From 374eb3d06d43615f1cff179f7e5d0d3505cd8387 Mon Sep 17 00:00:00 2001 From: aAbed <39409020+TheAabedKhan@users.noreply.github.com> Date: Fri, 4 Aug 2023 03:25:08 +0545 Subject: [PATCH] feat: abort patching process at any time (#1072) --- .../revanced/manager/flutter/MainActivity.kt | 77 ++++++++++++++++++- assets/i18n/en_US.json | 1 + lib/services/patcher_api.dart | 10 +++ .../views/installer/installer_viewmodel.dart | 30 +++++++- 4 files changed, 112 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt index 9654a781..2c8d7716 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt @@ -27,6 +27,8 @@ private const val INSTALLER_CHANNEL = "app.revanced.manager.flutter/installer" class MainActivity : FlutterActivity() { private val handler = Handler(Looper.getMainLooper()) private lateinit var installerChannel: MethodChannel + private var cancel: Boolean = false + private var stopResult: MethodChannel.Result? = null override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) @@ -57,6 +59,7 @@ class MainActivity : FlutterActivity() { keyStoreFilePath != null && keystorePassword != null ) { + cancel = false runPatcher( result, patchBundleFilePath, @@ -74,6 +77,10 @@ class MainActivity : FlutterActivity() { result.notImplemented() } } + "stopPatcher" -> { + cancel = true + stopResult = result + } else -> result.notImplemented() } } @@ -111,6 +118,12 @@ class MainActivity : FlutterActivity() { ) ) } + + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + originalFile.copyTo(inputFile, true) handler.post { @@ -123,6 +136,12 @@ class MainActivity : FlutterActivity() { ) ) } + + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + val patcher = Patcher( PatcherOptions( @@ -134,6 +153,11 @@ class MainActivity : FlutterActivity() { ) ) + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + handler.post { installerChannel.invokeMethod( "update", @@ -150,8 +174,19 @@ class MainActivity : FlutterActivity() { ) ) } + + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + patcher.addIntegrations(listOf(integrations)) {} + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + handler.post { installerChannel.invokeMethod( "update", @@ -163,6 +198,11 @@ class MainActivity : FlutterActivity() { ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + val patches = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) { PatchBundle.Dex( patchBundleFilePath, @@ -179,6 +219,12 @@ class MainActivity : FlutterActivity() { } else { TODO("VERSION.SDK_INT < CUPCAKE") } + + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + patcher.addPatches(patches) patcher.executePatches().forEach { (patch, res) -> if (res.isSuccess) { @@ -193,15 +239,24 @@ class MainActivity : FlutterActivity() { ) ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } return@forEach } - val msg = "Failed to apply $patch: " + "${res.exceptionOrNull()!!.message ?: res.exceptionOrNull()!!.cause!!::class.simpleName}" + val msg = + "Failed to apply $patch: " + "${res.exceptionOrNull()!!.message ?: res.exceptionOrNull()!!.cause!!::class.simpleName}" handler.post { installerChannel.invokeMethod( "update", mapOf("progress" to 0.5, "header" to "", "log" to msg) ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } } handler.post { @@ -214,9 +269,17 @@ class MainActivity : FlutterActivity() { ) ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } val res = patcher.save() ZipFile(patchedFile).use { file -> res.dexFiles.forEach { + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } file.addEntryCompressData( ZipEntry.createWithName(it.name), it.stream.readBytes() @@ -233,6 +296,10 @@ class MainActivity : FlutterActivity() { ZipAligner::getEntryAlignment ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } handler.post { installerChannel.invokeMethod( "update", @@ -244,10 +311,12 @@ class MainActivity : FlutterActivity() { ) } - // Signer("ReVanced", "s3cur3p@ssw0rd").signApk(patchedFile, outFile, keyStoreFile) - try { - Signer("ReVanced", keystorePassword).signApk(patchedFile, outFile, keyStoreFile) + Signer("ReVanced", keystorePassword).signApk( + patchedFile, + outFile, + keyStoreFile + ) } catch (e: Exception) { //log to console print("Error signing apk: ${e.message}") diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json index 5d067670..532cf3d4 100644 --- a/assets/i18n/en_US.json +++ b/assets/i18n/en_US.json @@ -135,6 +135,7 @@ "widgetTitle": "Installer", "installButton": "Install", "installRootButton": "Install as Root", + "pressBackAgain": "Press back again to cancel", "openButton": "Open", "shareButton": "Share file", diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index 77fb76f5..568e6183 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -202,6 +202,16 @@ class PatcherAPI { } } + Future stopPatcher() async { + try { + await patcherChannel.invokeMethod('stopPatcher'); + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + } + } + Future installPatchedFile(PatchedApplication patchedApp) async { if (_outFile != null) { try { diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index a1e95e30..c33d85a2 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -36,6 +36,8 @@ class InstallerViewModel extends BaseViewModel { bool isPatching = true; bool isInstalled = false; bool hasErrors = false; + bool isCanceled = false; + bool cancel = false; Future initialize(BuildContext context) async { isRooted = await _rootAPI.isRooted(); @@ -162,6 +164,19 @@ class InstallerViewModel extends BaseViewModel { } } + Future stopPatcher() async { + try { + isCanceled = true; + update(0.5, 'Aborting...', 'Canceling patching process'); + await _patcherAPI.stopPatcher(); + update(-100.0, 'Aborted...', 'Press back to exit'); + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + } + } + Future installResult(BuildContext context, bool installAsRoot) async { try { _app.isRooted = installAsRoot; @@ -280,10 +295,21 @@ class InstallerViewModel extends BaseViewModel { Future onWillPop(BuildContext context) async { if (isPatching) { - _toast.showBottom('installerView.noExit'); + if (!cancel) { + cancel = true; + _toast.showBottom('installerView.pressBackAgain'); + } else if (!isCanceled) { + await stopPatcher(); + } else { + _toast.showBottom('installerView.noExit'); + } return false; } - cleanPatcher(); + if (!cancel) { + cleanPatcher(); + } else { + _patcherAPI.cleanPatcher(); + } Navigator.of(context).pop(); return true; }