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