1
mirror of https://github.com/revanced/revanced-patcher synced 2025-09-06 16:38:50 +02:00

Compare commits

...

90 Commits

Author SHA1 Message Date
semantic-release-bot
30f0ea29a3 chore(release): 15.0.0-dev.3 [skip ci]
# [15.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v15.0.0-dev.2...v15.0.0-dev.3) (2023-09-06)

### Bug Fixes

* Make `CompatiblePackage.versions` a property ([67b7dff](67b7dff67a))
* Use correct module name ([080fbe9](080fbe9feb))

* feat Use `Set` as super type for `PatchBundleLoader` ([4b76d19](4b76d19596))

### BREAKING CHANGES

* `PatchBundleLoader` is not a map anymore
* This renames packages and the Maven package.
2023-09-06 12:32:05 +00:00
oSumAtrIX
49930f6565 chore: Use correct resource names for tests 2023-09-06 14:27:51 +02:00
oSumAtrIX
909d89fa8d chore: Print correct error message 2023-09-06 14:23:26 +02:00
oSumAtrIX
81d1d7f544 refactor: Do not reify generic type 2023-09-06 06:34:38 +02:00
oSumAtrIX
67b7dff67a fix: Make CompatiblePackage.versions a property 2023-09-06 06:12:44 +02:00
oSumAtrIX
4b76d19596 feat Use Set as super type for PatchBundleLoader
BREAKING CHANGE: `PatchBundleLoader` is not a map anymore
2023-09-06 06:12:22 +02:00
oSumAtrIX
080fbe9feb fix: Use correct module name
BREAKING CHANGE: This renames packages and the Maven package.
2023-09-06 06:11:15 +02:00
semantic-release-bot
d3721229bf chore(release): 15.0.0-dev.2 [skip ci]
# [15.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v15.0.0-dev.1...v15.0.0-dev.2) (2023-09-06)
2023-09-06 03:36:03 +00:00
oSumAtrIX
86c1c9c772 build(Needs bump): Use correct Maven repository URL 2023-09-06 05:32:58 +02:00
oSumAtrIX
c299817193 feat!: Use Kotlin DSL for patch options (#234) 2023-09-06 02:53:31 +02:00
semantic-release-bot
fcc1de45ed chore(release): 15.0.0-dev.1 [skip ci]
# [15.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.2.2...v15.0.0-dev.1) (2023-09-04)

* feat!: Add patch annotation processor ([3fc6a13](3fc6a139ee))
* feat!: Remove patch annotations ([3b4db3d](3b4db3ddb7))

### Features

* Add patch annotation processor ([#231](https://github.com/ReVanced/revanced-patcher/issues/231)) ([a29931f](a29931f2ec))

### BREAKING CHANGES

* The manifest for patches has been removed, and the properties have been added to patches. Patches are now `OptionsContainer`. The `@Patch` annotation has been removed in favour of the `@Patch` annotation from the annotation processor.
* Patch annotations have been removed. PatcherException is now thrown in various places. PatchBundleLoader is now a map of patches associated by their name. Patches are now instances.
2023-09-04 03:51:04 +00:00
oSumAtrIX
a29931f2ec feat: Add patch annotation processor (#231) 2023-09-04 05:48:20 +02:00
oSumAtrIX
3fc6a139ee feat!: Add patch annotation processor
This commit introduces an annotation processor for patches. Patches can use the `@Patch` instead of super constructor parameters.

BREAKING CHANGE: The manifest for patches has been removed, and the properties have been added to patches. Patches are now `OptionsContainer`. The `@Patch` annotation has been removed in favour of the `@Patch` annotation from the annotation processor.
2023-09-04 05:43:41 +02:00
oSumAtrIX
4dd04975d9 refactor: Move ReVanced Patcher to sub-project
This allows other sub-projects to exist.
2023-09-04 05:37:13 +02:00
oSumAtrIX
3b4db3ddb7 feat!: Remove patch annotations
Annotations required reflection and working with them turned out to be rather cumbersome. The annotations have been replaced with properties for the most part.

BREAKING CHANGE: Patch annotations have been removed. PatcherException is now thrown in various places. PatchBundleLoader is now a map of patches associated by their name. Patches are now instances.
2023-09-04 05:24:29 +02:00
semantic-release-bot
c4a7117ee8 chore(release): 14.2.2 [skip ci]
## [14.2.2](https://github.com/ReVanced/revanced-patcher/compare/v14.2.1...v14.2.2) (2023-08-30)

### Bug Fixes

* allow setting `DexClassLoader.optimizedDirectory` ([11a3378](11a3378659))
2023-08-30 17:25:12 +00:00
oSumAtrIX
b4e900fde8 chore: merge branch dev to main (#226) 2023-08-30 19:22:46 +02:00
semantic-release-bot
9818d730e4 chore(release): 14.2.2-dev.1 [skip ci]
## [14.2.2-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.2.1...v14.2.2-dev.1) (2023-08-29)

### Bug Fixes

* allow setting `DexClassLoader.optimizedDirectory` ([11a3378](11a3378659))
2023-08-29 02:12:54 +00:00
oSumAtrIX
11a3378659 fix: allow setting DexClassLoader.optimizedDirectory
This is required for API level below 26, otherwise an NPE is thrown
2023-08-29 04:09:17 +02:00
oSumAtrIX
1bb05f22d3 chore: add initial API dump
This is necessary for the binary compatibility validation.
2023-08-29 04:05:18 +02:00
oSumAtrIX
26b70554c4 build: use binary compatibility validator
This prevents releasing breaking changes accidentally.
2023-08-29 03:47:21 +02:00
oSumAtrIX
93b29d2e83 chore: assert instead of printing in tests 2023-08-29 03:38:11 +02:00
semantic-release-bot
072986374a chore(release): 14.2.1 [skip ci]
## [14.2.1](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0...v14.2.1) (2023-08-27)

### Bug Fixes

* do not flag resource table as sparse when main package is not loaded ([b832812](b832812767))
2023-08-27 20:23:09 +00:00
oSumAtrIX
2c590d212a chore: merge branch dev to main (#225) 2023-08-27 22:21:36 +02:00
semantic-release-bot
6cc863efb3 chore(release): 14.2.1-dev.1 [skip ci]
## [14.2.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0...v14.2.1-dev.1) (2023-08-27)

### Bug Fixes

* do not flag resource table as sparse when main package is not loaded ([b832812](b832812767))
2023-08-27 20:17:31 +00:00
oSumAtrIX
b832812767 fix: do not flag resource table as sparse when main package is not loaded 2023-08-27 22:14:43 +02:00
oSumAtrIX
c44558cacd build: bump dependencies
This fixes an issue with flagging the resource table with sparse incorrectly.
2023-08-27 22:14:11 +02:00
semantic-release-bot
6d83a720cd chore(release): 14.2.0 [skip ci]
# [14.2.0](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0) (2023-08-27)

### Features

* load patches in lexicographical order ([e8f2087](e8f2087a6f))
* log when merging integrations ([983563e](983563efb6))

### Performance Improvements

* compare types of classes ([55d6945](55d694579a))
2023-08-27 00:55:36 +00:00
oSumAtrIX
8d0dd9c448 chore: merge branch dev to main (#222) 2023-08-27 02:53:47 +02:00
oSumAtrIX
64020eec49 chore: add multi-threading opportunity notice 2023-08-26 20:58:19 +02:00
semantic-release-bot
4dedfb85cb chore(release): 14.2.0-dev.3 [skip ci]
# [14.2.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.2...v14.2.0-dev.3) (2023-08-26)

### Performance Improvements

* compare types of classes ([55d6945](55d694579a))
2023-08-26 17:44:12 +00:00
oSumAtrIX
55d694579a perf: compare types of classes 2023-08-26 19:42:33 +02:00
semantic-release-bot
86db64edff chore(release): 14.2.0-dev.2 [skip ci]
# [14.2.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.1...v14.2.0-dev.2) (2023-08-26)

### Features

* log when merging integrations ([983563e](983563efb6))
2023-08-26 17:16:08 +00:00
oSumAtrIX
983563efb6 feat: log when merging integrations 2023-08-26 19:14:29 +02:00
oSumAtrIX
37abb2db99 build: package the Java sources 2023-08-26 19:10:29 +02:00
semantic-release-bot
5ba0b47e60 chore(release): 14.2.0-dev.1 [skip ci]
# [14.2.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0-dev.1) (2023-08-25)

### Features

* load patches in lexicographical order ([e8f2087](e8f2087a6f))
2023-08-25 15:12:46 +00:00
oSumAtrIX
e8f2087a6f feat: load patches in lexicographical order
This feature was lost in past commits
2023-08-25 17:10:44 +02:00
semantic-release-bot
6ce99f5cdf chore(release): 14.1.0 [skip ci]
# [14.1.0](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.1.0) (2023-08-24)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:50:15 +00:00
oSumAtrIX
13c0c9cdd3 chore: merge branch dev to main (#220) 2023-08-24 04:48:39 +02:00
semantic-release-bot
58ffdb60d7 chore(release): 14.1.0-dev.1 [skip ci]
# [14.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.1-dev.1...v14.1.0-dev.1) (2023-08-24)

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:45:16 +00:00
oSumAtrIX
ba56a6a2ee feat: properly make use of logging facade
This deprecates the primary constructor of `PatcherOptions` with the `logger` parameter
2023-08-24 04:43:16 +02:00
oSumAtrIX
ccccf5b1d2 build: migrate dependencies to version catalogs 2023-08-23 04:30:31 +02:00
semantic-release-bot
b507ac0a54 chore(release): 14.0.1-dev.1 [skip ci]
## [14.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.0.1-dev.1) (2023-08-23)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))
2023-08-23 01:39:26 +00:00
oSumAtrIX
e985676c2d fix: move version properties file to correct package 2023-08-23 03:36:48 +02:00
oSumAtrIX
f7f4ba6c55 build: update dependencies 2023-08-23 03:36:48 +02:00
semantic-release-bot
4292f43814 chore(release): 14.0.0 [skip ci]
# [14.0.0](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0) (2023-08-22)

### Bug Fixes

* log decoding resources after logging deleting resource cache directory ([db62a16](db62a1607b))
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
* supply the parent classloader to `DexClassLoader` ([0f15077](0f15077225))

### Code Refactoring

* improve structure and public API ([6b8977f](6b8977f178))

### Features

* do not log instantiation of ReVanced Patcher ([273dd8d](273dd8d388))

### BREAKING CHANGES

* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-22 17:16:51 +00:00
oSumAtrIX
30bd4fd9fe chore: merge branch dev to main (#217) 2023-08-22 19:15:09 +02:00
semantic-release-bot
76de39369d chore(release): 14.0.0-dev.4 [skip ci]
# [14.0.0-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.3...v14.0.0-dev.4) (2023-08-22)

### Bug Fixes

* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
2023-08-22 17:04:25 +00:00
oSumAtrIX
88a703ce36 build: bump dependencies 2023-08-22 19:01:59 +02:00
oSumAtrIX
5938f6b7ea fix: only emit closed patches that did not throw an exception with the @Patch annotation 2023-08-22 19:00:34 +02:00
semantic-release-bot
5c0c0d6c37 chore(release): 14.0.0-dev.3 [skip ci]
# [14.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.2...v14.0.0-dev.3) (2023-08-20)

### Bug Fixes

* supply the parent classloader to `DexClassLoader` ([0f15077](0f15077225))

### Features

* do not log instantiation of ReVanced Patcher ([273dd8d](273dd8d388))
2023-08-20 17:16:00 +00:00
oSumAtrIX
0f15077225 fix: supply the parent classloader to DexClassLoader 2023-08-20 19:14:10 +02:00
oSumAtrIX
273dd8d388 feat: do not log instantiation of ReVanced Patcher 2023-08-20 19:14:09 +02:00
semantic-release-bot
1795f376ef chore(release): 14.0.0-dev.2 [skip ci]
# [14.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.1...v14.0.0-dev.2) (2023-08-19)
2023-08-19 15:26:18 +00:00
oSumAtrIX
e7360a7692 build(Needs bump): Bump dependencies
This fixes an issue with a library not working on Android
2023-08-19 17:23:31 +02:00
semantic-release-bot
e1fc86934f chore(release): 14.0.0-dev.1 [skip ci]
# [14.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0-dev.1) (2023-08-18)

### Bug Fixes

* log decoding resources after logging deleting resource cache directory ([db62a16](db62a1607b))

### Code Refactoring

* improve structure and public API ([6b8977f](6b8977f178))

### BREAKING CHANGES

* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-18 23:47:18 +00:00
oSumAtrIX
6b8977f178 refactor: improve structure and public API
This commit introduces a couple changes besides the refactor. Executing patches can be cancelled, multiple bundles loaded into the same class loader and `Patch.execute` does not have to return anymore.

BREAKING CHANGE: Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-19 01:45:27 +02:00
oSumAtrIX
12c6c73de0 build: add mavenLocal to repositories 2023-08-16 16:53:47 +02:00
oSumAtrIX
db62a1607b fix: log decoding resources after logging deleting resource cache directory 2023-08-16 16:53:45 +02:00
semantic-release-bot
58bb879ef5 chore(release): 13.0.0 [skip ci]
# [13.0.0](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1...v13.0.0) (2023-08-14)

### Bug Fixes

* decode in correct order ([8fb2f2d](8fb2f2dc1d))
* disable correct loggers ([c2d89c6](c2d89c622e))
* get framework ids to compile resources ([f2cb7ee](f2cb7ee7df))
* only enable logging for ReVanced ([783ccf8](783ccf8529))
* set package metadata correctly ([02d6ff1](02d6ff15fe))

* build(Needs bump)!: Bump dependencies ([d5f89a9](d5f89a903f))

### BREAKING CHANGES

* This bump updates smali, a crucial dependency
2023-08-14 02:11:55 +00:00
oSumAtrIX
254912438a chore: merge branch dev to main (#213) 2023-08-14 04:10:17 +02:00
semantic-release-bot
0e48918bcc chore(release): 13.0.0-dev.3 [skip ci]
# [13.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0-dev.2...v13.0.0-dev.3) (2023-08-14)

### Bug Fixes

* decode in correct order ([8fb2f2d](8fb2f2dc1d))
* only enable logging for ReVanced ([783ccf8](783ccf8529))
2023-08-14 02:04:54 +00:00
oSumAtrIX
783ccf8529 fix: only enable logging for ReVanced 2023-08-14 04:02:39 +02:00
oSumAtrIX
8fb2f2dc1d fix: decode in correct order 2023-08-14 04:02:24 +02:00
semantic-release-bot
2a8cc283c7 chore(release): 13.0.0-dev.2 [skip ci]
# [13.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0-dev.1...v13.0.0-dev.2) (2023-08-12)

### Bug Fixes

* disable correct loggers ([c2d89c6](c2d89c622e))
* get framework ids to compile resources ([f2cb7ee](f2cb7ee7df))
* set package metadata correctly ([02d6ff1](02d6ff15fe))
2023-08-12 00:25:18 +00:00
oSumAtrIX
433fe3af9f build(Needs bump): Bump dependencies 2023-08-12 02:23:03 +02:00
oSumAtrIX
c2d89c622e fix: disable correct loggers 2023-08-12 02:22:52 +02:00
oSumAtrIX
02d6ff15fe fix: set package metadata correctly 2023-08-12 02:19:28 +02:00
oSumAtrIX
f2cb7ee7df fix: get framework ids to compile resources 2023-08-12 02:18:43 +02:00
oSumAtrIX
a2ac44dcc1 chore: use more generic inline docs 2023-08-12 02:15:26 +02:00
semantic-release-bot
3cf9d74efa chore(release): 13.0.0-dev.1 [skip ci]
# [13.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1...v13.0.0-dev.1) (2023-08-11)

* build(Needs bump)!: Bump dependencies ([d5f89a9](d5f89a903f))

### BREAKING CHANGES

* This bump updates smali, a crucial dependency
2023-08-11 00:53:46 +00:00
oSumAtrIX
d5f89a903f build(Needs bump)!: Bump dependencies
BREAKING CHANGE: This bump updates smali, a crucial dependency
2023-08-11 02:51:37 +02:00
semantic-release-bot
496c2242bc chore(release): 12.1.1 [skip ci]
## [12.1.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0...v12.1.1) (2023-08-03)

### Bug Fixes

* clear method lookup maps before initializing them ([#210](https://github.com/ReVanced/revanced-patcher/issues/210)) ([746544f](746544f9d5))
2023-08-03 18:34:22 +00:00
oSumAtrIX
98fbff87df chore: merge branch dev to main (#211) 2023-08-03 20:32:45 +02:00
semantic-release-bot
ddb51a1c45 chore(release): 12.1.1-dev.2 [skip ci]
## [12.1.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1-dev.1...v12.1.1-dev.2) (2023-08-03)
2023-08-03 18:16:10 +00:00
oSumAtrIX
8df1155215 build(Needs bump): Bump compatibility 2023-08-03 20:14:01 +02:00
semantic-release-bot
53f2a61409 chore(release): 12.1.1-dev.1 [skip ci]
## [12.1.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0...v12.1.1-dev.1) (2023-08-03)

### Bug Fixes

* clear method lookup maps before initializing them ([#210](https://github.com/ReVanced/revanced-patcher/issues/210)) ([746544f](746544f9d5))
2023-08-03 11:43:51 +00:00
aAbed
746544f9d5 fix: clear method lookup maps before initializing them (#210)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-08-03 13:42:00 +02:00
semantic-release-bot
c65c3df11c chore(release): 12.1.0 [skip ci]
# [12.1.0](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0...v12.1.0) (2023-08-03)

### Features

* add `MutableMethod.getInstructions` extension function ([fae4029](fae4029cfc))
2023-08-03 02:43:21 +00:00
oSumAtrIX
b29b8f12b3 chore: merge branch dev to main (#209) 2023-08-03 04:18:23 +02:00
semantic-release-bot
d6945677c4 chore(release): 12.1.0-dev.2 [skip ci]
# [12.1.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0-dev.1...v12.1.0-dev.2) (2023-08-03)
2023-08-03 02:16:55 +00:00
oSumAtrIX
aedf4aea08 build(Needs bump): Update dependencies 2023-08-03 04:15:09 +02:00
semantic-release-bot
dc28d414dc chore(release): 12.1.0-dev.1 [skip ci]
# [12.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0...v12.1.0-dev.1) (2023-08-01)

### Features

* add `MutableMethod.getInstructions` extension function ([fae4029](fae4029cfc))
2023-08-01 22:14:09 +00:00
oSumAtrIX
9755bab298 refactor: remove unnecessary annotation 2023-08-02 00:12:24 +02:00
oSumAtrIX
fae4029cfc feat: add MutableMethod.getInstructions extension function 2023-08-02 00:11:56 +02:00
oSumAtrIX
1790f0d706 ci: Change bumping commit scope 2023-07-30 02:50:41 +02:00
semantic-release-bot
0ba2c51676 chore(release): 12.0.0 [skip ci]
# [12.0.0](https://github.com/ReVanced/revanced-patcher/compare/v11.0.4...v12.0.0) (2023-07-30)

### Bug Fixes

* correct access flags of `PackageMetadata` ([416d691](416d69142f))
* set resource table via resource decoder ([e0f8e1b](e0f8e1b71a))

### Features

* Deprecate `Version` annotation ([c9bbcf2](c9bbcf2bf2))
* remove `Path` option ([#202](https://github.com/ReVanced/revanced-patcher/issues/202)) ([69e4a49](69e4a49065))

### BREAKING CHANGES

* This removes the previously available `Path` option
2023-07-30 00:10:57 +00:00
oSumAtrIX
03cd97b49c chore: merge branch dev to main (#203) 2023-07-30 02:09:12 +02:00
semantic-release-bot
16a162c1dd chore(release): 12.0.0-dev.2 [skip ci]
# [12.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0-dev.1...v12.0.0-dev.2) (2023-07-28)

### Features

* Deprecate `Version` annotation ([400442f](400442f70e))
2023-07-28 20:19:02 +02:00
oSumAtrIX
c9bbcf2bf2 feat: Deprecate Version annotation 2023-07-28 20:19:01 +02:00
126 changed files with 4000 additions and 1839 deletions

View File

@@ -36,7 +36,7 @@ jobs:
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew clean --no-daemon
run: ./gradlew build clean --no-daemon
- name: Setup semantic-release
run: npm install
- name: Release

View File

@@ -10,7 +10,7 @@
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "needs-bump", "release": "patch" }
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +1,10 @@
plugins {
kotlin("jvm") version "1.8.20"
`maven-publish`
kotlin("jvm") version "1.9.0" apply false
alias(libs.plugins.binary.compatibility.validator)
}
group = "app.revanced"
allprojects {
apply(plugin = "maven-publish")
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
repositories {
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/revanced/multidexlib2")
credentials {
username = githubUsername
password = githubPassword
}
}
}
dependencies {
implementation("xpp3:xpp3:1.1.4c")
implementation("app.revanced:smali:2.5.3-a3836654")
implementation("app.revanced:multidexlib2:2.5.3-a3836654")
implementation("app.revanced:apktool-lib:2.8.2")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20-RC")
testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20-RC")
}
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
processResources {
expand("projectVersion" to project.version)
}
}
java {
withSourcesJar()
}
kotlin {
jvmToolchain(11)
}
publishing {
repositories {
if (System.getenv("GITHUB_ACTOR") != null)
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
else
mavenLocal()
}
publications {
register<MavenPublication>("gpr") {
from(components["java"])
}
}
}
group = "app.revanced"
}

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 12.0.0-dev.1
version = 15.0.0-dev.3

31
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,31 @@
[versions]
android = "4.1.1.4"
kotlin-reflect = "1.9.0"
apktool-lib = "2.8.2-6"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.1"
multidexlib2 = "3.0.3.r2"
smali = "3.0.3"
symbol-processing-api = "1.9.0-1.0.11"
xpp3 = "1.1.4c"
binary-compatibility-validator = "0.13.2"
kotlin-compile-testing-ksp = "1.5.0"
kotlinpoet-ksp = "1.14.2"
ksp = "1.9.0-1.0.11"
[libraries]
android = { module = "com.google.android:android", version.ref = "android" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
symbol-processing-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "symbol-processing-api" }
xpp3 = { module = "xpp3:xpp3", version.ref = "xpp3" }
kotlin-compile-testing = { module = "com.github.tschuchortdev:kotlin-compile-testing-ksp", version.ref = "kotlin-compile-testing-ksp" }
kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoet-ksp" }
[plugins]
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

View File

@@ -0,0 +1,25 @@
public abstract interface annotation class app/revanced/patcher/patch/annotation/CompatiblePackage : java/lang/annotation/Annotation {
public abstract fun name ()Ljava/lang/String;
public abstract fun versions ()[Ljava/lang/String;
}
public abstract interface annotation class app/revanced/patcher/patch/annotation/Patch : java/lang/annotation/Annotation {
public abstract fun compatiblePackages ()[Lapp/revanced/patcher/patch/annotation/CompatiblePackage;
public abstract fun dependencies ()[Ljava/lang/Class;
public abstract fun description ()Ljava/lang/String;
public abstract fun name ()Ljava/lang/String;
public abstract fun requiresIntegrations ()Z
public abstract fun use ()Z
}
public final class app/revanced/patcher/patch/annotation/processor/PatchProcessor : com/google/devtools/ksp/processing/SymbolProcessor {
public fun <init> (Lcom/google/devtools/ksp/processing/CodeGenerator;Lcom/google/devtools/ksp/processing/KSPLogger;)V
public fun process (Lcom/google/devtools/ksp/processing/Resolver;)Ljava/util/List;
}
public final class app/revanced/patcher/patch/annotation/processor/PatchProcessorProvider : com/google/devtools/ksp/processing/SymbolProcessorProvider {
public fun <init> ()V
public fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lapp/revanced/patcher/patch/annotation/processor/PatchProcessor;
public synthetic fun create (Lcom/google/devtools/ksp/processing/SymbolProcessorEnvironment;)Lcom/google/devtools/ksp/processing/SymbolProcessor;
}

View File

@@ -0,0 +1,74 @@
plugins {
kotlin("jvm") version "1.9.0"
alias(libs.plugins.ksp)
}
dependencies {
implementation(libs.symbol.processing.api)
implementation(libs.kotlinpoet.ksp)
implementation(project(":revanced-patcher"))
testImplementation(libs.kotlin.test)
testImplementation(libs.kotlin.compile.testing)
}
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
}
kotlin { jvmToolchain(11) }
java {
withSourcesJar()
}
publishing {
repositories {
mavenLocal()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
publications {
create<MavenPublication>("gpr") {
from(components["java"])
version = project.version.toString()
pom {
name = "ReVanced patch annotation processor"
description = "Annotation processor for patches."
url = "https://revanced.app"
licenses {
license {
name = "GNU General Public License v3.0"
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
}
}
developers {
developer {
id = "ReVanced"
name = "ReVanced"
email = "contact@revanced.app"
}
}
scm {
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
url = "https://github.com/revanced/revanced-patcher"
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
rootProject.name = "revanced-patch-annotation-processor"

View File

@@ -0,0 +1,38 @@
package app.revanced.patcher.patch.annotation
import java.lang.annotation.Inherited
import kotlin.reflect.KClass
/**
* Annotation for [app.revanced.patcher.patch.Patch] classes.
*
* @param name The name of the patch. If empty, the patch will be unnamed.
* @param description The description of the patch. If empty, no description will be used.
* @param dependencies The patches this patch depends on.
* @param compatiblePackages The packages this patch is compatible with.
* @param use Whether this patch should be used.
* @param requiresIntegrations Whether this patch requires integrations.
*/
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS)
@Inherited
annotation class Patch(
val name: String = "",
val description: String = "",
val dependencies: Array<KClass<out app.revanced.patcher.patch.Patch<*>>> = [],
val compatiblePackages: Array<CompatiblePackage> = [],
val use: Boolean = true,
// TODO: Remove this property, once integrations are coupled with patches.
val requiresIntegrations: Boolean = false,
)
/**
* A package that a [app.revanced.patcher.patch.Patch] is compatible with.
*
* @param name The name of the package.
* @param versions The versions of the package.
*/
annotation class CompatiblePackage(
val name: String,
val versions: Array<String> = [],
)

View File

@@ -0,0 +1,205 @@
package app.revanced.patcher.patch.annotation.processor
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.google.devtools.ksp.validate
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.writeTo
import kotlin.reflect.KClass
class PatchProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
) : SymbolProcessor {
private fun KSAnnotated.isSubclassOf(cls: KClass<*>): Boolean {
if (this !is KSClassDeclaration) return false
if (qualifiedName?.asString() == cls.qualifiedName) return true
return superTypes.any { it.resolve().declaration.isSubclassOf(cls) }
}
@Suppress("UNCHECKED_CAST")
override fun process(resolver: Resolver): List<KSAnnotated> {
val executablePatches = buildMap {
resolver.getSymbolsWithAnnotation(Patch::class.qualifiedName!!).filter {
// Do not check here if Patch is super of the class, because it is expensive.
// Check it later when processing.
it.validate() && it.isSubclassOf(app.revanced.patcher.patch.Patch::class)
}.map {
it as KSClassDeclaration
}.forEach { patchDeclaration ->
patchDeclaration.annotations.find {
it.annotationType.resolve().declaration.qualifiedName!!.asString() == Patch::class.qualifiedName!!
}?.let { annotation ->
fun KSAnnotation.property(name: String) =
arguments.find { it.name!!.asString() == name }?.value!!
val name =
annotation.property("name").toString().ifEmpty { null }
val description =
annotation.property("description").toString().ifEmpty { null }
val dependencies =
(annotation.property("dependencies") as List<KSType>).ifEmpty { null }
val compatiblePackages =
(annotation.property("compatiblePackages") as List<KSAnnotation>).ifEmpty { null }
val use =
annotation.property("use") as Boolean
val requiresIntegrations =
annotation.property("requiresIntegrations") as Boolean
// Data class for KotlinPoet
data class PatchData(
val name: String?,
val description: String?,
val dependencies: List<ClassName>?,
val compatiblePackages: List<CodeBlock>?,
val use: Boolean,
val requiresIntegrations: Boolean
)
this[patchDeclaration] = PatchData(
name,
description,
dependencies?.map { dependency -> dependency.toClassName() },
compatiblePackages?.map {
val packageName = it.property("name")
val packageVersions = (it.property("versions") as List<String>)
.joinToString(", ") { version -> "\"$version\"" }
CodeBlock.of(
"%T(%S, setOf(%L))",
app.revanced.patcher.patch.Patch.CompatiblePackage::class,
packageName,
packageVersions
)
},
use,
requiresIntegrations
)
}
}
}
// If a patch depends on another, that is annotated, the dependency should be replaced with the generated patch,
// because the generated patch has all the necessary properties to invoke the super constructor,
// unlike the annotated patch.
val dependencyResolutionMap = buildMap {
executablePatches.values.filter { it.dependencies != null }.flatMap {
it.dependencies!!
}.distinct().forEach { dependency ->
executablePatches.keys.find { it.qualifiedName?.asString() == dependency.toString() }
?.let { patch ->
this[dependency] = ClassName(
patch.packageName.asString(),
patch.simpleName.asString() + "Generated"
)
}
}
}
executablePatches.forEach { (patchDeclaration, patchAnnotation) ->
val isBytecodePatch = patchDeclaration.isSubclassOf(BytecodePatch::class)
val superClass = if (isBytecodePatch) {
BytecodePatch::class
} else {
ResourcePatch::class
}
val contextClass = if (isBytecodePatch) {
BytecodeContext::class
} else {
ResourceContext::class
}
val generatedPatchClassName = ClassName(
patchDeclaration.packageName.asString(),
patchDeclaration.simpleName.asString() + "Generated"
)
FileSpec.builder(generatedPatchClassName)
.addType(
TypeSpec.objectBuilder(generatedPatchClassName)
.superclass(superClass).apply {
patchAnnotation.name?.let { name ->
addSuperclassConstructorParameter("name = %S", name)
}
patchAnnotation.description?.let { description ->
addSuperclassConstructorParameter("description = %S", description)
}
patchAnnotation.compatiblePackages?.let { compatiblePackages ->
addSuperclassConstructorParameter(
"compatiblePackages = setOf(%L)",
compatiblePackages.joinToString(", ")
)
}
patchAnnotation.dependencies?.let { dependencies ->
addSuperclassConstructorParameter(
"dependencies = setOf(%L)",
buildList {
addAll(dependencies)
// Also add the source class of the generated class so that it is also executed.
add(patchDeclaration.toClassName())
}.joinToString(", ") { dependency ->
"${(dependencyResolutionMap[dependency] ?: dependency)}::class"
}
)
}
addSuperclassConstructorParameter(
"use = %L", patchAnnotation.use
)
addSuperclassConstructorParameter(
"requiresIntegrations = %L",
patchAnnotation.requiresIntegrations
)
}
.addFunction(
FunSpec.builder("execute")
.addModifiers(KModifier.OVERRIDE)
.addParameter("context", contextClass)
.build()
)
.addInitializerBlock(
CodeBlock.builder()
.add(
"%T.options.forEach { (key, option) ->",
patchDeclaration.toClassName()
)
.addStatement(
"options.register(option)"
)
.add(
"}"
)
.build()
)
.build()
).build().writeTo(
codeGenerator,
Dependencies(false, patchDeclaration.containingFile!!)
)
}
return emptyList()
}
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.patch.annotation.processor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
class PatchProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment) =
PatchProcessor(environment.codeGenerator, environment.logger)
}

View File

@@ -0,0 +1 @@
app.revanced.patcher.patch.annotation.processor.PatchProcessorProvider

View File

@@ -0,0 +1,135 @@
package app.revanced.patcher.patch.annotation.processor
import app.revanced.patcher.patch.Patch
import com.tschuchort.compiletesting.KotlinCompilation
import com.tschuchort.compiletesting.SourceFile
import com.tschuchort.compiletesting.kspWithCompilation
import com.tschuchort.compiletesting.symbolProcessorProviders
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
class TestPatchAnnotationProcessor {
// region Processing
@Test
fun testProcessing() = assertEquals(
"Processable patch", compile(
getSourceFile(
"processing", "ProcessablePatch"
)
).loadPatch("$SAMPLE_PACKAGE.processing.ProcessablePatchGenerated").name
)
// endregion
// region Dependencies
@Test
fun testDependencies() {
compile(
getSourceFile(
"dependencies", "DependentPatch"
), getSourceFile(
"dependencies", "DependencyPatch"
)
).let { result ->
result.loadPatch("$SAMPLE_PACKAGE.dependencies.DependentPatchGenerated").let {
// Dependency as well as the source class of the generated class.
assertEquals(
2,
it.dependencies!!.size
)
// The last dependency is always the source class of the generated class to respect
// order of dependencies.
assertEquals(
result.loadPatch("$SAMPLE_PACKAGE.dependencies.DependentPatch")::class,
it.dependencies!!.last()
)
}
}
}
// endregion
// region Options
@Test
fun testOptions() {
val patch = compile(
getSourceFile(
"options", "OptionsPatch"
)
).loadPatch("$SAMPLE_PACKAGE.options.OptionsPatchGenerated")
assert(patch.options.isNotEmpty())
assertEquals(patch.options["print"].title, "Print message")
}
// endregion
// region Limitations
@Test
fun failingManualDependency() = assertNull(
compile(
getSourceFile(
"limitations/manualdependency", "DependentPatch"
), getSourceFile(
"limitations/manualdependency", "DependencyPatch"
)
).loadPatch("$SAMPLE_PACKAGE.limitations.manualdependency.DependentPatchGenerated").dependencies
)
// endregion
private companion object Utils {
const val SAMPLE_PACKAGE = "app.revanced.patcher.patch.annotation.processor.samples"
/**
* Get a source file from the given sample and class name.
*
* @param sample The sample to get the source file from.
* @param className The name of the class to get the source file from.
* @return The source file.
*/
fun getSourceFile(sample: String, className: String): SourceFile {
val resourceName = "app/revanced/patcher/patch/annotation/processor/samples/$sample/$className.kt"
return SourceFile.kotlin(
"$className.kt",
TestPatchAnnotationProcessor::class.java.classLoader.getResourceAsStream(resourceName)
?.readAllBytes()
?.toString(Charsets.UTF_8)
?: error("Could not find resource $resourceName")
)
}
/**
* Compile the given source files and return the result.
*
* @param sourceFiles The source files to compile.
* @return The result of the compilation.
*/
fun compile(vararg sourceFiles: SourceFile) = KotlinCompilation().apply {
sources = sourceFiles.asList()
symbolProcessorProviders = listOf(PatchProcessorProvider())
// Required until https://github.com/tschuchortdev/kotlin-compile-testing/issues/312 closed.
kspWithCompilation = true
inheritClassPath = true
messageOutputStream = System.out
}.compile().also { result ->
assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode)
}
// region Class loading
fun KotlinCompilation.Result.loadPatch(name: String) = classLoader.loadClass(name).loadPatch()
fun Class<*>.loadPatch() = this.getField("INSTANCE").get(null) as Patch<*>
// endregion
}
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patcher.patch.annotation.processor.samples.dependencies
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
@Patch(name = "Dependency patch")
object DependencyPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {}
}

View File

@@ -0,0 +1,12 @@
package app.revanced.patcher.patch.annotation.processor.samples.dependencies
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
@Patch(
name = "Dependent patch",
dependencies = [DependencyPatch::class],
)
object DependentPatch : BytecodePatch() {
override fun execute(context: BytecodeContext) {}
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patcher.patch.annotation.processor.samples.limitations.manualdependency
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
@Patch(name = "Dependency patch")
object DependencyPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { }
}

View File

@@ -0,0 +1,17 @@
package app.revanced.patcher.patch.annotation.processor.samples.limitations.manualdependency
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
@Patch(name = "Dependent patch")
object DependentPatch : BytecodePatch(
// Dependency will not be executed correctly if it is manually specified.
// The reason for this is that the dependency patch is annotated too,
// so the processor will generate a new patch class for it embedding the annotated information.
// Because the dependency is manually specified,
// the processor will not be able to change this dependency to the generated class,
// which means that the dependency will lose the annotated information.
dependencies = setOf(DependencyPatch::class)
) {
override fun execute(context: BytecodeContext) {}
}

View File

@@ -0,0 +1,19 @@
package app.revanced.patcher.patch.annotation.processor.samples.options
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.patch.options.types.StringPatchOption.Companion.stringPatchOption
@Patch(name = "Options patch")
object OptionsPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {}
@Suppress("unused")
private val printOption by stringPatchOption(
"print",
null,
"Print message",
"The message to print."
)
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patcher.patch.annotation.processor.samples.processing
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
@Patch("Processable patch")
object ProcessablePatch : BytecodePatch() {
override fun execute(context: BytecodeContext) {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
plugins {
kotlin("jvm") version "1.9.0"
}
dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.xpp3)
implementation(libs.smali)
implementation(libs.multidexlib2)
implementation(libs.apktool.lib)
implementation(libs.kotlin.reflect)
compileOnly(libs.android)
testImplementation(project(":revanced-patch-annotation-processor"))
testImplementation(libs.kotlin.test)
}
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
processResources {
expand("projectVersion" to project.version)
}
}
kotlin { jvmToolchain(11) }
java {
withSourcesJar()
}
publishing {
repositories {
mavenLocal()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
publications {
create<MavenPublication>("gpr") {
from(components["java"])
version = project.version.toString()
pom {
name = "ReVanced Patcher"
description = "Patcher used by ReVanced."
url = "https://revanced.app"
licenses {
license {
name = "GNU General Public License v3.0"
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
}
}
developers {
developer {
id = "ReVanced"
name = "ReVanced"
email = "contact@revanced.app"
}
}
scm {
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
url = "https://github.com/revanced/revanced-patcher"
}
}
}
}
}

View File

@@ -0,0 +1 @@
rootProject.name = "revanced-patcher"

View File

@@ -0,0 +1,8 @@
package app.revanced.patcher
import java.io.File
@FunctionalInterface
interface IntegrationsConsumer {
fun acceptIntegrations(integrations: List<File>)
}

View File

@@ -1,15 +1,14 @@
package app.revanced.patcher.data
package app.revanced.patcher
import brut.androlib.apk.ApkInfo
/**
* Metadata about a package.
*/
class PackageMetadata {
class PackageMetadata internal constructor(internal val apkInfo: ApkInfo) {
lateinit var packageName: String
internal set
lateinit var packageVersion: String
internal set
internal lateinit var apkInfo: ApkInfo
}

View File

@@ -0,0 +1,122 @@
@file:Suppress("unused")
package app.revanced.patcher
import app.revanced.patcher.patch.Patch
import dalvik.system.DexClassLoader
import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.MultiDexIO
import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
import java.util.logging.Logger
import kotlin.reflect.KClass
/**
* A set of [Patch]es.
*/
typealias PatchSet = Set<Patch<*>>
/**
* A [Patch] class.
*/
typealias PatchClass = KClass<out Patch<*>>
/**
* A loader of [Patch]es from patch bundles.
* This will load all [Patch]es from the given patch bundles that have a name.
*
* @param getBinaryClassNames A function that returns the binary names of all classes in a patch bundle.
* @param classLoader The [ClassLoader] to use for loading the classes.
*/
sealed class PatchBundleLoader private constructor(
classLoader: ClassLoader,
patchBundles: Array<out File>,
getBinaryClassNames: (patchBundle: File) -> List<String>,
) : PatchSet by mutableSetOf() {
private val logger = Logger.getLogger(PatchBundleLoader::class.java.name)
init {
patchBundles.flatMap(getBinaryClassNames).asSequence().map {
classLoader.loadClass(it)
}.filter {
it.isInstance(Patch::class.java)
}.mapNotNull { patchClass ->
patchClass.getInstance(logger)
}.filter {
it.name != null
}.let { patches ->
@Suppress("UNCHECKED_CAST")
(this as MutableSet<Patch<*>>).addAll(patches)
}
}
internal companion object Utils {
/**
* Instantiates a [Patch]. If the class is a singleton, the INSTANCE field will be used.
*
* @param logger The [Logger] to use for logging.
* @return The instantiated [Patch] or `null` if the [Patch] could not be instantiated.
*/
internal fun Class<*>.getInstance(logger: Logger): Patch<*>? {
return try {
getField("INSTANCE").get(null)
} catch (exception: NoSuchFileException) {
logger.fine(
"Patch class '${name}' has no INSTANCE field, therefor not a singleton. " +
"Will try to instantiate it."
)
try {
getDeclaredConstructor().newInstance()
} catch (exception: Exception) {
logger.severe(
"Patch class '${name}' is not singleton and has no suitable constructor, " +
"therefor cannot be instantiated and will be ignored."
)
return null
}
} as Patch<*>
}
}
/**
* A [PatchBundleLoader] for JAR files.
*
* @param patchBundles The path to patch bundles of JAR format.
*/
class Jar(vararg patchBundles: File) : PatchBundleLoader(
URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray()),
patchBundles,
{ patchBundle ->
JarFile(patchBundle).entries().toList().filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
}
)
/**
* A [PatchBundleLoader] for [Dex] files.
*
* @param patchBundles The path to patch bundles of DEX format.
* @param optimizedDexDirectory The directory to store optimized DEX files in.
* This parameter is deprecated and has no effect since API level 26.
*/
class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader(
DexClassLoader(
patchBundles.joinToString(File.pathSeparator) { it.absolutePath }, optimizedDexDirectory?.absolutePath,
null,
PatchBundleLoader::class.java.classLoader
),
patchBundles,
{ patchBundle ->
MultiDexIO.readDexFile(true, patchBundle, BasicDexFileNamer(), null, null).classes
.map { classDef ->
classDef.type.substring(1, classDef.length - 1)
}
}
) {
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
}
}

View File

@@ -0,0 +1,8 @@
package app.revanced.patcher
import app.revanced.patcher.patch.PatchResult
import kotlinx.coroutines.flow.Flow
import java.util.function.Function
@FunctionalInterface
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
package app.revanced.patcher
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.Patch
import brut.androlib.apk.ApkInfo
import brut.directory.ExtFile
/**
* A context for ReVanced [Patcher].
*
* @param options The [PatcherOptions] used to create this context.
*/
class PatcherContext internal constructor(options: PatcherOptions) {
/**
* [PackageMetadata] of the supplied [PatcherOptions.inputFile].
*/
val packageMetadata = PackageMetadata(ApkInfo(ExtFile(options.inputFile)))
/**
* The map of [Patch]es associated by their [PatchClass].
*/
internal val executablePatches = mutableMapOf<PatchClass, Patch<*>>()
/**
* The map of all [Patch]es and their dependencies associated by their [PatchClass].
*/
internal val allPatches = mutableMapOf<PatchClass, Patch<*>>()
/**
* The [ResourceContext] of this [PatcherContext].
* This holds the current state of the resources.
*/
internal val resourceContext = ResourceContext(this, options)
/**
* The [BytecodeContext] of this [PatcherContext].
* This holds the current state of the bytecode.
*/
internal val bytecodeContext = BytecodeContext(options) }

View File

@@ -0,0 +1,16 @@
package app.revanced.patcher
/**
* An exception thrown by ReVanced [Patcher].
*
* @param errorMessage The exception message.
* @param cause The corresponding [Throwable].
*/
sealed class PatcherException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) {
constructor(errorMessage: String) : this(errorMessage, null)
class CircularDependencyException internal constructor(dependant: String) : PatcherException(
"Patch '$dependant' causes a circular dependency"
)
}

View File

@@ -0,0 +1,73 @@
package app.revanced.patcher
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.logging.impl.NopLogger
import brut.androlib.Config
import java.io.File
import java.util.logging.Logger
/**
* Options for ReVanced [Patcher].
* @param inputFile The input file to patch.
* @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
* @param unusedLogger The logger to use for logging.
*/
data class PatcherOptions
@Deprecated("Use the constructor without the logger parameter instead")
constructor(
internal val inputFile: File,
internal val resourceCachePath: File = File("revanced-resource-cache"),
internal val aaptBinaryPath: String? = null,
internal val frameworkFileDirectory: String? = null,
internal val unusedLogger: app.revanced.patcher.logging.Logger = NopLogger
) {
private val logger = Logger.getLogger(PatcherOptions::class.java.name)
/**
* The mode to use for resource decoding.
* @see ResourceContext.ResourceDecodingMode
*/
internal var resourceDecodingMode = ResourceContext.ResourceDecodingMode.MANIFEST_ONLY
/**
* The configuration to use for resource decoding and compiling.
*/
internal val resourceConfig = Config.getDefaultConfig().apply {
useAapt2 = true
aaptPath = aaptBinaryPath ?: ""
frameworkDirectory = frameworkFileDirectory
}
/**
* Options for ReVanced [Patcher].
* @param inputFile The input file to patch.
* @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
*/
constructor(
inputFile: File,
resourceCachePath: File = File("revanced-resource-cache"),
aaptBinaryPath: String? = null,
frameworkFileDirectory: String? = null,
) : this(
inputFile,
resourceCachePath,
aaptBinaryPath,
frameworkFileDirectory,
NopLogger
)
fun recreateResourceCacheDirectory() = resourceCachePath.also {
if (it.exists()) {
logger.info("Deleting existing resource cache directory")
if (!it.deleteRecursively())
logger.severe("Failed to delete existing resource cache directory")
}
it.mkdirs()
}
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patcher
import java.io.File
import java.io.InputStream
/**
* The result of a patcher.
* @param dexFiles The patched dex files.
* @param resourceFile File containing resources that need to be extracted into the APK.
* @param doNotCompress List of relative paths of files to exclude from compressing.
*/
data class PatcherResult(
val dexFiles: List<PatchedDexFile>,
val resourceFile: File?,
val doNotCompress: List<String>? = null
) {
/**
* Wrapper for dex files.
* @param name The original name of the dex file.
* @param stream The dex file as [InputStream].
*/
class PatchedDexFile(val name: String, val stream: InputStream)
}

Some files were not shown because too many files have changed in this diff Show More