diff --git a/android/app/build.gradle b/android/app/build.gradle index b7082387..40448eb7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -85,9 +85,10 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // ReVanced - implementation "app.revanced:revanced-patcher:14.2.0" + implementation "app.revanced:revanced-patcher:11.0.4" // 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 b94a582c..49f45a21 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,30 +1,25 @@ 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.patch.PatchResult +import app.revanced.patcher.logging.Logger +import app.revanced.patcher.util.patch.PatchBundle +import dalvik.system.DexClassLoader 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" @@ -35,11 +30,10 @@ class MainActivity : FlutterActivity() { private var cancel: Boolean = false private var stopResult: MethodChannel.Result? = null - override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + override fun configureFlutterEngine(@NonNull 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" -> { @@ -113,34 +107,9 @@ 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", @@ -152,18 +121,13 @@ 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", @@ -175,13 +139,19 @@ class MainActivity : FlutterActivity() { ) } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + val patcher = Patcher( PatcherOptions( inputFile, - cacheDir, + cacheDirPath, Aapt.binary(applicationContext).absolutePath, - cacheDir.path, + cacheDirPath, + logger = ManagerLogger() ) ) @@ -193,19 +163,28 @@ class MainActivity : FlutterActivity() { handler.post { installerChannel.invokeMethod( "update", - mapOf("progress" to 0.3, "header" to "Loading patches...", "log" to "Loading patches") + 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" + ) ) } - 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 } - } + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } - if (cancel) { + patcher.addIntegrations(listOf(integrations)) {} + + if(cancel) { handler.post { stopResult!!.success(null) } return@Thread } @@ -215,60 +194,73 @@ class MainActivity : FlutterActivity() { "update", mapOf( "progress" to 0.5, - "header" to "Executing patches...", + "header" to "Applying patches...", "log" to "" ) ) } - 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) { + 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", @@ -279,8 +271,11 @@ class MainActivity : FlutterActivity() { ) ) } - val res = patcher.get() - patcher.close() + if(cancel) { + handler.post { stopResult!!.success(null) } + return@Thread + } + val res = patcher.save() ZipFile(patchedFile).use { file -> res.dexFiles.forEach { if (cancel) { @@ -341,54 +336,52 @@ class MainActivity : FlutterActivity() { ) } } 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" - ) + 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 bfe266a7..88ac491c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.9.0' + ext.kotlin_version = '1.7.10' repositories { google() mavenCentral()