From 45fae3f0fd29e379b83f69584943a3b8748e0873 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 27 Aug 2023 22:32:07 +0200 Subject: [PATCH 1/4] build: bump ReVanced Patcher back to v14.2.1 This reverts the previous regression with the dependency to ReVanced Patcher. --- android/app/build.gradle | 3 +- .../revanced/manager/flutter/MainActivity.kt | 283 +++++++++--------- android/build.gradle | 2 +- 3 files changed, 147 insertions(+), 141 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 40448eb7..13b99831 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -85,10 +85,9 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // ReVanced - implementation "app.revanced:revanced-patcher:11.0.4" + implementation "app.revanced:revanced-patcher:14.2.1" // Signing & aligning implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("com.android.tools.build:apksig:7.2.2") - } 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 49f45a21..b94a582c 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 @@ -1,25 +1,30 @@ package app.revanced.manager.flutter -import android.os.Build import android.os.Handler import android.os.Looper -import androidx.annotation.NonNull import app.revanced.manager.flutter.utils.Aapt import app.revanced.manager.flutter.utils.aligning.ZipAligner 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.Patcher import app.revanced.patcher.PatcherOptions import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.patchName -import app.revanced.patcher.logging.Logger -import app.revanced.patcher.util.patch.PatchBundle -import dalvik.system.DexClassLoader +import app.revanced.patcher.patch.PatchResult import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel +import kotlinx.coroutines.cancel +import kotlinx.coroutines.runBlocking import java.io.File +import java.io.PrintWriter +import java.io.StringWriter +import java.util.logging.Level +import java.util.logging.LogRecord +import java.util.logging.Logger +import java.util.logging.SimpleFormatter private const val PATCHER_CHANNEL = "app.revanced.manager.flutter/patcher" private const val INSTALLER_CHANNEL = "app.revanced.manager.flutter/installer" @@ -30,10 +35,11 @@ class MainActivity : FlutterActivity() { private var cancel: Boolean = false private var stopResult: MethodChannel.Result? = null - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) val mainChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PATCHER_CHANNEL) - installerChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL) + installerChannel = + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL) mainChannel.setMethodCallHandler { call, result -> when (call.method) { "runPatcher" -> { @@ -107,9 +113,34 @@ class MainActivity : FlutterActivity() { val outFile = File(outFilePath) val integrations = File(integrationsPath) val keyStoreFile = File(keyStoreFilePath) + val cacheDir = File(cacheDirPath) Thread { try { + Logger.getLogger("").apply { + handlers.forEach { + it.close() + removeHandler(it) + } + object : java.util.logging.Handler() { + override fun publish(record: LogRecord) = formatter.format(record).toByteArray().let { + if (record.level.intValue() > Level.INFO.intValue()) + System.err.write(it) + else + System.out.write(it) + } + + override fun flush() { + System.out.flush() + System.err.flush() + } + + override fun close() = flush() + }.also { + it.level = Level.ALL + it.formatter = SimpleFormatter() + }.let(::addHandler) + } handler.post { installerChannel.invokeMethod( "update", @@ -121,13 +152,18 @@ class MainActivity : FlutterActivity() { ) } - if(cancel) { + if (cancel) { handler.post { stopResult!!.success(null) } return@Thread } originalFile.copyTo(inputFile, true) + if (cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + handler.post { installerChannel.invokeMethod( "update", @@ -139,19 +175,13 @@ class MainActivity : FlutterActivity() { ) } - if(cancel) { - handler.post { stopResult!!.success(null) } - return@Thread - } - val patcher = Patcher( PatcherOptions( inputFile, - cacheDirPath, + cacheDir, Aapt.binary(applicationContext).absolutePath, - cacheDirPath, - logger = ManagerLogger() + cacheDir.path, ) ) @@ -163,28 +193,19 @@ class MainActivity : FlutterActivity() { handler.post { installerChannel.invokeMethod( "update", - mapOf("progress" to 0.3, "header" to "", "log" to "") - ) - } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.4, - "header" to "Merging integrations...", - "log" to "Merging integrations" - ) + mapOf("progress" to 0.3, "header" to "Loading patches...", "log" to "Loading patches") ) } - if(cancel) { - handler.post { stopResult!!.success(null) } - return@Thread - } + val patches = + PatchBundleLoader.Dex( + File(patchBundleFilePath) + ).filter { patch -> + (patch.compatiblePackages?.any { it.name == patcher.context.packageMetadata.packageName } == true || patch.compatiblePackages.isNullOrEmpty()) && + selectedPatches.any { it == patch.patchName } + } - patcher.addIntegrations(listOf(integrations)) {} - - if(cancel) { + if (cancel) { handler.post { stopResult!!.success(null) } return@Thread } @@ -194,73 +215,60 @@ class MainActivity : FlutterActivity() { "update", mapOf( "progress" to 0.5, - "header" to "Applying patches...", + "header" to "Executing patches...", "log" to "" ) ) } - if(cancel) { + patcher.apply { + acceptIntegrations(listOf(integrations)) + acceptPatches(patches) + + runBlocking { + apply(false).collect { patchResult: PatchResult -> + patchResult.exception?.let { + if (cancel) { + handler.post { stopResult!!.success(null) } + this.cancel() + return@collect + } + StringWriter().use { writer -> + it.printStackTrace(PrintWriter(writer)) + handler.post { + installerChannel.invokeMethod( + "update", + mapOf("progress" to 0.5, "header" to "", "log" to "${patchResult.patchName} failed: $writer") + ) + } + } + } ?: run { + if (cancel) { + handler.post { stopResult!!.success(null) } + this.cancel() + return@collect + } + val msg = "${patchResult.patchName} succeeded" + handler.post { + installerChannel.invokeMethod( + "update", + mapOf( + "progress" to 0.5, + "header" to "", + "log" to msg + ) + ) + } + } + } + } + } + + if (cancel) { handler.post { stopResult!!.success(null) } return@Thread } - val patches = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) { - PatchBundle.Dex( - patchBundleFilePath, - DexClassLoader( - patchBundleFilePath, - cacheDirPath, - null, - javaClass.classLoader - ) - ).loadPatches().filter { patch -> - (patch.compatiblePackages?.any { it.name == patcher.context.packageMetadata.packageName } == true || patch.compatiblePackages.isNullOrEmpty()) && - selectedPatches.any { it == patch.patchName } - } - } 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) { - val msg = "Applied $patch" - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.5, - "header" to "", - "log" to msg - ) - ) - } - 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}" - 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 { installerChannel.invokeMethod( "update", @@ -271,11 +279,8 @@ class MainActivity : FlutterActivity() { ) ) } - if(cancel) { - handler.post { stopResult!!.success(null) } - return@Thread - } - val res = patcher.save() + val res = patcher.get() + patcher.close() ZipFile(patchedFile).use { file -> res.dexFiles.forEach { if (cancel) { @@ -336,52 +341,54 @@ class MainActivity : FlutterActivity() { ) } } catch (ex: Throwable) { - val stack = ex.stackTraceToString() - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to -100.0, - "header" to "Aborted...", - "log" to "An error occurred! Aborted\nError:\n$stack" + if (!cancel) { + val stack = ex.stackTraceToString() + handler.post { + installerChannel.invokeMethod( + "update", + mapOf( + "progress" to -100.0, + "header" to "Aborted...", + "log" to "An error occurred! Aborted\nError:\n$stack" + ) ) - ) + } } } handler.post { result.success(null) } }.start() } - inner class ManagerLogger : Logger { - override fun error(msg: String) { - handler.post { - installerChannel - .invokeMethod( - "update", - mapOf("progress" to -1.0, "header" to "", "log" to msg) - ) - } - } - - override fun warn(msg: String) { - handler.post { - installerChannel.invokeMethod( - "update", - mapOf("progress" to -1.0, "header" to "", "log" to msg) - ) - } - } - - override fun info(msg: String) { - handler.post { - installerChannel.invokeMethod( - "update", - mapOf("progress" to -1.0, "header" to "", "log" to msg) - ) - } - } - - override fun trace(_msg: String) { /* unused */ - } - } +// inner class ManagerLogger : Logger { +// override fun error(msg: String) { +// handler.post { +// installerChannel +// .invokeMethod( +// "update", +// mapOf("progress" to -1.0, "header" to "", "log" to msg) +// ) +// } +// } +// +// override fun warn(msg: String) { +// handler.post { +// installerChannel.invokeMethod( +// "update", +// mapOf("progress" to -1.0, "header" to "", "log" to msg) +// ) +// } +// } +// +// override fun info(msg: String) { +// handler.post { +// installerChannel.invokeMethod( +// "update", +// mapOf("progress" to -1.0, "header" to "", "log" to msg) +// ) +// } +// } +// +// override fun trace(_msg: String) { /* unused */ +// } +// } } diff --git a/android/build.gradle b/android/build.gradle index 88ac491c..bfe266a7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '1.9.0' repositories { google() mavenCentral() From 64a96fc3cea3a59d89d757c06a4a13d6d88cf995 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 28 Aug 2023 00:41:16 +0200 Subject: [PATCH 2/4] fix: close before returning --- .../main/kotlin/app/revanced/manager/flutter/MainActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) 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 b94a582c..e00044da 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 @@ -266,6 +266,7 @@ class MainActivity : FlutterActivity() { if (cancel) { handler.post { stopResult!!.success(null) } + patcher.close() return@Thread } @@ -279,8 +280,10 @@ class MainActivity : FlutterActivity() { ) ) } + val res = patcher.get() patcher.close() + ZipFile(patchedFile).use { file -> res.dexFiles.forEach { if (cancel) { @@ -303,10 +306,12 @@ class MainActivity : FlutterActivity() { ZipAligner::getEntryAlignment ) } + if (cancel) { handler.post { stopResult!!.success(null) } return@Thread } + handler.post { installerChannel.invokeMethod( "update", From 7911a8f49e9606658bc83fbcca1df89fa0cd6343 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 28 Aug 2023 01:43:44 +0200 Subject: [PATCH 3/4] fix: properly log messages and progress --- .../revanced/manager/flutter/MainActivity.kt | 295 ++++++------------ 1 file changed, 98 insertions(+), 197 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 e00044da..2c11653d 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 @@ -21,13 +21,9 @@ import kotlinx.coroutines.runBlocking import java.io.File import java.io.PrintWriter import java.io.StringWriter -import java.util.logging.Level import java.util.logging.LogRecord import java.util.logging.Logger -import java.util.logging.SimpleFormatter -private const val PATCHER_CHANNEL = "app.revanced.manager.flutter/patcher" -private const val INSTALLER_CHANNEL = "app.revanced.manager.flutter/installer" class MainActivity : FlutterActivity() { private val handler = Handler(Looper.getMainLooper()) @@ -37,9 +33,16 @@ class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) - val mainChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PATCHER_CHANNEL) - installerChannel = - MethodChannel(flutterEngine.dartExecutor.binaryMessenger, INSTALLER_CHANNEL) + + val patcherChannel = "app.revanced.manager.flutter/patcher" + val installerChannel = "app.revanced.manager.flutter/installer" + + val mainChannel = + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, patcherChannel) + + this.installerChannel = + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, installerChannel) + mainChannel.setMethodCallHandler { call, result -> when (call.method) { "runPatcher" -> { @@ -79,9 +82,7 @@ class MainActivity : FlutterActivity() { keyStoreFilePath, keystorePassword ) - } else { - result.notImplemented() - } + } else result.notImplemented() } "stopPatcher" -> { @@ -116,110 +117,94 @@ class MainActivity : FlutterActivity() { val cacheDir = File(cacheDirPath) Thread { - try { - Logger.getLogger("").apply { - handlers.forEach { - it.close() - removeHandler(it) - } - object : java.util.logging.Handler() { - override fun publish(record: LogRecord) = formatter.format(record).toByteArray().let { - if (record.level.intValue() > Level.INFO.intValue()) - System.err.write(it) - else - System.out.write(it) - } - - override fun flush() { - System.out.flush() - System.err.flush() - } - - override fun close() = flush() - }.also { - it.level = Level.ALL - it.formatter = SimpleFormatter() - }.let(::addHandler) - } + fun updateProgress(progress: Double, header: String, log: String) { handler.post { installerChannel.invokeMethod( "update", mapOf( - "progress" to 0.1, - "header" to "", - "log" to "Copying original APK" + "progress" to progress, + "header" to header, + "log" to log ) ) } + } + + fun postStop() = handler.post { stopResult!!.success(null) } + + // Setup logger + Logger.getLogger("").apply { + handlers.forEach { + it.close() + removeHandler(it) + } + + object : java.util.logging.Handler() { + override fun publish(record: LogRecord) = + updateProgress(-1.0, "", record.message) + + override fun flush() = Unit + override fun close() = flush() + }.let(::addHandler) + } + + try { + updateProgress(0.0, "", "Copying APK") if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } originalFile.copyTo(inputFile, true) if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.2, - "header" to "Reading APK...", - "log" to "Reading input APK" - ) - ) - } + updateProgress(0.05, "Reading APK...", "Reading APK") - val patcher = - Patcher( - PatcherOptions( - inputFile, - cacheDir, - Aapt.binary(applicationContext).absolutePath, - cacheDir.path, - ) + val patcher = Patcher( + PatcherOptions( + inputFile, + cacheDir, + Aapt.binary(applicationContext).absolutePath, + cacheDir.path, ) + ) if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf("progress" to 0.3, "header" to "Loading patches...", "log" to "Loading patches") - ) - } + updateProgress(0.1, "Loading patches...", "Loading patches") - val patches = - PatchBundleLoader.Dex( - File(patchBundleFilePath) - ).filter { patch -> - (patch.compatiblePackages?.any { it.name == patcher.context.packageMetadata.packageName } == true || patch.compatiblePackages.isNullOrEmpty()) && - selectedPatches.any { it == patch.patchName } - } + val patches = PatchBundleLoader.Dex( + File(patchBundleFilePath) + ).filter { patch -> + val isCompatible = patch.compatiblePackages?.any { + it.name == patcher.context.packageMetadata.packageName + } ?: false + + val compatibleOrUniversal = + isCompatible || patch.compatiblePackages.isNullOrEmpty() + + compatibleOrUniversal && selectedPatches.any { it == patch.patchName } + } if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.5, - "header" to "Executing patches...", - "log" to "" - ) - ) - } + updateProgress(0.15, "Executing...", "") + + // Update the progress bar every time a patch is executed from 0.15 to 0.7 + val totalPatchesCount = patches.size + val progressStep = 0.55 / totalPatchesCount + var progress = 0.15 patcher.apply { acceptIntegrations(listOf(integrations)) @@ -227,59 +212,34 @@ class MainActivity : FlutterActivity() { runBlocking { apply(false).collect { patchResult: PatchResult -> - patchResult.exception?.let { - if (cancel) { - handler.post { stopResult!!.success(null) } - this.cancel() - return@collect - } - StringWriter().use { writer -> - it.printStackTrace(PrintWriter(writer)) - handler.post { - installerChannel.invokeMethod( - "update", - mapOf("progress" to 0.5, "header" to "", "log" to "${patchResult.patchName} failed: $writer") - ) - } - } - } ?: run { - if (cancel) { - handler.post { stopResult!!.success(null) } - this.cancel() - return@collect - } - val msg = "${patchResult.patchName} succeeded" - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.5, - "header" to "", - "log" to msg - ) - ) - } + if (cancel) { + handler.post { stopResult!!.success(null) } + this.cancel() + this@apply.close() + return@collect } + + val msg = patchResult.exception?.let { + val writer = StringWriter() + it.printStackTrace(PrintWriter(writer)) + "${patchResult.patchName} failed: $writer" + } ?: run { + "${patchResult.patchName} succeeded" + } + + updateProgress(progress, "", msg) + progress += progressStep } } } if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() patcher.close() return@Thread } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.7, - "header" to "Repacking APK...", - "log" to "" - ) - ) - } + updateProgress(0.8, "Building...", "") val res = patcher.get() patcher.close() @@ -287,7 +247,7 @@ class MainActivity : FlutterActivity() { ZipFile(patchedFile).use { file -> res.dexFiles.forEach { if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } file.addEntryCompressData( @@ -308,92 +268,33 @@ class MainActivity : FlutterActivity() { } if (cancel) { - handler.post { stopResult!!.success(null) } + postStop() return@Thread } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 0.9, - "header" to "Signing APK...", - "log" to "" - ) - ) - } + updateProgress(0.9, "Signing...", "Signing APK") 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}") e.printStackTrace() } - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to 1.0, - "header" to "Finished!", - "log" to "Finished!" - ) - ) - } + updateProgress(1.0, "Patched", "Patched") } catch (ex: Throwable) { if (!cancel) { val stack = ex.stackTraceToString() - handler.post { - installerChannel.invokeMethod( - "update", - mapOf( - "progress" to -100.0, - "header" to "Aborted...", - "log" to "An error occurred! Aborted\nError:\n$stack" - ) - ) - } + updateProgress( + -100.0, + "Aborted", + "An error occurred:\n$stack" + ) } } + handler.post { result.success(null) } }.start() } - -// inner class ManagerLogger : Logger { -// override fun error(msg: String) { -// handler.post { -// installerChannel -// .invokeMethod( -// "update", -// mapOf("progress" to -1.0, "header" to "", "log" to msg) -// ) -// } -// } -// -// override fun warn(msg: String) { -// handler.post { -// installerChannel.invokeMethod( -// "update", -// mapOf("progress" to -1.0, "header" to "", "log" to msg) -// ) -// } -// } -// -// override fun info(msg: String) { -// handler.post { -// installerChannel.invokeMethod( -// "update", -// mapOf("progress" to -1.0, "header" to "", "log" to msg) -// ) -// } -// } -// -// override fun trace(_msg: String) { /* unused */ -// } -// } } From f4e1cccfac23baf58d45a4612a78e1f52e72ea11 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 27 Aug 2023 22:33:05 +0200 Subject: [PATCH 4/4] build: bump version to v1.9.4 --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9f398d18..0031a4d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/revanced/revanced-manager publish_to: 'none' -version: 1.9.3+100900300 +version: 1.9.4+100900200 environment: sdk: '>=3.0.0 <4.0.0'