You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-10-01 11:30:50 +02:00
Compare commits
62 Commits
v20.0.0-de
...
feat/kmp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c2e0f57579 | ||
![]() |
242e244b18 | ||
![]() |
f338ebff6c | ||
![]() |
00e5950cf2 | ||
![]() |
5a0e3841ff | ||
![]() |
cfb459b832 | ||
![]() |
2096306107 | ||
![]() |
92eaba8081 | ||
![]() |
7be0cd8548 | ||
![]() |
ab624f04f6 | ||
![]() |
21b5c079fb | ||
![]() |
5024204046 | ||
![]() |
a44802ef4e | ||
![]() |
4c1c34ad01 | ||
![]() |
b2aecb726d | ||
![]() |
851f9c7885 | ||
![]() |
ea6fc70caa | ||
![]() |
a2875d1d64 | ||
![]() |
2be6e97817 | ||
![]() |
348d0070e7 | ||
![]() |
d53aacdad4 | ||
![]() |
f1615b7ab5 | ||
![]() |
ffb1d880d7 | ||
![]() |
e95f13ae3e | ||
![]() |
e1b984d601 | ||
![]() |
c2dc29e061 | ||
![]() |
69f2f20fd9 | ||
![]() |
525beda18e | ||
![]() |
73d3cbf4ff | ||
![]() |
70278dd79d | ||
![]() |
5e98e9e30a | ||
![]() |
ac1aff5a1a | ||
![]() |
5481d0c54c | ||
![]() |
4604742d0f | ||
![]() |
4beb907a61 | ||
![]() |
7f44174d91 | ||
![]() |
d310246852 | ||
![]() |
dcc989243c | ||
![]() |
5227e98abf | ||
![]() |
8c4dd5b3a3 | ||
![]() |
736b3eebbf | ||
![]() |
b41a542952 | ||
![]() |
d21128fe2e | ||
![]() |
cf4374b8cf | ||
![]() |
8a30b0fa10 | ||
![]() |
11a911dc67 | ||
![]() |
6e3ba7419b | ||
![]() |
50a66ccfed | ||
![]() |
0be79840b1 | ||
![]() |
d8b4c60321 | ||
![]() |
f77e99e817 | ||
![]() |
ea26c486c0 | ||
![]() |
bebb734608 | ||
![]() |
d842f82d07 | ||
![]() |
82bab58ac2 | ||
![]() |
90b7631d9e | ||
![]() |
26d449e6d9 | ||
![]() |
49466060e3 | ||
![]() |
620ea5b852 | ||
![]() |
3e2168a2b2 | ||
![]() |
13c77967b1 | ||
![]() |
f57e571a14 |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -10,6 +10,9 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -46,5 +49,5 @@ jobs:
|
||||
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npm exec semantic-release
|
||||
|
@@ -23,7 +23,8 @@
|
||||
"assets": [
|
||||
"CHANGELOG.md",
|
||||
"gradle.properties"
|
||||
]
|
||||
],
|
||||
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
],
|
||||
[
|
||||
|
108
CHANGELOG.md
108
CHANGELOG.md
@@ -1,3 +1,111 @@
|
||||
## [20.0.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1...v20.0.2) (2024-10-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make it work on Android 12 and lower by using existing APIs ([#312](https://github.com/ReVanced/revanced-patcher/issues/312)) ([a44802e](https://github.com/ReVanced/revanced-patcher/commit/a44802ef4ebf59ae47213854ba761c81dadc51f3))
|
||||
|
||||
## [20.0.2-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1...v20.0.2-dev.1) (2024-10-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make it work on Android 12 and lower by using existing APIs ([#312](https://github.com/ReVanced/revanced-patcher/issues/312)) ([a44802e](https://github.com/ReVanced/revanced-patcher/commit/a44802ef4ebf59ae47213854ba761c81dadc51f3))
|
||||
|
||||
## [20.0.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0...v20.0.1) (2024-10-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Check for class type exactly instead of with contains ([#310](https://github.com/ReVanced/revanced-patcher/issues/310)) ([69f2f20](https://github.com/ReVanced/revanced-patcher/commit/69f2f20fd99162f91cd9c531dfe47d00d3152ead))
|
||||
* Make it work on Android by not using APIs from JVM unavailable to Android. ([2be6e97](https://github.com/ReVanced/revanced-patcher/commit/2be6e97817437f40e17893dfff3bea2cd4c3ff9e))
|
||||
* Use non-nullable type for options ([ea6fc70](https://github.com/ReVanced/revanced-patcher/commit/ea6fc70caab055251ad4d0d3f1b5cf53865abb85))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Free memory earlier and remove negligible lookup maps ([d53aacd](https://github.com/ReVanced/revanced-patcher/commit/d53aacdad4ed3750ddae526fb307577ea36e6171))
|
||||
|
||||
## [20.0.1-dev.5](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.4...v20.0.1-dev.5) (2024-10-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use non-nullable type for options ([ea6fc70](https://github.com/ReVanced/revanced-patcher/commit/ea6fc70caab055251ad4d0d3f1b5cf53865abb85))
|
||||
|
||||
## [20.0.1-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.3...v20.0.1-dev.4) (2024-10-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make it work on Android by not using APIs from JVM unavailable to Android. ([2be6e97](https://github.com/ReVanced/revanced-patcher/commit/2be6e97817437f40e17893dfff3bea2cd4c3ff9e))
|
||||
|
||||
## [20.0.1-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.2...v20.0.1-dev.3) (2024-10-03)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Free memory earlier and remove negligible lookup maps ([d53aacd](https://github.com/ReVanced/revanced-patcher/commit/d53aacdad4ed3750ddae526fb307577ea36e6171))
|
||||
|
||||
## [20.0.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.1...v20.0.1-dev.2) (2024-10-01)
|
||||
|
||||
## [20.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0...v20.0.1-dev.1) (2024-09-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Check for class type exactly instead of with contains ([#310](https://github.com/ReVanced/revanced-patcher/issues/310)) ([69f2f20](https://github.com/ReVanced/revanced-patcher/commit/69f2f20fd99162f91cd9c531dfe47d00d3152ead))
|
||||
|
||||
# [20.0.0](https://github.com/ReVanced/revanced-patcher/compare/v19.3.1...v20.0.0) (2024-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Downgrade smali to fix dex compilation issue ([5227e98](https://github.com/ReVanced/revanced-patcher/commit/5227e98abfaa2ff1204eb20a0f2671f58c489930))
|
||||
* Improve exception message wording ([5481d0c](https://github.com/ReVanced/revanced-patcher/commit/5481d0c54ccecc91cd8d15af1ba2d3285a33e5ab))
|
||||
* Make constructor internal as supposed ([7f44174](https://github.com/ReVanced/revanced-patcher/commit/7f44174d91f0af0d50a83d80a7103c779241e094))
|
||||
* Merge all extensions before initializing lookup maps ([8c4dd5b](https://github.com/ReVanced/revanced-patcher/commit/8c4dd5b3a309077fa9a3827b4931fc28b0517809))
|
||||
* Use null for compatible package version when adding packages only ([736b3ee](https://github.com/ReVanced/revanced-patcher/commit/736b3eebbfdd7279b8d5fcfc5c46c9e3aadbee12))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add ability to create options outside of a patch ([d310246](https://github.com/ReVanced/revanced-patcher/commit/d310246852504b08a15f6376bbf25ac7c6fae76f))
|
||||
* Convert APIs to Kotlin DSL ([#298](https://github.com/ReVanced/revanced-patcher/issues/298)) ([11a911d](https://github.com/ReVanced/revanced-patcher/commit/11a911dc674eb0801649949dd3f28dfeb00efe97))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Various old APIs are removed, and DSL APIs are added instead.
|
||||
|
||||
# [20.0.0-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0-dev.3...v20.0.0-dev.4) (2024-08-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Improve exception message wording ([bd434ce](https://github.com/ReVanced/revanced-patcher/commit/bd434ceb3394d1d5292e8b94e5bfd6da0e4e9c72))
|
||||
|
||||
# [20.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0-dev.2...v20.0.0-dev.3) (2024-08-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make constructor internal as supposed ([e95fcd1](https://github.com/ReVanced/revanced-patcher/commit/e95fcd1c0b641164bbf0840ec7e562aeb3bacc3e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add ability to create options outside of a patch ([b8d763a](https://github.com/ReVanced/revanced-patcher/commit/b8d763a66e0601627dd71c8c24247726aa300146))
|
||||
|
||||
# [20.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0-dev.1...v20.0.0-dev.2) (2024-07-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Downgrade smali to fix dex compilation issue ([714447d](https://github.com/ReVanced/revanced-patcher/commit/714447de70096bf736e8e1d31c14bb5f24195070))
|
||||
* Merge all extensions before initializing lookup maps ([328aa87](https://github.com/ReVanced/revanced-patcher/commit/328aa876d8ed7826be3713754b6404195e9fe84b))
|
||||
* Use null for compatible package version when adding packages only ([a8e8fa4](https://github.com/ReVanced/revanced-patcher/commit/a8e8fa4093deb8cffbd7a582409f41867f6b568b))
|
||||
|
||||
# [20.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v19.3.1...v20.0.0-dev.1) (2024-07-22)
|
||||
|
||||
|
||||
|
@@ -1,7 +1,4 @@
|
||||
public final class app/revanced/patcher/Fingerprint {
|
||||
public final fun getMatch ()Lapp/revanced/patcher/Match;
|
||||
public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
||||
public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;)Z
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/FingerprintBuilder {
|
||||
@@ -18,20 +15,17 @@ public final class app/revanced/patcher/FingerprintBuilder {
|
||||
|
||||
public final class app/revanced/patcher/FingerprintKt {
|
||||
public static final fun fingerprint (ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/Fingerprint;
|
||||
public static final fun fingerprint (Lapp/revanced/patcher/patch/BytecodePatchBuilder;ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatchBuilder$InvokedFingerprint;
|
||||
public static synthetic fun fingerprint$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/Fingerprint;
|
||||
public static synthetic fun fingerprint$default (Lapp/revanced/patcher/patch/BytecodePatchBuilder;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatchBuilder$InvokedFingerprint;
|
||||
}
|
||||
|
||||
public abstract interface annotation class app/revanced/patcher/InternalApi : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/Match {
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/Match$PatternMatch;Ljava/util/List;Lapp/revanced/patcher/patch/BytecodePatchContext;)V
|
||||
public final fun getClassDef ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
||||
public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
||||
public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
||||
public final fun getMutableMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public final fun getClassDef ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
||||
public final fun getMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public final fun getOriginalClassDef ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
||||
public final fun getOriginalMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
||||
public final fun getPatternMatch ()Lapp/revanced/patcher/Match$PatternMatch;
|
||||
public final fun getStringMatches ()Ljava/util/List;
|
||||
}
|
||||
@@ -63,11 +57,12 @@ public final class app/revanced/patcher/Patcher : java/io/Closeable {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherConfig {
|
||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Z)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherContext {
|
||||
public final class app/revanced/patcher/PatcherContext : java/io/Closeable {
|
||||
public fun close ()V
|
||||
public final fun getPackageMetadata ()Lapp/revanced/patcher/PackageMetadata;
|
||||
}
|
||||
|
||||
@@ -134,31 +129,28 @@ public final class app/revanced/patcher/extensions/InstructionExtensions {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
||||
public final fun getExtension ()Ljava/io/InputStream;
|
||||
public final fun getFingerprints ()Ljava/util/Set;
|
||||
public final fun getExtensionInputStream ()Ljava/util/function/Supplier;
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/BytecodePatchBuilder : app/revanced/patcher/patch/PatchBuilder {
|
||||
public synthetic fun build$revanced_patcher ()Lapp/revanced/patcher/patch/Patch;
|
||||
public final fun extendWith (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatchBuilder;
|
||||
public final fun getExtension ()Ljava/io/InputStream;
|
||||
public final fun invoke (Lapp/revanced/patcher/Fingerprint;)Lapp/revanced/patcher/patch/BytecodePatchBuilder$InvokedFingerprint;
|
||||
public final fun setExtension (Ljava/io/InputStream;)V
|
||||
public final fun getExtensionInputStream ()Ljava/util/function/Supplier;
|
||||
public final fun setExtensionInputStream (Ljava/util/function/Supplier;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/BytecodePatchBuilder$InvokedFingerprint {
|
||||
public fun <init> (Lapp/revanced/patcher/Fingerprint;)V
|
||||
public final fun getValue (Ljava/lang/Void;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/Match;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/BytecodePatchContext : app/revanced/patcher/patch/PatchContext {
|
||||
public final class app/revanced/patcher/patch/BytecodePatchContext : app/revanced/patcher/patch/PatchContext, java/io/Closeable {
|
||||
public final fun classBy (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
||||
public final fun classByType (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
||||
public fun close ()V
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Ljava/util/Set;
|
||||
public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList;
|
||||
public final fun navigate (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/MethodNavigator;
|
||||
public final fun getMatch (Lapp/revanced/patcher/Fingerprint;)Lapp/revanced/patcher/Match;
|
||||
public final fun getValue (Lapp/revanced/patcher/Fingerprint;Ljava/lang/Void;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/Match;
|
||||
public final fun match (Lapp/revanced/patcher/Fingerprint;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/Match;
|
||||
public final fun match (Lapp/revanced/patcher/Fingerprint;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/Match;
|
||||
public final fun navigate (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)Lapp/revanced/patcher/util/MethodNavigator;
|
||||
public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
||||
}
|
||||
|
||||
@@ -203,25 +195,43 @@ public final class app/revanced/patcher/patch/OptionException$ValueValidationExc
|
||||
|
||||
public final class app/revanced/patcher/patch/OptionKt {
|
||||
public static final fun booleanOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun booleanOption (Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun booleanOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun booleanOption$default (Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun booleansOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun booleansOption (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun booleansOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun booleansOption$default (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun floatOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun floatOption (Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun floatOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun floatOption$default (Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun floatsOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun floatsOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun intOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun intOption (Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun intOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun intOption$default (Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun intsOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun intsOption (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun intsOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun intsOption$default (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun longOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun longOption (Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun longOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun longOption$default (Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun longsOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun longsOption (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun longsOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun longsOption$default (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun stringOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun stringOption (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun stringOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun stringOption$default (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun stringsOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static final fun stringsOption (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun stringsOption$default (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
public static synthetic fun stringsOption$default (Ljava/lang/String;Ljava/util/List;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/Option;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/Options : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
|
||||
@@ -267,7 +277,7 @@ public final class app/revanced/patcher/patch/Options : java/util/Map, kotlin/jv
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/Patch {
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;Ljava/util/Set;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/util/Set;Ljava/util/Set;Ljava/util/Set;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun execute (Lapp/revanced/patcher/patch/PatchContext;)V
|
||||
public final fun finalize (Lapp/revanced/patcher/patch/PatchContext;)V
|
||||
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||
@@ -284,13 +294,13 @@ public abstract class app/revanced/patcher/patch/PatchBuilder {
|
||||
public final fun compatibleWith ([Ljava/lang/String;)V
|
||||
public final fun compatibleWith ([Lkotlin/Pair;)V
|
||||
public final fun dependsOn ([Lapp/revanced/patcher/patch/Patch;)V
|
||||
public final fun execute (Lkotlin/jvm/functions/Function2;)V
|
||||
public final fun finalize (Lkotlin/jvm/functions/Function2;)V
|
||||
public final fun execute (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun finalize (Lkotlin/jvm/functions/Function1;)V
|
||||
protected final fun getCompatiblePackages ()Ljava/util/Set;
|
||||
protected final fun getDependencies ()Ljava/util/Set;
|
||||
protected final fun getDescription ()Ljava/lang/String;
|
||||
protected final fun getExecutionBlock ()Lkotlin/jvm/functions/Function2;
|
||||
protected final fun getFinalizeBlock ()Lkotlin/jvm/functions/Function2;
|
||||
protected final fun getExecutionBlock ()Lkotlin/jvm/functions/Function1;
|
||||
protected final fun getFinalizeBlock ()Lkotlin/jvm/functions/Function1;
|
||||
protected final fun getName ()Ljava/lang/String;
|
||||
protected final fun getOptions ()Ljava/util/Set;
|
||||
protected final fun getUse ()Z
|
||||
@@ -298,8 +308,8 @@ public abstract class app/revanced/patcher/patch/PatchBuilder {
|
||||
public final fun invoke (Ljava/lang/String;[Ljava/lang/String;)Lkotlin/Pair;
|
||||
protected final fun setCompatiblePackages (Ljava/util/Set;)V
|
||||
protected final fun setDependencies (Ljava/util/Set;)V
|
||||
protected final fun setExecutionBlock (Lkotlin/jvm/functions/Function2;)V
|
||||
protected final fun setFinalizeBlock (Lkotlin/jvm/functions/Function2;)V
|
||||
protected final fun setExecutionBlock (Lkotlin/jvm/functions/Function1;)V
|
||||
protected final fun setFinalizeBlock (Lkotlin/jvm/functions/Function1;)V
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/patcher/patch/PatchContext : java/util/function/Supplier {
|
||||
@@ -376,18 +386,13 @@ public final class app/revanced/patcher/patch/ResourcePatchBuilder : app/revance
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/ResourcePatchContext : app/revanced/patcher/patch/PatchContext {
|
||||
public final fun delete (Ljava/lang/String;)Z
|
||||
public final fun document (Ljava/io/InputStream;)Lapp/revanced/patcher/util/Document;
|
||||
public final fun document (Ljava/lang/String;)Lapp/revanced/patcher/util/Document;
|
||||
public fun get ()Lapp/revanced/patcher/PatcherResult$PatchedResources;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public final fun get (Ljava/lang/String;Z)Ljava/io/File;
|
||||
public static synthetic fun get$default (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;ZILjava/lang/Object;)Ljava/io/File;
|
||||
public final fun getDocument ()Lapp/revanced/patcher/patch/ResourcePatchContext$DocumentOperatable;
|
||||
public final fun stageDelete (Lkotlin/jvm/functions/Function1;)Z
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/ResourcePatchContext$DocumentOperatable {
|
||||
public fun <init> (Lapp/revanced/patcher/patch/ResourcePatchContext;)V
|
||||
public final fun get (Ljava/io/InputStream;)Lapp/revanced/patcher/util/Document;
|
||||
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/Document;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/Document : java/io/Closeable, org/w3c/dom/Document {
|
||||
@@ -466,8 +471,9 @@ public final class app/revanced/patcher/util/MethodNavigator {
|
||||
public final fun at (ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/MethodNavigator;
|
||||
public final fun at ([I)Lapp/revanced/patcher/util/MethodNavigator;
|
||||
public static synthetic fun at$default (Lapp/revanced/patcher/util/MethodNavigator;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/util/MethodNavigator;
|
||||
public final fun immutable ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
||||
public final fun mutable ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public final fun getValue (Ljava/lang/Void;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public final fun original ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
||||
public final fun stop ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/ProxyClassList : java/util/List, kotlin/jvm/internal/markers/KMutableList {
|
||||
|
@@ -36,20 +36,21 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.xpp3)
|
||||
implementation(libs.smali)
|
||||
implementation(libs.multidexlib2)
|
||||
implementation(libs.apktool.lib)
|
||||
implementation(libs.kotlin.reflect)
|
||||
|
||||
// TODO: Convert project to KMP.
|
||||
compileOnly(libs.android) {
|
||||
// Exclude, otherwise the org.w3c.dom API breaks.
|
||||
exclude(group = "xerces", module = "xmlParserAPIs")
|
||||
}
|
||||
testImplementation(libs.kotlin.test)
|
||||
|
||||
implementation(libs.apktool.lib)
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.multidexlib2)
|
||||
implementation(libs.smali)
|
||||
implementation(libs.xpp3)
|
||||
|
||||
testImplementation(libs.mockk)
|
||||
testImplementation(libs.kotlin.test)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
@@ -72,6 +72,10 @@ To start developing patches with ReVanced Patcher, you must prepare a developmen
|
||||
|
||||
Throughout the documentation, [ReVanced Patches](https://github.com/revanced/revanced-patches) will be used as an example project.
|
||||
|
||||
> [!NOTE]
|
||||
> To start a fresh project,
|
||||
> you can use the [ReVanced Patches template](https://github.com/revanced/revanced-patches-template).
|
||||
|
||||
1. Clone the repository
|
||||
|
||||
```bash
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -76,23 +76,23 @@ val disableAdsPatch = bytecodePatch(
|
||||
) {
|
||||
compatibleWith("com.some.app"("1.0.0"))
|
||||
|
||||
// Resource patch disables ads by patching resource files.
|
||||
// Patches can depend on other patches, executing them first.
|
||||
dependsOn(disableAdsResourcePatch)
|
||||
|
||||
// Precompiled DEX file to be merged into the patched app.
|
||||
// Merge precompiled DEX files into the patched app, before the patch is executed.
|
||||
extendWith("disable-ads.rve")
|
||||
|
||||
// Fingerprint to find the method to patch.
|
||||
val showAdsMatch by showAdsFingerprint {
|
||||
// More about fingerprints on the next page of the documentation.
|
||||
}
|
||||
|
||||
// Business logic of the patch to disable ads in the app.
|
||||
execute {
|
||||
// Fingerprint to find the method to patch.
|
||||
val showAdsMatch by showAdsFingerprint {
|
||||
// More about fingerprints on the next page of the documentation.
|
||||
}
|
||||
|
||||
// In the method that shows ads,
|
||||
// call DisableAdsPatch.shouldDisableAds() from the extension (precompiled DEX file)
|
||||
// to enable or disable ads.
|
||||
showAdsMatch.mutableMethod.addInstructions(
|
||||
showAdsMatch.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, LDisableAdsPatch;->shouldDisableAds()Z
|
||||
@@ -115,9 +115,9 @@ val disableAdsPatch = bytecodePatch(
|
||||
Patches can have options to get and set before a patch is executed.
|
||||
Options are useful for making patches configurable.
|
||||
After loading the patches using `PatchLoader`, options can be set for a patch.
|
||||
Multiple types are already inbuilt in ReVanced Patcher and are supported by any application that uses ReVanced Patcher.
|
||||
Multiple types are already built into ReVanced Patcher and are supported by any application that uses ReVanced Patcher.
|
||||
|
||||
To define an option, use available `option` functions:
|
||||
To define an option, use the available `option` functions:
|
||||
|
||||
```kt
|
||||
val patch = bytecodePatch(name = "Patch") {
|
||||
@@ -146,12 +146,24 @@ loadPatchesJar(patches).apply {
|
||||
The type of an option can be obtained from the `type` property of the option:
|
||||
|
||||
```kt
|
||||
option.type // The KType of the option.
|
||||
option.type // The KType of the option. Captures the full type information of the option.
|
||||
```
|
||||
|
||||
Options can be declared outside a patch and added to a patch manually:
|
||||
|
||||
```kt
|
||||
val option = stringOption(key = "option")
|
||||
|
||||
bytecodePatch(name = "Patch") {
|
||||
val value by option()
|
||||
}
|
||||
```
|
||||
|
||||
This is useful when the same option is referenced in multiple patches.
|
||||
|
||||
### 🧩 Extensions
|
||||
|
||||
An extension is a precompiled DEX file that is merged into the patched app before a patch is executed.
|
||||
An extension is a precompiled DEX file merged into the patched app before a patch is executed.
|
||||
While patches are compile-time constructs, extensions are runtime constructs
|
||||
that extend the patched app with additional classes.
|
||||
|
||||
@@ -171,11 +183,9 @@ and use it in a patch:
|
||||
```kt
|
||||
val patch = bytecodePatch(name = "Complex patch") {
|
||||
extendWith("complex-patch.rve")
|
||||
|
||||
val match by methodFingerprint()
|
||||
|
||||
|
||||
execute {
|
||||
match.mutableMethod.addInstructions(0, "invoke-static { }, LComplexPatch;->doSomething()V")
|
||||
fingerprint.match!!.mutableMethod.addInstructions(0, "invoke-static { }, LComplexPatch;->doSomething()V")
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -232,13 +242,13 @@ The same order is followed for multiple patches depending on the patch.
|
||||
|
||||
## 💡 Additional tips
|
||||
|
||||
- When using ´PatchLoader` to load patches, only patches with a name are loaded.
|
||||
- When using `PatchLoader` to load patches, only patches with a name are loaded.
|
||||
Refer to the inline documentation of `PatchLoader` for detailed information.
|
||||
- Patches can depend on others. Dependencies are executed first.
|
||||
The dependent patch will not be executed if a dependency raises an exception while executing.
|
||||
- A patch can declare compatibility with specific packages and versions,
|
||||
but patches can still be executed on any package or version.
|
||||
It is recommended to declare compatibility to present known compatible packages and versions.
|
||||
It is recommended that compatibility is specified to present known compatible packages and versions.
|
||||
- If `compatibleWith` is not used, the patch is treated as compatible with any package
|
||||
- If a package is specified with no versions, the patch is compatible with any version of the package
|
||||
- If an empty array of versions is specified, the patch is not compatible with any version of the package.
|
||||
|
@@ -96,21 +96,21 @@ Example of patches:
|
||||
@Surpress("unused")
|
||||
val bytecodePatch = bytecodePatch {
|
||||
execute {
|
||||
// TODO
|
||||
// More about this on the next page of the documentation.
|
||||
}
|
||||
}
|
||||
|
||||
@Surpress("unused")
|
||||
val rawResourcePatch = rawResourcePatch {
|
||||
execute {
|
||||
// TODO
|
||||
execute {
|
||||
// More about this on the next page of the documentation.
|
||||
}
|
||||
}
|
||||
|
||||
@Surpress("unused")
|
||||
val resourcePatch = rawResourcePatch {
|
||||
execute {
|
||||
// TODO
|
||||
val resourcePatch = resourcePatch {
|
||||
execute {
|
||||
// More about this on the next page of the documentation.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
107
docs/4_apis.md
107
docs/4_apis.md
@@ -4,18 +4,107 @@ A handful of APIs are available to make patch development easier and more effici
|
||||
|
||||
## 📙 Overview
|
||||
|
||||
1. 👹 Mutate classes with `context.proxy(ClassDef)`
|
||||
2. 🔍 Find and proxy existing classes with `classBy(Predicate)` and `classByType(String)`
|
||||
3. 🏃 Easily access referenced methods recursively by index with `MethodNavigator`
|
||||
4. 🔨 Make use of extension functions from `BytecodeUtils` and `ResourceUtils` with certain applications
|
||||
(Available in ReVanced Patches)
|
||||
5. 💾 Read and write (decoded) resources with `ResourcePatchContext.get(Path, Boolean)`
|
||||
6. 📃 Read and write DOM files using `ResourcePatchContext.document`
|
||||
1. 👹 Create mutable replacements of classes with `proxy(ClassDef)`
|
||||
2. 🔍 Find and create mutable replaces with `classBy(Predicate)`
|
||||
3. 🏃 Navigate method calls recursively by index with `navigate(Method)`
|
||||
4. 💾 Read and write resource files with `get(String, Boolean)` and `delete(String)`
|
||||
5. 📃 Read and write DOM files using `document(String)` and `document(InputStream)`
|
||||
|
||||
### 🧰 APIs
|
||||
|
||||
> [!WARNING]
|
||||
> This section is still under construction and may be incomplete.
|
||||
#### 👹 `proxy(ClassDef)`
|
||||
|
||||
By default, the classes are immutable, meaning they cannot be modified.
|
||||
To make a class mutable, use the `proxy(ClassDef)` function.
|
||||
This function creates a lazy mutable copy of the class definition.
|
||||
Accessing the property will replace the original class definition with the mutable copy,
|
||||
thus allowing you to make changes to the class. Subsequent accesses will return the same mutable copy.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
val mutableClass = proxy(classDef)
|
||||
mutableClass.methods.add(Method())
|
||||
}
|
||||
```
|
||||
|
||||
#### 🔍 `classBy(Predicate)`
|
||||
|
||||
The `classBy(Predicate)` function is an alternative to finding and creating mutable classes by a predicate.
|
||||
It automatically proxies the class definition, making it mutable.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
// Alternative to proxy(classes.find { it.name == "Lcom/example/MyClass;" })?.classDef
|
||||
val classDef = classBy { it.name == "Lcom/example/MyClass;" }?.classDef
|
||||
}
|
||||
```
|
||||
|
||||
#### 🏃 `navigate(Method).at(index)`
|
||||
|
||||
The `navigate(Method)` function allows you to navigate method calls recursively by index.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
// Sequentially navigate to the instructions at index 1 within 'someMethod'.
|
||||
val method = navigate(someMethod).at(1).original() // original() returns the original immutable method.
|
||||
|
||||
// Further navigate to the second occurrence where the instruction's opcode is 'INVOKEVIRTUAL'.
|
||||
// stop() returns the mutable copy of the method.
|
||||
val method = navigate(someMethod).at(2) { instruction -> instruction.opcode == Opcode.INVOKEVIRTUAL }.stop()
|
||||
|
||||
// Alternatively, to stop(), you can delegate the method to a variable.
|
||||
val method by navigate(someMethod).at(1)
|
||||
|
||||
// You can chain multiple calls to at() to navigate deeper into the method.
|
||||
val method by navigate(someMethod).at(1).at(2, 3, 4).at(5)
|
||||
}
|
||||
```
|
||||
|
||||
#### 💾 `get(String, Boolean)` and `delete(String)`
|
||||
|
||||
The `get(String, Boolean)` function returns a `File` object that can be used to read and write resource files.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
val file = get("res/values/strings.xml")
|
||||
val content = file.readText()
|
||||
file.writeText(content)
|
||||
}
|
||||
```
|
||||
|
||||
The `delete` function can mark files for deletion when the APK is rebuilt.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
delete("res/values/strings.xml")
|
||||
}
|
||||
```
|
||||
|
||||
#### 📃 `document(String)` and `document(InputStream)`
|
||||
|
||||
The `document` function is used to read and write DOM files.
|
||||
|
||||
```kt
|
||||
execute {
|
||||
document("res/values/strings.xml").use { document ->
|
||||
val element = doc.createElement("string").apply {
|
||||
textContent = "Hello, World!"
|
||||
}
|
||||
document.documentElement.appendChild(element)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also read documents from an `InputStream`:
|
||||
|
||||
```kt
|
||||
execute {
|
||||
val inputStream = classLoader.getResourceAsStream("some.xml")
|
||||
document(inputStream).use { document ->
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎉 Afterword
|
||||
|
||||
|
@@ -1,3 +1,3 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
version = 20.0.0-dev.1
|
||||
version = 20.0.2
|
||||
|
@@ -1,20 +1,22 @@
|
||||
[versions]
|
||||
android = "4.1.1.4"
|
||||
apktool-lib = "2.9.3"
|
||||
kotlin = "1.9.22"
|
||||
kotlinx-coroutines-core = "1.7.3"
|
||||
binary-compatibility-validator = "0.15.1"
|
||||
kotlin = "2.0.0"
|
||||
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"
|
||||
binary-compatibility-validator = "0.14.0"
|
||||
xpp3 = "1.1.4c"
|
||||
|
||||
[libraries]
|
||||
android = { module = "com.google.android:android", version.ref = "android" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
|
||||
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
|
||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
8
gradle/wrapper/gradle-wrapper.properties
vendored
8
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dist
|
||||
zipStorePath=wrapper/dists
|
||||
|
22
gradlew
vendored
22
gradlew
vendored
@@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -83,7 +85,9 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -201,11 +205,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
2972
package-lock.json
generated
2972
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.9.1",
|
||||
"semantic-release": "^23.0.2"
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"semantic-release": "^24.1.2"
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -39,9 +39,6 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||
patch.addRecursively()
|
||||
}
|
||||
|
||||
fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean =
|
||||
predicate(this) || dependencies.any { dependency -> dependency.anyRecursively(predicate) }
|
||||
|
||||
context.allPatches.let { allPatches ->
|
||||
// Check, if what kind of resource mode is required.
|
||||
config.resourceMode = if (allPatches.any { patch -> patch.anyRecursively { it is ResourcePatch } }) {
|
||||
@@ -94,11 +91,16 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||
}.also { executedPatches[this] = it }
|
||||
}
|
||||
|
||||
// Prevent from decoding the app manifest twice if it is not needed.
|
||||
// Prevent decoding the app manifest twice if it is not needed.
|
||||
if (config.resourceMode != ResourcePatchContext.ResourceMode.NONE) {
|
||||
context.resourceContext.decodeResources(config.resourceMode)
|
||||
}
|
||||
|
||||
logger.info("Initializing lookup maps")
|
||||
|
||||
// Accessing the lazy lookup maps to initialize them.
|
||||
context.bytecodeContext.lookupMaps
|
||||
|
||||
logger.info("Executing patches")
|
||||
|
||||
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>()
|
||||
@@ -146,7 +148,7 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() = context.bytecodeContext.lookupMaps.close()
|
||||
override fun close() = context.close()
|
||||
|
||||
/**
|
||||
* Compile and save patched APK files.
|
||||
|
@@ -12,15 +12,12 @@ import java.util.logging.Logger
|
||||
* @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.
|
||||
* @param multithreadingDexFileWriter Whether to use multiple threads for writing dex files.
|
||||
* This has impact on memory usage and performance.
|
||||
*/
|
||||
class PatcherConfig(
|
||||
internal val apkFile: File,
|
||||
private val temporaryFilesPath: File = File("revanced-temporary-files"),
|
||||
aaptBinaryPath: String? = null,
|
||||
frameworkFileDirectory: String? = null,
|
||||
internal val multithreadingDexFileWriter: Boolean = false,
|
||||
) {
|
||||
private val logger = Logger.getLogger(PatcherConfig::class.java.name)
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.ResourcePatchContext
|
||||
import brut.androlib.apk.ApkInfo
|
||||
import brut.directory.ExtFile
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the patcher.
|
||||
@@ -12,7 +13,7 @@ import brut.directory.ExtFile
|
||||
* @param config The configuration for the patcher.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class PatcherContext internal constructor(config: PatcherConfig) {
|
||||
class PatcherContext internal constructor(config: PatcherConfig): Closeable {
|
||||
/**
|
||||
* [PackageMetadata] of the supplied [PatcherConfig.apkFile].
|
||||
*/
|
||||
@@ -37,4 +38,6 @@ class PatcherContext internal constructor(config: PatcherConfig) {
|
||||
* The context for patches containing the current state of the bytecode.
|
||||
*/
|
||||
internal val bytecodeContext = BytecodePatchContext(config)
|
||||
|
||||
override fun close() = bytecodeContext.close()
|
||||
}
|
||||
|
@@ -29,12 +29,12 @@ class PatcherResult internal constructor(
|
||||
* @param resourcesApk The compiled resources.apk file.
|
||||
* @param otherResources The directory containing other resources files.
|
||||
* @param doNotCompress List of files that should not be compressed.
|
||||
* @param deleteResources List of predicates about resources that should be deleted.
|
||||
* @param deleteResources List of resources that should be deleted.
|
||||
*/
|
||||
class PatchedResources internal constructor(
|
||||
val resourcesApk: File?,
|
||||
val otherResources: File?,
|
||||
val doNotCompress: Set<String>,
|
||||
val deleteResources: Set<(String) -> Boolean>,
|
||||
val deleteResources: Set<String>,
|
||||
)
|
||||
}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.InternalApi
|
||||
import app.revanced.patcher.PatcherConfig
|
||||
import app.revanced.patcher.PatcherResult
|
||||
import app.revanced.patcher.*
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructionsOrNull
|
||||
import app.revanced.patcher.util.ClassMerger.merge
|
||||
import app.revanced.patcher.util.MethodNavigator
|
||||
@@ -14,6 +12,7 @@ import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.DexFile
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
import lanchon.multidexlib2.BasicDexFileNamer
|
||||
import lanchon.multidexlib2.DexIO
|
||||
@@ -21,9 +20,9 @@ import lanchon.multidexlib2.MultiDexIO
|
||||
import lanchon.multidexlib2.RawDexIO
|
||||
import java.io.Closeable
|
||||
import java.io.FileFilter
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import java.util.logging.Logger
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A context for patches containing the current state of the bytecode.
|
||||
@@ -31,7 +30,9 @@ import java.util.logging.Logger
|
||||
* @param config The [PatcherConfig] used to create this context.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class BytecodePatchContext internal constructor(private val config: PatcherConfig) : PatchContext<Set<PatcherResult.PatchedDexFile>> {
|
||||
class BytecodePatchContext internal constructor(private val config: PatcherConfig) :
|
||||
PatchContext<Set<PatcherResult.PatchedDexFile>>,
|
||||
Closeable {
|
||||
private val logger = Logger.getLogger(BytecodePatchContext::class.java.name)
|
||||
|
||||
/**
|
||||
@@ -52,50 +53,73 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
).also { opcodes = it.opcodes }.classes.toMutableList(),
|
||||
)
|
||||
|
||||
/**
|
||||
* The match for this [Fingerprint]. Null if unmatched.
|
||||
*/
|
||||
val Fingerprint.match get() = match(this@BytecodePatchContext)
|
||||
|
||||
/**
|
||||
* Match using a [ClassDef].
|
||||
*
|
||||
* @param classDef The class to match against.
|
||||
* @return The [Match] if a match was found or if the fingerprint is already matched to a method, null otherwise.
|
||||
*/
|
||||
fun Fingerprint.match(classDef: ClassDef) = match(this@BytecodePatchContext, classDef)
|
||||
|
||||
/**
|
||||
* Match using a [Method].
|
||||
* The class is retrieved from the method.
|
||||
*
|
||||
* @param method The method to match against.
|
||||
* @return The [Match] if a match was found or if the fingerprint is already matched to a method, null otherwise.
|
||||
*/
|
||||
fun Fingerprint.match(method: Method) = match(this@BytecodePatchContext, method)
|
||||
|
||||
/**
|
||||
* Get the match for this [Fingerprint].
|
||||
*
|
||||
* @throws IllegalStateException If the [Fingerprint] has not been matched.
|
||||
*/
|
||||
operator fun Fingerprint.getValue(nothing: Nothing?, property: KProperty<*>): Match = _match
|
||||
?: throw PatchException("No fingerprint match to delegate to \"${property.name}\".")
|
||||
|
||||
/**
|
||||
* The lookup maps for methods and the class they are a member of from the [classes].
|
||||
*/
|
||||
internal val lookupMaps by lazy { LookupMaps(classes) }
|
||||
|
||||
/**
|
||||
* Merge an extension to [classes].
|
||||
* Merge the extension of [bytecodePatch] into the [BytecodePatchContext].
|
||||
* If no extension is present, the function will return early.
|
||||
*
|
||||
* @param extensionInputStream The input stream of the extension to merge.
|
||||
* @param bytecodePatch The [BytecodePatch] to merge the extension of.
|
||||
*/
|
||||
internal fun merge(extensionInputStream: InputStream) {
|
||||
val extension = extensionInputStream.readAllBytes()
|
||||
internal fun mergeExtension(bytecodePatch: BytecodePatch) {
|
||||
bytecodePatch.extensionInputStream?.get()?.use { extensionStream ->
|
||||
RawDexIO.readRawDexFile(extensionStream, 0, null).classes.forEach { classDef ->
|
||||
val existingClass = lookupMaps.classesByType[classDef.type] ?: run {
|
||||
logger.fine("Adding class \"$classDef\"")
|
||||
|
||||
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
||||
val existingClass = lookupMaps.classesByType[classDef.type] ?: run {
|
||||
logger.fine("Adding class \"$classDef\"")
|
||||
classes += classDef
|
||||
lookupMaps.classesByType[classDef.type] = classDef
|
||||
|
||||
lookupMaps.classesByType[classDef.type] = classDef
|
||||
classes += classDef
|
||||
|
||||
return@forEach
|
||||
}
|
||||
|
||||
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")
|
||||
|
||||
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
|
||||
// If the class was merged, replace the original class with the merged class.
|
||||
if (mergedClass === existingClass) {
|
||||
return@let
|
||||
return@forEach
|
||||
}
|
||||
|
||||
classes -= existingClass
|
||||
classes += mergedClass
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")
|
||||
|
||||
/**
|
||||
* Find a class by its type using a contains check.
|
||||
*
|
||||
* @param type The type of the class.
|
||||
* @return A proxy for the first class that matches the type.
|
||||
*/
|
||||
fun classByType(type: String) = classBy { type in it.type }
|
||||
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
|
||||
// If the class was merged, replace the original class with the merged class.
|
||||
if (mergedClass === existingClass) {
|
||||
return@let
|
||||
}
|
||||
|
||||
classes -= existingClass
|
||||
classes += mergedClass
|
||||
}
|
||||
}
|
||||
} ?: logger.fine("No extension to merge")
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a class with a predicate.
|
||||
@@ -124,7 +148,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
*
|
||||
* @return A [MethodNavigator] for the method.
|
||||
*/
|
||||
fun navigate(method: Method) = MethodNavigator(this@BytecodePatchContext, method)
|
||||
fun navigate(method: MethodReference) = MethodNavigator(this@BytecodePatchContext, method)
|
||||
|
||||
/**
|
||||
* Compile bytecode from the [BytecodePatchContext].
|
||||
@@ -135,6 +159,9 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
override fun get(): Set<PatcherResult.PatchedDexFile> {
|
||||
logger.info("Compiling patched dex files")
|
||||
|
||||
// Free up memory before compiling the dex files.
|
||||
lookupMaps.close()
|
||||
|
||||
val patchedDexFileResults =
|
||||
config.patchedFiles.resolve("dex").also {
|
||||
it.deleteRecursively() // Make sure the directory is empty.
|
||||
@@ -142,7 +169,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
}.apply {
|
||||
MultiDexIO.writeDexFile(
|
||||
true,
|
||||
if (config.multithreadingDexFileWriter) -1 else 1,
|
||||
-1,
|
||||
this,
|
||||
BasicDexFileNamer(),
|
||||
object : DexFile {
|
||||
@@ -168,47 +195,21 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
* @param classes The list of classes to create the lookup maps from.
|
||||
*/
|
||||
internal class LookupMaps internal constructor(classes: List<ClassDef>) : Closeable {
|
||||
/**
|
||||
* Classes associated by their type.
|
||||
*/
|
||||
internal val classesByType = classes.associateBy { it.type }.toMutableMap()
|
||||
|
||||
/**
|
||||
* All methods and the class they are a member of.
|
||||
*/
|
||||
internal val allMethods = MethodClassPairs()
|
||||
|
||||
/**
|
||||
* Methods associated by its access flags, return type and parameter.
|
||||
*/
|
||||
internal val methodsBySignature = MethodClassPairsLookupMap()
|
||||
|
||||
/**
|
||||
* Methods associated by strings referenced in it.
|
||||
*/
|
||||
internal val methodsByStrings = MethodClassPairsLookupMap()
|
||||
|
||||
// Lookup map for fast checking if a class exists by its type.
|
||||
val classesByType = mutableMapOf<String, ClassDef>().apply {
|
||||
classes.forEach { classDef -> put(classDef.type, classDef) }
|
||||
}
|
||||
|
||||
init {
|
||||
classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
val methodClassPair: MethodClassPair = method to classDef
|
||||
|
||||
// For fingerprints with no access or return type specified.
|
||||
allMethods += methodClassPair
|
||||
|
||||
val accessFlagsReturnKey = method.accessFlags.toString() + method.returnType.first()
|
||||
|
||||
// Add <access><returnType> as the key.
|
||||
methodsBySignature[accessFlagsReturnKey] = methodClassPair
|
||||
|
||||
// Add <access><returnType>[parameters] as the key.
|
||||
methodsBySignature[
|
||||
buildString {
|
||||
append(accessFlagsReturnKey)
|
||||
appendParameters(method.parameterTypes)
|
||||
},
|
||||
] = methodClassPair
|
||||
|
||||
// Add strings contained in the method as the key.
|
||||
method.instructionsOrNull?.forEach instructions@{ instruction ->
|
||||
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO) {
|
||||
@@ -249,11 +250,15 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
allMethods.clear()
|
||||
methodsBySignature.clear()
|
||||
methodsByStrings.clear()
|
||||
classesByType.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
lookupMaps.close()
|
||||
classes.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -32,14 +32,19 @@ class ResourcePatchContext internal constructor(
|
||||
private val logger = Logger.getLogger(ResourcePatchContext::class.java.name)
|
||||
|
||||
/**
|
||||
* Read and write documents in the [PatcherConfig.apkFiles].
|
||||
* Read a document from an [InputStream].
|
||||
*/
|
||||
val document = DocumentOperatable()
|
||||
fun document(inputStream: InputStream) = Document(inputStream)
|
||||
|
||||
/**
|
||||
* Predicate to delete resources from [PatcherConfig.apkFiles].
|
||||
* Read and write documents in the [PatcherConfig.apkFiles].
|
||||
*/
|
||||
private val deleteResources = mutableSetOf<(String) -> Boolean>()
|
||||
fun document(path: String) = Document(get(path))
|
||||
|
||||
/**
|
||||
* Set of resources from [PatcherConfig.apkFiles] to delete.
|
||||
*/
|
||||
private val deleteResources = mutableSetOf<String>()
|
||||
|
||||
/**
|
||||
* Decode resources of [PatcherConfig.apkFile].
|
||||
@@ -201,11 +206,11 @@ class ResourcePatchContext internal constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Stage a file to be deleted from [PatcherConfig.apkFile].
|
||||
* Mark a file for deletion when the APK is rebuilt.
|
||||
*
|
||||
* @param shouldDelete The predicate to stage the file for deletion given its name.
|
||||
* @param name The name of the file to delete.
|
||||
*/
|
||||
fun stageDelete(shouldDelete: (String) -> Boolean) = deleteResources.add(shouldDelete)
|
||||
fun delete(name: String) = deleteResources.add(name)
|
||||
|
||||
/**
|
||||
* How to handle resources decoding and compiling.
|
||||
@@ -227,10 +232,4 @@ class ResourcePatchContext internal constructor(
|
||||
*/
|
||||
NONE,
|
||||
}
|
||||
|
||||
inner class DocumentOperatable {
|
||||
operator fun get(inputStream: InputStream) = Document(inputStream)
|
||||
|
||||
operator fun get(path: String) = Document(this@ResourcePatchContext[path])
|
||||
}
|
||||
}
|
||||
|
@@ -179,7 +179,9 @@ internal object ClassMerger {
|
||||
callback: MutableClass.() -> Unit,
|
||||
) {
|
||||
callback(targetClass)
|
||||
this.classByType(targetClass.superclass ?: return)?.mutableClass?.let {
|
||||
|
||||
targetClass.superclass ?: return
|
||||
this.classBy { targetClass.superclass == it.type }?.mutableClass?.let {
|
||||
traverseClassHierarchy(it, callback)
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A navigator for methods.
|
||||
@@ -27,7 +28,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
class MethodNavigator internal constructor(private val context: BytecodePatchContext, private var startMethod: MethodReference) {
|
||||
private var lastNavigatedMethodReference = startMethod
|
||||
|
||||
private val lastNavigatedMethodInstructions get() = with(immutable()) {
|
||||
private val lastNavigatedMethodInstructions get() = with(original()) {
|
||||
instructionsOrNull ?: throw NavigateException("Method $definingClass.$name does not have an implementation.")
|
||||
}
|
||||
|
||||
@@ -76,15 +77,22 @@ class MethodNavigator internal constructor(private val context: BytecodePatchCon
|
||||
*
|
||||
* @return The last navigated method mutably.
|
||||
*/
|
||||
fun mutable() = context.classBy(matchesCurrentMethodReferenceDefiningClass)!!.mutableClass.firstMethodBySignature
|
||||
fun stop() = context.classBy(matchesCurrentMethodReferenceDefiningClass)!!.mutableClass.firstMethodBySignature
|
||||
as MutableMethod
|
||||
|
||||
/**
|
||||
* Get the last navigated method mutably.
|
||||
*
|
||||
* @return The last navigated method mutably.
|
||||
*/
|
||||
operator fun getValue(nothing: Nothing?, property: KProperty<*>) = stop()
|
||||
|
||||
/**
|
||||
* Get the last navigated method immutably.
|
||||
*
|
||||
* @return The last navigated method immutably.
|
||||
*/
|
||||
fun immutable() = context.classes.first(matchesCurrentMethodReferenceDefiningClass).firstMethodBySignature
|
||||
fun original() = context.classes.first(matchesCurrentMethodReferenceDefiningClass).firstMethodBySignature
|
||||
|
||||
/**
|
||||
* Predicate to match the class defining the current method reference.
|
||||
|
@@ -9,21 +9,13 @@ class MutableAnnotation(annotation: Annotation) : BaseAnnotation() {
|
||||
private val type = annotation.type
|
||||
private val _elements by lazy { annotation.elements.map { element -> element.toMutable() }.toMutableSet() }
|
||||
|
||||
override fun getType(): String {
|
||||
return type
|
||||
}
|
||||
override fun getType(): String = type
|
||||
|
||||
override fun getElements(): MutableSet<MutableAnnotationElement> {
|
||||
return _elements
|
||||
}
|
||||
override fun getElements(): MutableSet<MutableAnnotationElement> = _elements
|
||||
|
||||
override fun getVisibility(): Int {
|
||||
return visibility
|
||||
}
|
||||
override fun getVisibility(): Int = visibility
|
||||
|
||||
companion object {
|
||||
fun Annotation.toMutable(): MutableAnnotation {
|
||||
return MutableAnnotation(this)
|
||||
}
|
||||
fun Annotation.toMutable(): MutableAnnotation = MutableAnnotation(this)
|
||||
}
|
||||
}
|
||||
|
@@ -18,17 +18,11 @@ class MutableAnnotationElement(annotationElement: AnnotationElement) : BaseAnnot
|
||||
this.value = value
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return name
|
||||
}
|
||||
override fun getName(): String = name
|
||||
|
||||
override fun getValue(): EncodedValue {
|
||||
return value
|
||||
}
|
||||
override fun getValue(): EncodedValue = value
|
||||
|
||||
companion object {
|
||||
fun AnnotationElement.toMutable(): MutableAnnotationElement {
|
||||
return MutableAnnotationElement(this)
|
||||
}
|
||||
fun AnnotationElement.toMutable(): MutableAnnotationElement = MutableAnnotationElement(this)
|
||||
}
|
||||
}
|
||||
|
@@ -7,9 +7,10 @@ import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.util.FieldUtil
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import com.google.common.collect.Iterables
|
||||
|
||||
class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() {
|
||||
class MutableClass(classDef: ClassDef) :
|
||||
BaseTypeReference(),
|
||||
ClassDef {
|
||||
// Class
|
||||
private var type = classDef.type
|
||||
private var sourceFile = classDef.sourceFile
|
||||
@@ -23,13 +24,13 @@ class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() {
|
||||
|
||||
// Methods
|
||||
private val _methods by lazy { classDef.methods.map { method -> method.toMutable() }.toMutableSet() }
|
||||
private val _directMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_DIRECT).toMutableSet() }
|
||||
private val _virtualMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_VIRTUAL).toMutableSet() }
|
||||
private val _directMethods by lazy { _methods.filter { method -> MethodUtil.isDirect(method) }.toMutableSet() }
|
||||
private val _virtualMethods by lazy { _methods.filter { method -> !MethodUtil.isDirect(method) }.toMutableSet() }
|
||||
|
||||
// Fields
|
||||
private val _fields by lazy { classDef.fields.map { field -> field.toMutable() }.toMutableSet() }
|
||||
private val _staticFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_STATIC).toMutableSet() }
|
||||
private val _instanceFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_INSTANCE).toMutableSet() }
|
||||
private val _staticFields by lazy { _fields.filter { field -> FieldUtil.isStatic(field) }.toMutableSet() }
|
||||
private val _instanceFields by lazy { _fields.filter { field -> !FieldUtil.isStatic(field) }.toMutableSet() }
|
||||
|
||||
fun setType(type: String) {
|
||||
this.type = type
|
||||
@@ -47,57 +48,31 @@ class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() {
|
||||
this.superclass = superclass
|
||||
}
|
||||
|
||||
override fun getType(): String {
|
||||
return type
|
||||
}
|
||||
override fun getType(): String = type
|
||||
|
||||
override fun getAccessFlags(): Int {
|
||||
return accessFlags
|
||||
}
|
||||
override fun getAccessFlags(): Int = accessFlags
|
||||
|
||||
override fun getSourceFile(): String? {
|
||||
return sourceFile
|
||||
}
|
||||
override fun getSourceFile(): String? = sourceFile
|
||||
|
||||
override fun getSuperclass(): String? {
|
||||
return superclass
|
||||
}
|
||||
override fun getSuperclass(): String? = superclass
|
||||
|
||||
override fun getInterfaces(): MutableList<String> {
|
||||
return _interfaces
|
||||
}
|
||||
override fun getInterfaces(): MutableList<String> = _interfaces
|
||||
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||
return _annotations
|
||||
}
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> = _annotations
|
||||
|
||||
override fun getStaticFields(): MutableSet<MutableField> {
|
||||
return _staticFields
|
||||
}
|
||||
override fun getStaticFields(): MutableSet<MutableField> = _staticFields
|
||||
|
||||
override fun getInstanceFields(): MutableSet<MutableField> {
|
||||
return _instanceFields
|
||||
}
|
||||
override fun getInstanceFields(): MutableSet<MutableField> = _instanceFields
|
||||
|
||||
override fun getFields(): MutableSet<MutableField> {
|
||||
return _fields
|
||||
}
|
||||
override fun getFields(): MutableSet<MutableField> = _fields
|
||||
|
||||
override fun getDirectMethods(): MutableSet<MutableMethod> {
|
||||
return _directMethods
|
||||
}
|
||||
override fun getDirectMethods(): MutableSet<MutableMethod> = _directMethods
|
||||
|
||||
override fun getVirtualMethods(): MutableSet<MutableMethod> {
|
||||
return _virtualMethods
|
||||
}
|
||||
override fun getVirtualMethods(): MutableSet<MutableMethod> = _virtualMethods
|
||||
|
||||
override fun getMethods(): MutableSet<MutableMethod> {
|
||||
return _methods
|
||||
}
|
||||
override fun getMethods(): MutableSet<MutableMethod> = _methods
|
||||
|
||||
companion object {
|
||||
fun ClassDef.toMutable(): MutableClass {
|
||||
return MutableClass(this)
|
||||
}
|
||||
fun ClassDef.toMutable(): MutableClass = MutableClass(this)
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user