From 4b2806c519c48a00af87ac22d1271b61323fee08 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Fri, 19 Aug 2022 19:13:43 +0100 Subject: [PATCH] feat: working resource patching --- android/app/build.gradle | 8 +- .../app/revanced/manager/MainActivity.kt | 46 ++++++----- lib/services/github_api.dart | 8 +- lib/services/manager_api.dart | 24 +++--- lib/services/patcher_api.dart | 80 ++++++++++++++----- lib/ui/views/home/home_viewmodel.dart | 2 +- .../views/installer/installer_viewmodel.dart | 2 +- pubspec.yaml | 1 + 8 files changed, 107 insertions(+), 64 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index bf2aac2b..8425b83b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -30,12 +30,12 @@ android { ndkVersion flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '11' } sourceSets { @@ -67,7 +67,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // ReVanced - implementation "app.revanced:revanced-patcher:3.3.1" + implementation "app.revanced:revanced-patcher:3.3.3" // Signing & aligning implementation("org.bouncycastle:bcpkix-jdk15on:1.70") diff --git a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt index 7859dafe..16e00a6c 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/MainActivity.kt @@ -16,7 +16,7 @@ import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.version import app.revanced.patcher.patch.Patch -import app.revanced.patcher.util.patch.implementation.DexPatchBundle +import app.revanced.patcher.util.patch.impl.DexPatchBundle import dalvik.system.DexClassLoader import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine @@ -41,9 +41,10 @@ class MainActivity : FlutterActivity() { mainChannel.setMethodCallHandler { call, result -> when (call.method) { "loadPatches" -> { - val pathBundlesPaths = call.argument>("pathBundlesPaths") - if (pathBundlesPaths != null) { - loadPatches(result, pathBundlesPaths) + val zipPatchBundlePath = call.argument("zipPatchBundlePath") + val cacheDirPath = call.argument("cacheDirPath") + if (zipPatchBundlePath != null && cacheDirPath != null) { + loadPatches(result, zipPatchBundlePath, cacheDirPath) } else { result.notImplemented() } @@ -100,23 +101,25 @@ class MainActivity : FlutterActivity() { } } - fun loadPatches(result: MethodChannel.Result, pathBundlesPaths: List) { + fun loadPatches( + result: MethodChannel.Result, + zipPatchBundlePath: String, + cacheDirPath: String + ) { Thread( Runnable { - pathBundlesPaths.forEach { path -> - patches.addAll( - DexPatchBundle( - path, - DexClassLoader( - path, - applicationContext.cacheDir.path, - null, - javaClass.classLoader - ) - ) - .loadPatches() - ) - } + patches.addAll( + DexPatchBundle( + zipPatchBundlePath, + DexClassLoader( + zipPatchBundlePath, + cacheDirPath, + null, + javaClass.classLoader + ) + ) + .loadPatches() + ) handler.post { result.success(null) } } ) @@ -185,7 +188,8 @@ class MainActivity : FlutterActivity() { val patchedFile = File(patchedFilePath) val outFile = File(outFilePath) val integrations = File(integrationsPath) - val filteredPatches = patches.filter { patch -> selectedPatches.any { it == patch.patchName } } + val filteredPatches = + patches.filter { patch -> selectedPatches.any { it == patch.patchName } } Thread( Runnable { @@ -289,7 +293,7 @@ class MainActivity : FlutterActivity() { res.dexFiles.forEach { file.addEntryCompressData( ZipEntry.createWithName(it.name), - it.dexFileInputStream.readBytes() + it.stream.readBytes() ) } res.resourceFile?.let { diff --git a/lib/services/github_api.dart b/lib/services/github_api.dart index f9275b30..84bef88e 100644 --- a/lib/services/github_api.dart +++ b/lib/services/github_api.dart @@ -17,7 +17,11 @@ class GithubAPI { } } - Future latestReleaseFile(String org, repoName) async { + Future latestReleaseFile( + String extension, + String org, + repoName, + ) async { try { var latestRelease = await _github.repositories.getLatestRelease( RepositorySlug(org, repoName), @@ -25,7 +29,7 @@ class GithubAPI { String? url = latestRelease.assets ?.firstWhere((asset) => asset.name != null && - (asset.name!.endsWith('.dex') || asset.name!.endsWith('.apk')) && + asset.name!.endsWith(extension) && !asset.name!.contains('-sources') && !asset.name!.contains('-javadoc')) .browserDownloadUrl; diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index a64cf8e3..7064b29f 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -6,30 +6,28 @@ import 'package:revanced_manager/services/github_api.dart'; class ManagerAPI { final GithubAPI _githubAPI = GithubAPI(); - Future downloadPatches() async { - return await _githubAPI.latestReleaseFile(ghOrg, patchesRepo); + Future downloadPatches(String extension) async { + return await _githubAPI.latestReleaseFile(extension, ghOrg, patchesRepo); } - Future downloadIntegrations() async { - return await _githubAPI.latestReleaseFile(ghOrg, integrationsRepo); - } - - Future downloadManager() async { + Future downloadIntegrations(String extension) async { return await _githubAPI.latestReleaseFile( - 'Aunali321', - 'revanced-manager-flutter', + extension, + ghOrg, + integrationsRepo, ); } + Future downloadManager(String extension) async { + return await _githubAPI.latestReleaseFile(extension, ghOrg, managerRepo); + } + Future getLatestPatchesVersion() async { return await _githubAPI.latestReleaseVersion(ghOrg, patchesRepo); } Future getLatestManagerVersion() async { - return await _githubAPI.latestReleaseVersion( - 'Aunali321', - 'revanced-manager-flutter', - ); + return await _githubAPI.latestReleaseVersion(ghOrg, managerRepo); } Future getCurrentManagerVersion() async { diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index 5fbedb6b..0786b353 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:app_installer/app_installer.dart'; import 'package:device_apps/device_apps.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_archive/flutter_archive.dart'; import 'package:injectable/injectable.dart'; import 'package:path_provider/path_provider.dart'; import 'package:revanced_manager/models/patch.dart'; @@ -21,29 +22,47 @@ class PatcherAPI { Directory? _tmpDir; Directory? _workDir; Directory? _cacheDir; - File? _patchBundleFile; + File? _zipPatchBundleFile; File? _integrations; File? _inputFile; File? _patchedFile; File? _outFile; + Future initPatcher() async { + _tmpDir = await getTemporaryDirectory(); + _workDir = _tmpDir!.createTempSync('tmp-'); + _inputFile = File('${_workDir!.path}/base.apk'); + _patchedFile = File('${_workDir!.path}/patched.apk'); + _outFile = File('${_workDir!.path}/out.apk'); + _cacheDir = Directory('${_workDir!.path}/cache'); + _cacheDir!.createSync(); + } + Future loadPatches() async { - if (_patchBundleFile == null) { - _patchBundleFile = await _managerAPI.downloadPatches(); - if (_patchBundleFile != null) { - await patcherChannel.invokeMethod( - 'loadPatches', - { - 'pathBundlesPaths': [_patchBundleFile!.absolute.path], - }, - ); + if (_cacheDir == null) { + await initPatcher(); + } + if (_zipPatchBundleFile == null) { + File? patchBundleDexFile = await _managerAPI.downloadPatches('.dex'); + File? patchBundleJarFile = await _managerAPI.downloadPatches('.jar'); + if (patchBundleDexFile != null && patchBundleJarFile != null) { + await joinPatchBundleFiles(patchBundleDexFile, patchBundleJarFile); + if (_zipPatchBundleFile != null) { + await patcherChannel.invokeMethod( + 'loadPatches', + { + 'zipPatchBundlePath': _zipPatchBundleFile!.path, + 'cacheDirPath': _cacheDir!.path, + }, + ); + } } } } Future> getFilteredInstalledApps() async { List filteredPackages = []; - if (_patchBundleFile != null) { + if (_zipPatchBundleFile != null) { try { List? patchesPackages = await patcherChannel .invokeListMethod('getCompatiblePackages'); @@ -71,7 +90,7 @@ class PatcherAPI { PatchedApplication? selectedApp, ) async { List filteredPatches = []; - if (_patchBundleFile != null && selectedApp != null) { + if (_zipPatchBundleFile != null && selectedApp != null) { try { var patches = await patcherChannel.invokeListMethod>( @@ -112,7 +131,7 @@ class PatcherAPI { PatchedApplication? selectedApp, ) async { List appliedPatches = []; - if (_patchBundleFile != null && selectedApp != null) { + if (_zipPatchBundleFile != null && selectedApp != null) { try { var patches = await patcherChannel.invokeListMethod>( @@ -148,17 +167,12 @@ class PatcherAPI { return appliedPatches; } - Future initPatcher(bool mergeIntegrations) async { + Future mergeIntegrations(bool mergeIntegrations) async { if (mergeIntegrations) { - _integrations = await _managerAPI.downloadIntegrations(); + _integrations = await _managerAPI.downloadIntegrations('.apk'); + } else { + _integrations = null; } - _tmpDir = await getTemporaryDirectory(); - _workDir = _tmpDir!.createTempSync('tmp-'); - _inputFile = File('${_workDir!.path}/base.apk'); - _patchedFile = File('${_workDir!.path}/patched.apk'); - _outFile = File('${_workDir!.path}/out.apk'); - _cacheDir = Directory('${_workDir!.path}/cache'); - _cacheDir!.createSync(); } Future runPatcher( @@ -234,4 +248,26 @@ class PatcherAPI { await _rootAPI.deleteApp(patchedApp.packageName, patchedApp.apkFilePath); } } + + Future joinPatchBundleFiles( + File patchBundleDexFile, + File patchBundleJarFile, + ) async { + _zipPatchBundleFile = File('${_workDir!.path}/join.zip'); + Directory joinDir = Directory('${_cacheDir!.path}/join'); + try { + await ZipFile.extractToDirectory( + zipFile: patchBundleJarFile, + destinationDir: joinDir, + ); + patchBundleDexFile.copySync('${joinDir.path}/classes.dex'); + await ZipFile.createFromDirectory( + sourceDir: joinDir, + zipFile: _zipPatchBundleFile!, + recurseSubDirs: true, + ); + } on Exception { + _zipPatchBundleFile = null; + } + } } diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index 4ba35f73..2fec5d2f 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -89,7 +89,7 @@ class HomeViewModel extends BaseViewModel { toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.CENTER, ); - File? managerApk = await _managerAPI.downloadManager(); + File? managerApk = await _managerAPI.downloadManager('.apk'); if (managerApk != null) { flutterLocalNotificationsPlugin.show( 0, diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 3058cc11..46ba4e39 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -111,7 +111,7 @@ class InstallerViewModel extends BaseViewModel { 'com.google.android.apps.youtube.music') { resourcePatching = true; } - await _patcherAPI.initPatcher(mergeIntegrations); + await _patcherAPI.mergeIntegrations(mergeIntegrations); await _patcherAPI.runPatcher( apkFilePath, _patches, diff --git a/pubspec.yaml b/pubspec.yaml index f0e7afd1..decc0081 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: file_picker: ^5.0.1 flutter: sdk: flutter + flutter_archive: ^5.0.0 flutter_background: ^1.1.0 flutter_cache_manager: ^3.3.0 flutter_i18n: ^0.32.4