You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-06 16:38:50 +02:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f4bc5079f | ||
![]() |
caf2745805 | ||
![]() |
a4529c3fee | ||
![]() |
835c0f9f7a | ||
![]() |
34f607aa24 | ||
![]() |
0f38b94701 | ||
![]() |
39bb1b25dc | ||
![]() |
4fc63a4d8a | ||
![]() |
6037397bc2 | ||
![]() |
273dd86b65 | ||
![]() |
e8488b3e86 | ||
![]() |
c13361823d | ||
![]() |
8f66f9f606 | ||
![]() |
a123026f46 | ||
![]() |
9c39c9efdb |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -28,8 +28,6 @@ jobs:
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,3 +1,38 @@
|
||||
# [1.8.0](https://github.com/revanced/revanced-patcher/compare/v1.7.2...v1.8.0) (2022-06-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* logging class ([caf2745](https://github.com/revanced/revanced-patcher/commit/caf2745805ffd4b59fa81e79cc489b1a1a5c5d89))
|
||||
|
||||
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](https://github.com/revanced/revanced-patcher/commit/34f607aa24d89a777d906cc887203f343ce3fd07))
|
||||
|
||||
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](https://github.com/revanced/revanced-patcher/commit/e8488b3e86e0132011824f8ecba29e64f8db0573))
|
||||
|
||||
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* migrate logger to `slf4j` ([8f66f9f](https://github.com/revanced/revanced-patcher/commit/8f66f9f606a785ac947b0e553822877f211d82df))
|
||||
|
||||
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* use of `java.util.logging.Logger` ([9c39c9e](https://github.com/revanced/revanced-patcher/commit/9c39c9efdb5d48ddaffce7f711c275e732b0b2d9))
|
||||
|
||||
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)
|
||||
|
||||
|
||||
|
@@ -1,2 +1,2 @@
|
||||
kotlin.code.style = official
|
||||
version = 1.5.0
|
||||
version = 1.8.0
|
||||
|
@@ -42,13 +42,18 @@ val NAMER = BasicDexFileNamer()
|
||||
* @param options The options for the patcher.
|
||||
*/
|
||||
class Patcher(private val options: PatcherOptions) {
|
||||
val data: PatcherData
|
||||
private val logger = options.logger
|
||||
private val opcodes: Opcodes
|
||||
|
||||
val data: PatcherData
|
||||
|
||||
init {
|
||||
val extInputFile = ExtFile(options.inputFile)
|
||||
val outDir = File(options.resourceCacheDirectory)
|
||||
if (outDir.exists()) outDir.deleteRecursively()
|
||||
if (outDir.exists()) {
|
||||
logger.info("Deleting existing resource cache directory")
|
||||
outDir.deleteRecursively()
|
||||
}
|
||||
outDir.mkdirs()
|
||||
|
||||
val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
|
||||
@@ -57,6 +62,8 @@ class Patcher(private val options: PatcherOptions) {
|
||||
val packageMetadata = PackageMetadata()
|
||||
|
||||
if (options.patchResources) {
|
||||
logger.info("Decoding resources using Androlib, this may take a long time...")
|
||||
|
||||
// decode resources to cache directory
|
||||
androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
|
||||
androlib.decodeResourcesFull(extInputFile, outDir, resourceTable)
|
||||
@@ -71,6 +78,8 @@ class Patcher(private val options: PatcherOptions) {
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.info("Decoding AndroidManifest.xml manually because resource patching is disabled")
|
||||
|
||||
// create decoder for the resource table
|
||||
val decoder = ResAttrDecoder()
|
||||
decoder.currentPackage = ResPackage(resourceTable, 0, null)
|
||||
@@ -93,6 +102,8 @@ class Patcher(private val options: PatcherOptions) {
|
||||
packageMetadata.metaInfo.versionInfo = resourceTable.versionInfo
|
||||
packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo
|
||||
|
||||
logger.info("Reading input as dex file")
|
||||
|
||||
// read dex files
|
||||
val dexFile = MultiDexIO.readDexFile(true, options.inputFile, NAMER, null, null)
|
||||
// get the opcodes
|
||||
@@ -111,22 +122,35 @@ class Patcher(private val options: PatcherOptions) {
|
||||
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
|
||||
*/
|
||||
fun addFiles(
|
||||
files: List<File>, allowedOverwrites: Iterable<String> = emptyList(), throwOnDuplicates: Boolean = false
|
||||
files: List<File>,
|
||||
allowedOverwrites: Iterable<String> = emptyList(),
|
||||
throwOnDuplicates: Boolean = false,
|
||||
callback: (File) -> Unit
|
||||
) {
|
||||
for (file in files) {
|
||||
for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
|
||||
val e = data.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type }
|
||||
if (e != null) {
|
||||
if (throwOnDuplicates) {
|
||||
throw Exception("Class ${classDef.type} has already been added to the patcher.")
|
||||
}
|
||||
val (_, idx) = e
|
||||
if (allowedOverwrites.contains(classDef.type)) {
|
||||
data.bytecodeData.classes.internalClasses[idx] = classDef
|
||||
}
|
||||
val type = classDef.type
|
||||
|
||||
val existingClass = data.bytecodeData.classes.internalClasses.findIndexed { it.type == type }
|
||||
if (existingClass == null) {
|
||||
if (throwOnDuplicates) throw Exception("Class $type has already been added to the patcher")
|
||||
|
||||
logger.trace("Merging $type")
|
||||
data.bytecodeData.classes.internalClasses.add(classDef)
|
||||
|
||||
callback(file)
|
||||
|
||||
continue
|
||||
}
|
||||
data.bytecodeData.classes.internalClasses.add(classDef)
|
||||
|
||||
if (!allowedOverwrites.contains(type)) continue
|
||||
|
||||
logger.trace("Overwriting $type")
|
||||
|
||||
val index = existingClass.second
|
||||
data.bytecodeData.classes.internalClasses[index] = classDef
|
||||
|
||||
callback(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,6 +164,7 @@ class Patcher(private val options: PatcherOptions) {
|
||||
var resourceFile: File? = null
|
||||
|
||||
if (options.patchResources) {
|
||||
logger.info("Patching resources")
|
||||
val cacheDirectory = ExtFile(options.resourceCacheDirectory)
|
||||
|
||||
val androlibResources = AndrolibResources().also { resources ->
|
||||
@@ -168,19 +193,19 @@ class Patcher(private val options: PatcherOptions) {
|
||||
val resDirectory = cacheDirectory.resolve("res")
|
||||
val includedFiles = metaInfo.usesFramework.ids.map { id ->
|
||||
androlibResources.getFrameworkApk(
|
||||
id,
|
||||
metaInfo.usesFramework.tag
|
||||
id, metaInfo.usesFramework.tag
|
||||
)
|
||||
}.toTypedArray()
|
||||
|
||||
logger.trace("Packaging using aapt")
|
||||
androlibResources.aaptPackage(
|
||||
aaptFile, manifestFile, resDirectory, null,
|
||||
null, includedFiles
|
||||
aaptFile, manifestFile, resDirectory, null, null, includedFiles
|
||||
)
|
||||
|
||||
resourceFile = aaptFile
|
||||
}
|
||||
|
||||
logger.trace("Creating new dex file")
|
||||
val newDexFile = object : DexFile {
|
||||
override fun getClasses(): Set<ClassDef> {
|
||||
data.bytecodeData.classes.applyProxies()
|
||||
@@ -192,7 +217,8 @@ class Patcher(private val options: PatcherOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// write dex modified files
|
||||
// write modified dex files
|
||||
logger.info("Writing modified dex files")
|
||||
val dexFiles = mutableMapOf<String, MemoryDataStore>()
|
||||
MultiDexIO.writeDexFile(
|
||||
true, -1, // core count
|
||||
@@ -202,9 +228,7 @@ class Patcher(private val options: PatcherOptions) {
|
||||
return PatcherResult(
|
||||
dexFiles.map {
|
||||
app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
|
||||
},
|
||||
metaInfo.doNotCompress.toList(),
|
||||
resourceFile
|
||||
}, metaInfo.doNotCompress.toList(), resourceFile
|
||||
)
|
||||
}
|
||||
|
||||
@@ -227,8 +251,14 @@ class Patcher(private val options: PatcherOptions) {
|
||||
): PatchResult {
|
||||
val patchName = patch.patchName
|
||||
|
||||
logger.trace("Applying patch $patchName")
|
||||
|
||||
// if the patch has already applied silently skip it
|
||||
if (appliedPatches.contains(patchName)) return PatchResultSuccess()
|
||||
if (appliedPatches.contains(patchName)) {
|
||||
logger.trace("Skipping patch $patchName because it has already been applied")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
appliedPatches.add(patchName)
|
||||
|
||||
// recursively apply all dependency patches
|
||||
@@ -246,7 +276,9 @@ class Patcher(private val options: PatcherOptions) {
|
||||
|
||||
// if the current patch is a resource patch but resource patching is disabled, return an error
|
||||
val isResourcePatch = patchInstance is ResourcePatch
|
||||
if (!options.patchResources && isResourcePatch) return PatchResultError("$patchName is a resource patch, but resource patching is disabled.")
|
||||
if (!options.patchResources && isResourcePatch) {
|
||||
return PatchResultError("$patchName is a resource patch, but resource patching is disabled.")
|
||||
}
|
||||
|
||||
// TODO: find a solution for this
|
||||
val data = if (isResourcePatch) {
|
||||
@@ -258,6 +290,8 @@ class Patcher(private val options: PatcherOptions) {
|
||||
data.bytecodeData
|
||||
}
|
||||
|
||||
logger.trace("Executing patch $patchName of type: ${if (isResourcePatch) "resource" else "bytecode"}")
|
||||
|
||||
return try {
|
||||
patchInstance.execute(data)
|
||||
} catch (e: Exception) {
|
||||
@@ -273,23 +307,22 @@ class Patcher(private val options: PatcherOptions) {
|
||||
* If the [Patch] failed to apply, an Exception will always be returned to the wrapping Result object.
|
||||
*/
|
||||
fun applyPatches(
|
||||
stopOnError: Boolean = false, callback: (String) -> Unit = {}
|
||||
stopOnError: Boolean = false, callback: (Class<out Patch<Data>>, Boolean) -> Unit = { _, _ -> }
|
||||
): Map<String, Result<PatchResultSuccess>> {
|
||||
logger.trace("Applying all patches")
|
||||
val appliedPatches = mutableListOf<String>()
|
||||
|
||||
return buildMap {
|
||||
for (patch in data.patches) {
|
||||
val result = applyPatch(patch, appliedPatches)
|
||||
|
||||
val name = patch.patchName
|
||||
callback(name)
|
||||
|
||||
this[name] = if (result.isSuccess()) {
|
||||
this[patch.patchName] = if (result.isSuccess()) {
|
||||
Result.success(result.success()!!)
|
||||
} else {
|
||||
Result.failure(result.error()!!)
|
||||
}
|
||||
|
||||
callback(patch, result.isSuccess())
|
||||
if (stopOnError && result.isError()) break
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,23 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.logging.impl.NopLogger
|
||||
import app.revanced.patcher.logging.Logger
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Options for a patcher.
|
||||
* Options for the [Patcher].
|
||||
* @param inputFile The input file (usually an apk file).
|
||||
* @param resourceCacheDirectory Directory to cache resources.
|
||||
* @param patchResources Weather to use the resource patcher. Resources will still need to be decoded.
|
||||
* @param aaptPath Optional path to a custom aapt binary.
|
||||
* @param frameworkFolderLocation Optional path to a custom framework folder.
|
||||
* @param logger Custom logger implementation for the [Patcher].
|
||||
*/
|
||||
data class PatcherOptions(
|
||||
internal val inputFile: File,
|
||||
internal val resourceCacheDirectory: String,
|
||||
internal val patchResources: Boolean = false,
|
||||
internal val aaptPath: String = "",
|
||||
internal val frameworkFolderLocation: String? = null
|
||||
internal val frameworkFolderLocation: String? = null,
|
||||
internal val logger: Logger = NopLogger
|
||||
)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.util.dex.DexFile
|
||||
import brut.directory.ExtFile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
|
8
src/main/kotlin/app/revanced/patcher/logging/Logger.kt
Normal file
8
src/main/kotlin/app/revanced/patcher/logging/Logger.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package app.revanced.patcher.logging
|
||||
|
||||
interface Logger {
|
||||
fun error(msg: String) {}
|
||||
fun warn(msg: String) {}
|
||||
fun info(msg: String) {}
|
||||
fun trace(msg: String) {}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package app.revanced.patcher.logging.impl
|
||||
|
||||
import app.revanced.patcher.logging.Logger
|
||||
|
||||
object NopLogger : Logger
|
Reference in New Issue
Block a user