mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
perf: Do not load patches twice (#1328)
This commit is contained in:
commit
a709abd80c
@ -85,7 +85,7 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
// ReVanced
|
// ReVanced
|
||||||
implementation "app.revanced:revanced-patcher:15.0.3"
|
implementation "app.revanced:revanced-patcher:16.0.0"
|
||||||
|
|
||||||
// Signing & aligning
|
// Signing & aligning
|
||||||
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
|
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
|
||||||
|
@ -8,6 +8,7 @@ import app.revanced.manager.flutter.utils.signing.Signer
|
|||||||
import app.revanced.manager.flutter.utils.zip.ZipFile
|
import app.revanced.manager.flutter.utils.zip.ZipFile
|
||||||
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
|
import app.revanced.manager.flutter.utils.zip.structures.ZipEntry
|
||||||
import app.revanced.patcher.PatchBundleLoader
|
import app.revanced.patcher.PatchBundleLoader
|
||||||
|
import app.revanced.patcher.PatchSet
|
||||||
import app.revanced.patcher.Patcher
|
import app.revanced.patcher.Patcher
|
||||||
import app.revanced.patcher.PatcherOptions
|
import app.revanced.patcher.PatcherOptions
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
@ -31,6 +32,8 @@ class MainActivity : FlutterActivity() {
|
|||||||
private var cancel: Boolean = false
|
private var cancel: Boolean = false
|
||||||
private var stopResult: MethodChannel.Result? = null
|
private var stopResult: MethodChannel.Result? = null
|
||||||
|
|
||||||
|
private lateinit var patches: PatchSet
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
|
||||||
@ -46,7 +49,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
mainChannel.setMethodCallHandler { call, result ->
|
mainChannel.setMethodCallHandler { call, result ->
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"runPatcher" -> {
|
"runPatcher" -> {
|
||||||
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")
|
|
||||||
val originalFilePath = call.argument<String>("originalFilePath")
|
val originalFilePath = call.argument<String>("originalFilePath")
|
||||||
val inputFilePath = call.argument<String>("inputFilePath")
|
val inputFilePath = call.argument<String>("inputFilePath")
|
||||||
val patchedFilePath = call.argument<String>("patchedFilePath")
|
val patchedFilePath = call.argument<String>("patchedFilePath")
|
||||||
@ -57,7 +59,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
|
val keyStoreFilePath = call.argument<String>("keyStoreFilePath")
|
||||||
val keystorePassword = call.argument<String>("keystorePassword")
|
val keystorePassword = call.argument<String>("keystorePassword")
|
||||||
|
|
||||||
if (patchBundleFilePath != null &&
|
if (
|
||||||
originalFilePath != null &&
|
originalFilePath != null &&
|
||||||
inputFilePath != null &&
|
inputFilePath != null &&
|
||||||
patchedFilePath != null &&
|
patchedFilePath != null &&
|
||||||
@ -71,7 +73,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
cancel = false
|
cancel = false
|
||||||
runPatcher(
|
runPatcher(
|
||||||
result,
|
result,
|
||||||
patchBundleFilePath,
|
|
||||||
originalFilePath,
|
originalFilePath,
|
||||||
inputFilePath,
|
inputFilePath,
|
||||||
patchedFilePath,
|
patchedFilePath,
|
||||||
@ -94,17 +95,19 @@ class MainActivity : FlutterActivity() {
|
|||||||
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")!!
|
val patchBundleFilePath = call.argument<String>("patchBundleFilePath")!!
|
||||||
val cacheDirPath = call.argument<String>("cacheDirPath")!!
|
val cacheDirPath = call.argument<String>("cacheDirPath")!!
|
||||||
|
|
||||||
|
try {
|
||||||
|
patches = PatchBundleLoader.Dex(
|
||||||
|
File(patchBundleFilePath),
|
||||||
|
optimizedDexDirectory = File(cacheDirPath)
|
||||||
|
)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
return@setMethodCallHandler result.notImplemented()
|
||||||
|
} catch (err: Error) {
|
||||||
|
return@setMethodCallHandler result.notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
JSONArray().apply {
|
JSONArray().apply {
|
||||||
try {
|
patches.forEach {
|
||||||
PatchBundleLoader.Dex(
|
|
||||||
File(patchBundleFilePath),
|
|
||||||
optimizedDexDirectory = File(cacheDirPath)
|
|
||||||
)
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
return@setMethodCallHandler result.notImplemented()
|
|
||||||
} catch (err: Error) {
|
|
||||||
return@setMethodCallHandler result.notImplemented()
|
|
||||||
}.forEach {
|
|
||||||
JSONObject().apply {
|
JSONObject().apply {
|
||||||
put("name", it.name)
|
put("name", it.name)
|
||||||
put("description", it.description)
|
put("description", it.description)
|
||||||
@ -136,7 +139,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
|
|
||||||
private fun runPatcher(
|
private fun runPatcher(
|
||||||
result: MethodChannel.Result,
|
result: MethodChannel.Result,
|
||||||
patchBundleFilePath: String,
|
|
||||||
originalFilePath: String,
|
originalFilePath: String,
|
||||||
inputFilePath: String,
|
inputFilePath: String,
|
||||||
patchedFilePath: String,
|
patchedFilePath: String,
|
||||||
@ -223,10 +225,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
|
|
||||||
updateProgress(0.1, "Loading patches...", "Loading patches")
|
updateProgress(0.1, "Loading patches...", "Loading patches")
|
||||||
|
|
||||||
val patches = PatchBundleLoader.Dex(
|
val patches = patches.filter { patch ->
|
||||||
File(patchBundleFilePath),
|
|
||||||
optimizedDexDirectory = cacheDir
|
|
||||||
).filter { patch ->
|
|
||||||
val isCompatible = patch.compatiblePackages?.any {
|
val isCompatible = patch.compatiblePackages?.any {
|
||||||
it.name == patcher.context.packageMetadata.packageName
|
it.name == patcher.context.packageMetadata.packageName
|
||||||
} ?: false
|
} ?: false
|
||||||
@ -331,7 +330,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
val stack = ex.stackTraceToString()
|
val stack = ex.stackTraceToString()
|
||||||
updateProgress(
|
updateProgress(
|
||||||
-100.0,
|
-100.0,
|
||||||
"Aborted",
|
"Failed",
|
||||||
"An error occurred:\n$stack"
|
"An error occurred:\n$stack"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class PatcherAPI {
|
|||||||
File? outFile;
|
File? outFile;
|
||||||
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
await _loadPatches();
|
await loadPatches();
|
||||||
await _managerAPI.downloadIntegrations();
|
await _managerAPI.downloadIntegrations();
|
||||||
final Directory appCache = await getTemporaryDirectory();
|
final Directory appCache = await getTemporaryDirectory();
|
||||||
_dataDir = await getExternalStorageDirectory() ?? appCache;
|
_dataDir = await getExternalStorageDirectory() ?? appCache;
|
||||||
@ -59,12 +59,10 @@ class PatcherAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Patch> getUniversalPatches() {
|
List<Patch> getUniversalPatches() {
|
||||||
return _patches
|
return _patches.where((patch) => patch.compatiblePackages.isEmpty).toList();
|
||||||
.where((patch) => patch.compatiblePackages.isEmpty)
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadPatches() async {
|
Future<void> loadPatches() async {
|
||||||
try {
|
try {
|
||||||
if (_patches.isEmpty) {
|
if (_patches.isEmpty) {
|
||||||
_patches = await _managerAPI.getPatches();
|
_patches = await _managerAPI.getPatches();
|
||||||
@ -85,15 +83,14 @@ class PatcherAPI {
|
|||||||
) async {
|
) async {
|
||||||
final List<ApplicationWithIcon> filteredApps = [];
|
final List<ApplicationWithIcon> filteredApps = [];
|
||||||
final bool allAppsIncluded =
|
final bool allAppsIncluded =
|
||||||
_universalPatches.isNotEmpty &&
|
_universalPatches.isNotEmpty && showUniversalPatches;
|
||||||
showUniversalPatches;
|
|
||||||
if (allAppsIncluded) {
|
if (allAppsIncluded) {
|
||||||
final appList = await DeviceApps.getInstalledApplications(
|
final appList = await DeviceApps.getInstalledApplications(
|
||||||
includeAppIcons: true,
|
includeAppIcons: true,
|
||||||
onlyAppsWithLaunchIntent: true,
|
onlyAppsWithLaunchIntent: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
for(final app in appList) {
|
for (final app in appList) {
|
||||||
filteredApps.add(app as ApplicationWithIcon);
|
filteredApps.add(app as ApplicationWithIcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,9 +151,9 @@ class PatcherAPI {
|
|||||||
String apkFilePath,
|
String apkFilePath,
|
||||||
List<Patch> selectedPatches,
|
List<Patch> selectedPatches,
|
||||||
) async {
|
) async {
|
||||||
final File? patchBundleFile = await _managerAPI.downloadPatches();
|
|
||||||
final File? integrationsFile = await _managerAPI.downloadIntegrations();
|
final File? integrationsFile = await _managerAPI.downloadIntegrations();
|
||||||
if (patchBundleFile != null) {
|
|
||||||
|
if (integrationsFile != null) {
|
||||||
_dataDir.createSync();
|
_dataDir.createSync();
|
||||||
_tmpDir.createSync();
|
_tmpDir.createSync();
|
||||||
final Directory workDir = _tmpDir.createTempSync('tmp-');
|
final Directory workDir = _tmpDir.createTempSync('tmp-');
|
||||||
@ -170,12 +167,11 @@ class PatcherAPI {
|
|||||||
await patcherChannel.invokeMethod(
|
await patcherChannel.invokeMethod(
|
||||||
'runPatcher',
|
'runPatcher',
|
||||||
{
|
{
|
||||||
'patchBundleFilePath': patchBundleFile.path,
|
|
||||||
'originalFilePath': originalFilePath,
|
'originalFilePath': originalFilePath,
|
||||||
'inputFilePath': inputFile.path,
|
'inputFilePath': inputFile.path,
|
||||||
'patchedFilePath': patchedFile.path,
|
'patchedFilePath': patchedFile.path,
|
||||||
'outFilePath': outFile!.path,
|
'outFilePath': outFile!.path,
|
||||||
'integrationsPath': integrationsFile!.path,
|
'integrationsPath': integrationsFile.path,
|
||||||
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
'selectedPatches': selectedPatches.map((p) => p.name).toList(),
|
||||||
'cacheDirPath': cacheDir.path,
|
'cacheDirPath': cacheDir.path,
|
||||||
'keyStoreFilePath': _keyStoreFile.path,
|
'keyStoreFilePath': _keyStoreFile.path,
|
||||||
|
@ -130,28 +130,28 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
|
|
||||||
Future<void> runPatcher() async {
|
Future<void> runPatcher() async {
|
||||||
try {
|
try {
|
||||||
update(0.0, 'Initializing...', 'Initializing installer');
|
await _patcherAPI.runPatcher(
|
||||||
if (_patches.isNotEmpty) {
|
_app.packageName,
|
||||||
try {
|
_app.apkFilePath,
|
||||||
update(0.1, '', 'Creating working directory');
|
_patches,
|
||||||
await _patcherAPI.runPatcher(
|
);
|
||||||
_app.packageName,
|
} on Exception catch (e) {
|
||||||
_app.apkFilePath,
|
update(
|
||||||
_patches,
|
-100.0,
|
||||||
);
|
'Failed...',
|
||||||
} on Exception catch (e) {
|
'Something went wrong:\n$e',
|
||||||
update(
|
);
|
||||||
-100.0,
|
if (kDebugMode) {
|
||||||
'Aborted...',
|
print(e);
|
||||||
'An error occurred! Aborted\nError:\n$e',
|
|
||||||
);
|
|
||||||
if (kDebugMode) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
update(-100.0, 'Aborted...', 'No app or patches selected! Aborted');
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Necessary to reset the state of patches by reloading them
|
||||||
|
// in a later patching process.
|
||||||
|
_managerAPI.patches.clear();
|
||||||
|
await _patcherAPI.loadPatches();
|
||||||
|
|
||||||
|
try {
|
||||||
if (FlutterBackground.isBackgroundExecutionEnabled) {
|
if (FlutterBackground.isBackgroundExecutionEnabled) {
|
||||||
try {
|
try {
|
||||||
FlutterBackground.disableBackgroundExecution();
|
FlutterBackground.disableBackgroundExecution();
|
||||||
@ -209,7 +209,8 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
),
|
),
|
||||||
RadioListTile(
|
RadioListTile(
|
||||||
title: I18nText('installerView.installNonRootType'),
|
title: I18nText('installerView.installNonRootType'),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16),
|
||||||
value: 0,
|
value: 0,
|
||||||
groupValue: value,
|
groupValue: value,
|
||||||
onChanged: (selected) {
|
onChanged: (selected) {
|
||||||
@ -218,7 +219,8 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
),
|
),
|
||||||
RadioListTile(
|
RadioListTile(
|
||||||
title: I18nText('installerView.installRootType'),
|
title: I18nText('installerView.installRootType'),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 16),
|
||||||
value: 1,
|
value: 1,
|
||||||
groupValue: value,
|
groupValue: value,
|
||||||
onChanged: (selected) {
|
onChanged: (selected) {
|
||||||
@ -256,9 +258,9 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
Future<void> stopPatcher() async {
|
Future<void> stopPatcher() async {
|
||||||
try {
|
try {
|
||||||
isCanceled = true;
|
isCanceled = true;
|
||||||
update(0.5, 'Aborting...', 'Canceling patching process');
|
update(0.5, 'Canceling...', 'Canceling patching process');
|
||||||
await _patcherAPI.stopPatcher();
|
await _patcherAPI.stopPatcher();
|
||||||
update(-100.0, 'Aborted...', 'Press back to exit');
|
update(-100.0, 'Canceled...', 'Press back to exit');
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
@ -269,33 +271,34 @@ class InstallerViewModel extends BaseViewModel {
|
|||||||
Future<void> installResult(BuildContext context, bool installAsRoot) async {
|
Future<void> installResult(BuildContext context, bool installAsRoot) async {
|
||||||
try {
|
try {
|
||||||
_app.isRooted = installAsRoot;
|
_app.isRooted = installAsRoot;
|
||||||
update(
|
update(
|
||||||
1.0,
|
1.0,
|
||||||
'Installing...',
|
'Installing...',
|
||||||
_app.isRooted
|
_app.isRooted
|
||||||
? 'Installing patched file using root method'
|
? 'Installing patched file using root method'
|
||||||
: 'Installing patched file using nonroot method',
|
: 'Installing patched file using nonroot method',
|
||||||
);
|
);
|
||||||
isInstalled = await _patcherAPI.installPatchedFile(_app);
|
isInstalled = await _patcherAPI.installPatchedFile(_app);
|
||||||
if (isInstalled) {
|
if (isInstalled) {
|
||||||
_app.isFromStorage = false;
|
_app.isFromStorage = false;
|
||||||
_app.patchDate = DateTime.now();
|
_app.patchDate = DateTime.now();
|
||||||
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
_app.appliedPatches = _patches.map((p) => p.name).toList();
|
||||||
|
|
||||||
// In case a patch changed the app name or package name,
|
// In case a patch changed the app name or package name,
|
||||||
// update the app info.
|
// update the app info.
|
||||||
final app = await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path);
|
final app =
|
||||||
if (app != null) {
|
await DeviceApps.getAppFromStorage(_patcherAPI.outFile!.path);
|
||||||
_app.name = app.appName;
|
if (app != null) {
|
||||||
_app.packageName = app.packageName;
|
_app.name = app.appName;
|
||||||
}
|
_app.packageName = app.packageName;
|
||||||
|
|
||||||
await _managerAPI.savePatchedApp(_app);
|
|
||||||
|
|
||||||
update(1.0, 'Installed!', 'Installed!');
|
|
||||||
} else {
|
|
||||||
// TODO(aabed): Show error message.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _managerAPI.savePatchedApp(_app);
|
||||||
|
|
||||||
|
update(1.0, 'Installed!', 'Installed!');
|
||||||
|
} else {
|
||||||
|
// TODO(aabed): Show error message.
|
||||||
|
}
|
||||||
} on Exception catch (e) {
|
} on Exception catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print(e);
|
print(e);
|
||||||
|
Loading…
Reference in New Issue
Block a user