diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index a242881a..34ad9a23 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -73,6 +73,8 @@ public final class app/revanced/patcher/Patcher : java/io/Closeable { } public final class app/revanced/patcher/PatcherConfig { + public fun (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/lang/String;)V + public synthetic fun (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V public synthetic fun (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V } diff --git a/gradle.properties b/gradle.properties index 773110d2..a7c245f0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.parallel = true -org.gradle.caching = true -version = 21.1.0-dev.1 +org.gradle.parallel=true +org.gradle.caching=true +version=21.1.0-dev.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 53dd7145..18adf689 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,14 @@ [versions] android = "4.1.1.4" -apktool-lib = "2.9.3" +apktool-lib = "2.10.1.1" binary-compatibility-validator = "0.15.1" -kotlin = "2.0.0" +kotlin = "2.0.20" kotlinx-coroutines-core = "1.8.1" mockk = "1.13.10" multidexlib2 = "3.0.3.r3" # Tracking https://github.com/google/smali/issues/64. #noinspection GradleDependency -smali = "3.0.5" +smali = "3.0.8" xpp3 = "1.1.4c" [libraries] diff --git a/src/main/kotlin/app/revanced/patcher/PatcherConfig.kt b/src/main/kotlin/app/revanced/patcher/PatcherConfig.kt index 7c4b6133..037f7d34 100644 --- a/src/main/kotlin/app/revanced/patcher/PatcherConfig.kt +++ b/src/main/kotlin/app/revanced/patcher/PatcherConfig.kt @@ -16,9 +16,28 @@ import java.util.logging.Logger class PatcherConfig( internal val apkFile: File, private val temporaryFilesPath: File = File("revanced-temporary-files"), - aaptBinaryPath: String? = null, + aaptBinaryPath: File? = null, frameworkFileDirectory: String? = null, ) { + /** + * The configuration for the patcher. + * + * @param apkFile The apk file to patch. + * @param temporaryFilesPath A path to a folder to store temporary files in. + * @param aaptBinaryPath A path to a custom aapt binary. + * @param frameworkFileDirectory A path to the directory to cache the framework file in. + */ + @Deprecated( + "Use the constructor with a File for aaptBinaryPath instead.", + ReplaceWith("PatcherConfig(apkFile, temporaryFilesPath, aaptBinaryPath?.let { File(it) }, frameworkFileDirectory)"), + ) + constructor( + apkFile: File, + temporaryFilesPath: File = File("revanced-temporary-files"), + aaptBinaryPath: String? = null, + frameworkFileDirectory: String? = null, + ) : this(apkFile, temporaryFilesPath, aaptBinaryPath?.let { File(it) }, frameworkFileDirectory) + private val logger = Logger.getLogger(PatcherConfig::class.java.name) /** @@ -33,8 +52,7 @@ class PatcherConfig( */ internal val resourceConfig = Config.getDefaultConfig().apply { - useAapt2 = true - aaptPath = aaptBinaryPath ?: "" + aaptBinary = aaptBinaryPath frameworkDirectory = frameworkFileDirectory } diff --git a/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt b/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt index f1ae3ab5..a65481d1 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/ResourcePatchContext.kt @@ -10,9 +10,9 @@ import brut.androlib.ApkDecoder import brut.androlib.apk.UsesFramework import brut.androlib.res.Framework import brut.androlib.res.ResourcesDecoder +import brut.androlib.res.decoder.AndroidManifestPullStreamDecoder import brut.androlib.res.decoder.AndroidManifestResourceParser -import brut.androlib.res.decoder.XmlPullStreamDecoder -import brut.androlib.res.xml.ResXmlPatcher +import brut.androlib.res.xml.ResXmlUtils import brut.directory.ExtFile import java.io.InputStream import java.io.OutputStream @@ -51,64 +51,62 @@ class ResourcePatchContext internal constructor( * * @param mode The [ResourceMode] to use. */ - internal fun decodeResources(mode: ResourceMode) = - with(packageMetadata.apkInfo) { - config.initializeTemporaryFilesDirectories() + internal fun decodeResources(mode: ResourceMode) = with(packageMetadata.apkInfo) { + config.initializeTemporaryFilesDirectories() - // Needed to decode resources. - val resourcesDecoder = ResourcesDecoder(config.resourceConfig, this) + // Needed to decode resources. + val resourcesDecoder = ResourcesDecoder(config.resourceConfig, this) - if (mode == ResourceMode.FULL) { - logger.info("Decoding resources") + if (mode == ResourceMode.FULL) { + logger.info("Decoding resources") - resourcesDecoder.decodeResources(config.apkFiles) - resourcesDecoder.decodeManifest(config.apkFiles) + resourcesDecoder.decodeResources(config.apkFiles) + resourcesDecoder.decodeManifest(config.apkFiles) - // Needed to record uncompressed files. - val apkDecoder = ApkDecoder(config.resourceConfig, this) - apkDecoder.recordUncompressedFiles(resourcesDecoder.resFileMapping) + // Needed to record uncompressed files. + ApkDecoder(this, config.resourceConfig).recordUncompressedFiles(resourcesDecoder.resFileMapping) - usesFramework = - UsesFramework().apply { - ids = resourcesDecoder.resTable.listFramePackages().map { it.id } - } - } else { - logger.info("Decoding app manifest") - - // Decode manually instead of using resourceDecoder.decodeManifest - // because it does not support decoding to an OutputStream. - XmlPullStreamDecoder( - AndroidManifestResourceParser(resourcesDecoder.resTable), - resourcesDecoder.resXmlSerializer, - ).decodeManifest( - apkFile.directory.getFileInput("AndroidManifest.xml"), - // Older Android versions do not support OutputStream.nullOutputStream() - object : OutputStream() { - override fun write(b: Int) { // Do nothing. - } - }, - ) - - // Get the package name and version from the manifest using the XmlPullStreamDecoder. - // XmlPullStreamDecoder.decodeManifest() sets metadata.apkInfo. - packageMetadata.let { metadata -> - metadata.packageName = resourcesDecoder.resTable.packageRenamed - versionInfo.let { - metadata.packageVersion = it.versionName ?: it.versionCode + usesFramework = + UsesFramework().apply { + ids = resourcesDecoder.resTable.listFramePackages().map { it.id } + } + } else { + logger.info("Decoding app manifest") + + // Decode manually instead of using resourceDecoder.decodeManifest + // because it does not support decoding to an OutputStream. + AndroidManifestPullStreamDecoder( + AndroidManifestResourceParser(resourcesDecoder.resTable), + resourcesDecoder.newXmlSerializer(), + ).decode( + apkFile.directory.getFileInput("AndroidManifest.xml"), + // Older Android versions do not support OutputStream.nullOutputStream() + object : OutputStream() { + override fun write(b: Int) { // Do nothing. } + }, + ) + + // Get the package name and version from the manifest using the XmlPullStreamDecoder. + // AndroidManifestPullStreamDecoder.decode() sets metadata.apkInfo. + packageMetadata.let { metadata -> + metadata.packageName = resourcesDecoder.resTable.packageRenamed + versionInfo.let { + metadata.packageVersion = it.versionName ?: it.versionCode + } - /* - The ResTable if flagged as sparse if the main package is not loaded, which is the case here, - because ResourcesDecoder.decodeResources loads the main package - and not XmlPullStreamDecoder.decodeManifest. - See ARSCDecoder.readTableType for more info. + /* + The ResTable if flagged as sparse if the main package is not loaded, which is the case here, + because ResourcesDecoder.decodeResources loads the main package + and not AndroidManifestPullStreamDecoder.decode. + See ARSCDecoder.readTableType for more info. - Set this to false again to prevent the ResTable from being flagged as sparse falsely. - */ - metadata.apkInfo.sparseResources = false - } + Set this to false again to prevent the ResTable from being flagged as sparse falsely. + */ + metadata.apkInfo.sparseResources = false } } + } /** * Compile resources in [PatcherConfig.apkFiles]. @@ -130,10 +128,10 @@ class ResourcePatchContext internal constructor( AaptInvoker( config.resourceConfig, packageMetadata.apkInfo, - ).invokeAapt( + ).invoke( resources.resolve("resources.apk"), config.apkFiles.resolve("AndroidManifest.xml").also { - ResXmlPatcher.fixingPublicAttrsInProviderAttributes(it) + ResXmlUtils.fixingPublicAttrsInProviderAttributes(it) }, config.apkFiles.resolve("res"), null,