Compare commits

...

67 Commits

Author SHA1 Message Date
semantic-release-bot
835c0f9f7a chore(release): 1.7.2 [skip ci]
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)

### Bug Fixes

* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](34f607aa24))
2022-06-22 14:17:16 +00:00
Oskar
34f607aa24 fix: add execute permission to ./gradlew file (#46) 2022-06-22 16:16:00 +02:00
Lucaskyy
0f38b94701 Merge remote-tracking branch 'origin/main' into main 2022-06-22 16:13:34 +02:00
Lucaskyy
39bb1b25dc refactor: add logging 2022-06-22 16:13:23 +02:00
Lucaskyy
4fc63a4d8a refactor: add callbacks for applyPatches & addFiles 2022-06-22 15:37:33 +02:00
semantic-release-bot
6037397bc2 chore(release): 1.7.1 [skip ci]
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)

### Reverts

* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](e8488b3e86))
2022-06-22 13:07:22 +00:00
Lucaskyy
273dd86b65 chore: remove ExtFile import 2022-06-22 15:04:05 +02:00
Lucaskyy
e8488b3e86 revert "feat: use of java.util.logging.Logger"
This reverts commit 9c39c9efdb.
This reverts commit 8f66f9f606.
2022-06-22 15:03:30 +02:00
semantic-release-bot
c13361823d chore(release): 1.7.0 [skip ci]
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)

### Features

* migrate logger to `slf4j` ([8f66f9f](8f66f9f606))
2022-06-22 12:18:57 +00:00
oSumAtrIX
8f66f9f606 feat: migrate logger to slf4j 2022-06-22 14:17:09 +02:00
semantic-release-bot
a123026f46 chore(release): 1.6.0 [skip ci]
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)

### Features

* use of `java.util.logging.Logger` ([9c39c9e](9c39c9efdb))
2022-06-22 11:48:43 +00:00
oSumAtrIX
9c39c9efdb feat: use of java.util.logging.Logger 2022-06-22 13:45:13 +02:00
semantic-release-bot
3ee1c01430 chore(release): 1.5.0 [skip ci]
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)

### Features

* use streams to write the dex files ([64bae88](64bae884dc))
2022-06-22 01:21:33 +00:00
oSumAtrIX
64bae884dc feat: use streams to write the dex files 2022-06-22 03:19:39 +02:00
semantic-release-bot
e94a706949 chore(release): 1.4.0 [skip ci]
# [1.4.0](https://github.com/revanced/revanced-patcher/compare/v1.3.4...v1.4.0) (2022-06-22)

### Features

* return a `File` instance instead of `ExtFile` ([68174bb](68174bbd6b))
2022-06-22 00:55:56 +00:00
oSumAtrIX
89bb43066b build: use dependencies as implementations instead of apis 2022-06-22 02:54:23 +02:00
oSumAtrIX
68174bbd6b feat: return a File instance instead of ExtFile 2022-06-22 02:53:37 +02:00
semantic-release-bot
d05c9416d6 chore(release): 1.3.4 [skip ci]
## [1.3.4](https://github.com/revanced/revanced-patcher/compare/v1.3.3...v1.3.4) (2022-06-21)

### Bug Fixes

* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](5a2f02b97d)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
2022-06-21 21:53:33 +00:00
oSumAtrIX
5a2f02b97d fix: String.toInstructions defaulting forStaticMethod to false
Fixes revanced/revanced-patches#46
2022-06-21 23:52:09 +02:00
semantic-release-bot
a3005fa08e chore(release): 1.3.3 [skip ci]
## [1.3.3](https://github.com/revanced/revanced-patcher/compare/v1.3.2...v1.3.3) (2022-06-21)

### Bug Fixes

* add docs (trigger release) ([6628b78](6628b7870f))

### Reverts

* propagate dependencies ([365e1d7](365e1d7a45))
2022-06-21 19:04:06 +00:00
Lucaskyy
6628b7870f fix: add docs (trigger release) 2022-06-21 21:02:50 +02:00
Lucaskyy
a6411245aa Merge remote-tracking branch 'origin/main' into main 2022-06-21 20:50:11 +02:00
Lucaskyy
365e1d7a45 revert: propagate dependencies
guess it doesn't work when not propagating them
2022-06-21 20:50:00 +02:00
semantic-release-bot
4507cd2353 chore(release): 1.3.2 [skip ci]
## [1.3.2](https://github.com/revanced/revanced-patcher/compare/v1.3.1...v1.3.2) (2022-06-21)

### Bug Fixes

* return resourceFile to caller ([1f75777](1f75777cf9))
2022-06-21 18:45:16 +00:00
Lucaskyy
1f75777cf9 fix: return resourceFile to caller 2022-06-21 20:43:47 +02:00
Lucaskyy
28d5468b07 build: do not propagate all dependencies 2022-06-21 20:29:37 +02:00
semantic-release-bot
746496125d chore(release): 1.3.1 [skip ci]
## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21)

### Bug Fixes

* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](835a421cc0))
2022-06-21 15:48:43 +00:00
oSumAtrIX
835a421cc0 fix: InlineSmaliCompiler.compile using 0 registers instead of 1 by default 2022-06-21 17:46:43 +02:00
semantic-release-bot
99342fe033 chore(release): 1.3.0 [skip ci]
# [1.3.0](https://github.com/revanced/revanced-patcher/compare/v1.2.9...v1.3.0) (2022-06-20)

### Features

* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](ad6c5c8273))
* simplify adding instructions ([e47b67d](e47b67d7ec))
2022-06-20 19:22:22 +00:00
oSumAtrIX
e47b67d7ec feat: simplify adding instructions 2022-06-20 21:20:51 +02:00
oSumAtrIX
ad6c5c8273 feat: parametersCount for InlineSmaliCompiler instead of parameters 2022-06-20 20:10:11 +02:00
oSumAtrIX
fd690acd61 refactor: add internal attribute to signatures field 2022-06-20 20:10:06 +02:00
semantic-release-bot
e698b02bf6 chore(release): 1.2.9 [skip ci]
## [1.2.9](https://github.com/revanced/revanced-patcher/compare/v1.2.8...v1.2.9) (2022-06-20)

### Bug Fixes

* update apktool ([ab866bb](ab866bb8ef))
2022-06-20 15:08:57 +00:00
Lucaskyy
ab866bb8ef fix: update apktool 2022-06-20 17:07:04 +02:00
semantic-release-bot
714a98422d chore(release): 1.2.8 [skip ci]
## [1.2.8](https://github.com/revanced/revanced-patcher/compare/v1.2.7...v1.2.8) (2022-06-18)

### Bug Fixes

* update apktool ([051afd9](051afd98d0))
2022-06-18 21:51:07 +00:00
Sculas
051afd98d0 fix: update apktool 2022-06-18 23:49:41 +02:00
semantic-release-bot
d38cf6a229 chore(release): 1.2.7 [skip ci]
## [1.2.7](https://github.com/revanced/revanced-patcher/compare/v1.2.6...v1.2.7) (2022-06-18)

### Bug Fixes

* version not working with apktool due to cache ([03f5ee0](03f5ee088b))
2022-06-18 21:17:22 +00:00
Sculas
03f5ee088b fix: version not working with apktool due to cache 2022-06-18 23:15:33 +02:00
semantic-release-bot
5d0fd48b15 chore(release): 1.2.6 [skip ci]
## [1.2.6](https://github.com/revanced/revanced-patcher/compare/v1.2.5...v1.2.6) (2022-06-18)

### Bug Fixes

* remove javadoc jar (also trigger release) ([56f6ca3](56f6ca3891))
2022-06-18 20:54:29 +00:00
Sculas
56f6ca3891 fix: remove javadoc jar (also trigger release) 2022-06-18 22:52:49 +02:00
semantic-release-bot
9e0a74fcfb chore(release): 1.2.5 [skip ci]
## [1.2.5](https://github.com/revanced/revanced-patcher/compare/v1.2.4...v1.2.5) (2022-06-17)

### Bug Fixes

* goodbye security ([8f3ac77](8f3ac7702a))
2022-06-17 16:13:47 +00:00
Sculas
8f3ac7702a fix: goodbye security 2022-06-17 18:12:18 +02:00
semantic-release-bot
7b65f2d02c chore(release): 1.2.4 [skip ci]
## [1.2.4](https://github.com/revanced/revanced-patcher/compare/v1.2.3...v1.2.4) (2022-06-15)

### Reverts

* "fix: enforce aapt v1" ([dfd8a24](dfd8a24512))
2022-06-15 19:41:28 +00:00
Lucaskyy
2a1b2df56b Merge remote-tracking branch 'origin/main' into main 2022-06-15 21:39:42 +02:00
Lucaskyy
dfd8a24512 revert: "fix: enforce aapt v1"
This reverts commit cff87ff077.
2022-06-15 21:39:27 +02:00
semantic-release-bot
a3efd212fc chore(release): 1.2.3 [skip ci]
## [1.2.3](https://github.com/revanced/revanced-patcher/compare/v1.2.2...v1.2.3) (2022-06-14)

### Bug Fixes

* enforce aapt v1 ([cff87ff](cff87ff077))
2022-06-14 22:26:32 +00:00
Lucaskyy
3e610f7ba9 Merge remote-tracking branch 'origin/main' into main 2022-06-15 00:25:21 +02:00
Lucaskyy
cff87ff077 fix: enforce aapt v1 2022-06-15 00:25:06 +02:00
semantic-release-bot
54aa04ca34 chore(release): 1.2.2 [skip ci]
## [1.2.2](https://github.com/revanced/revanced-patcher/compare/v1.2.1...v1.2.2) (2022-06-14)

### Bug Fixes

* enforce aapt v2 ([b68b0bf](b68b0bf3d7))
2022-06-14 20:35:38 +00:00
Lucaskyy
0eda84eaef Merge remote-tracking branch 'origin/main' into main 2022-06-14 22:34:21 +02:00
Lucaskyy
b68b0bf3d7 fix: enforce aapt v2 2022-06-14 22:34:10 +02:00
semantic-release-bot
c692202f67 chore(release): 1.2.1 [skip ci]
## [1.2.1](https://github.com/revanced/revanced-patcher/compare/v1.2.0...v1.2.1) (2022-06-14)

### Bug Fixes

* Patcher setting BuildOptions too late ([6a5c873](6a5c8735fb))
2022-06-14 16:25:08 +00:00
Lucaskyy
8ce3535427 Merge remote-tracking branch 'origin/main' into main 2022-06-14 18:23:49 +02:00
Lucaskyy
6a5c8735fb fix: Patcher setting BuildOptions too late
This causes the Manager to crash, due to a stupid bug in Apktool which is prevented by setting a valid frameworkFolderLocation.
2022-06-14 18:23:40 +02:00
semantic-release-bot
8f32bc9c08 chore(release): 1.2.0 [skip ci]
# [1.2.0](https://github.com/revanced/revanced-patcher/compare/v1.1.0...v1.2.0) (2022-06-14)

### Features

* allow custom framework path to be specified ([d3a580e](d3a580ea19))
2022-06-14 15:50:24 +00:00
Lucaskyy
d3a580ea19 feat: allow custom framework path to be specified 2022-06-14 17:49:07 +02:00
oSumAtrIX
4c8eb0e5c7 refactor: gradle build script 2022-06-14 01:34:48 +02:00
semantic-release-bot
bc92eb7fd8 chore(release): 1.1.0 [skip ci]
# [1.1.0](https://github.com/revanced/revanced-patcher/compare/v1.0.0...v1.1.0) (2022-06-11)

### Bug Fixes

* resource patcher ([31815ca](31815ca9ea))
* update apktool to fork ([566ecef](566ecefa2b))

### Features

* allow custom aapt path to be specified ([8eb4a8f](8eb4a8f87a))
2022-06-11 23:25:19 +00:00
oSumAtrIX
cf89bd4171 Merge pull request #39 from revanced/non-root
fix: resource patcher
2022-06-12 01:24:04 +02:00
Lucaskyy
566ecefa2b fix: update apktool to fork 2022-06-11 20:39:29 +02:00
Lucaskyy
8eb4a8f87a feat: allow custom aapt path to be specified 2022-06-11 20:08:00 +02:00
oSumAtrIX
afcba5c212 refactor: simplify code by removing the with block 2022-06-11 19:45:11 +02:00
oSumAtrIX
2dcbd8d079 refactor: use include annotation parameter instead of excludeByDefault 2022-06-11 19:14:19 +02:00
oSumAtrIX
81895c7d5c Merge remote-tracking branch 'origin/non-root' into non-root
# Conflicts:
#	src/main/kotlin/app/revanced/patcher/Patcher.kt
2022-06-11 18:56:38 +02:00
Lucaskyy
22267883b1 refactor: get rid of all useless let blocks 2022-06-11 16:56:05 +02:00
oSumAtrIX
26fca60b53 refactor: use also instead of let where possible 2022-06-11 16:24:49 +02:00
oSumAtrIX
31815ca9ea fix: resource patcher 2022-06-11 06:36:13 +02:00
20 changed files with 461 additions and 127 deletions

View File

@@ -28,8 +28,6 @@ jobs:
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: "lts/*" node-version: "lts/*"
- name: Make gradlew executable
run: chmod +x gradlew
- name: Build with Gradle - name: Build with Gradle
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,3 +1,169 @@
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)
### Bug Fixes
* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](https://github.com/revanced/revanced-patcher/commit/34f607aa24d89a777d906cc887203f343ce3fd07))
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)
### Reverts
* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](https://github.com/revanced/revanced-patcher/commit/e8488b3e86e0132011824f8ecba29e64f8db0573))
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)
### Features
* migrate logger to `slf4j` ([8f66f9f](https://github.com/revanced/revanced-patcher/commit/8f66f9f606a785ac947b0e553822877f211d82df))
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)
### Features
* use of `java.util.logging.Logger` ([9c39c9e](https://github.com/revanced/revanced-patcher/commit/9c39c9efdb5d48ddaffce7f711c275e732b0b2d9))
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)
### Features
* use streams to write the dex files ([64bae88](https://github.com/revanced/revanced-patcher/commit/64bae884dcb72550a3218e149f3ca0fd0ca03aaf))
# [1.4.0](https://github.com/revanced/revanced-patcher/compare/v1.3.4...v1.4.0) (2022-06-22)
### Features
* return a `File` instance instead of `ExtFile` ([68174bb](https://github.com/revanced/revanced-patcher/commit/68174bbd6b4df47a91b610c2b97dbae55b594163))
## [1.3.4](https://github.com/revanced/revanced-patcher/compare/v1.3.3...v1.3.4) (2022-06-21)
### Bug Fixes
* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](https://github.com/revanced/revanced-patcher/commit/5a2f02b97dcde95dbe901fa68cca6c6c0219cb82)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
## [1.3.3](https://github.com/revanced/revanced-patcher/compare/v1.3.2...v1.3.3) (2022-06-21)
### Bug Fixes
* add docs (trigger release) ([6628b78](https://github.com/revanced/revanced-patcher/commit/6628b7870fc052da40be0d50a7e2b0b6c57743cc))
### Reverts
* propagate dependencies ([365e1d7](https://github.com/revanced/revanced-patcher/commit/365e1d7a4507b918a4c8170ce2c88f6c8ff1d474))
## [1.3.2](https://github.com/revanced/revanced-patcher/compare/v1.3.1...v1.3.2) (2022-06-21)
### Bug Fixes
* return resourceFile to caller ([1f75777](https://github.com/revanced/revanced-patcher/commit/1f75777cf985bf08483033ec541937d3e733347b))
## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21)
### Bug Fixes
* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](https://github.com/revanced/revanced-patcher/commit/835a421cc0588b92c2995e9d74727069d14b1750))
# [1.3.0](https://github.com/revanced/revanced-patcher/compare/v1.2.9...v1.3.0) (2022-06-20)
### Features
* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](https://github.com/revanced/revanced-patcher/commit/ad6c5c827389d10eae473dc66557a699df8c3280))
* simplify adding instructions ([e47b67d](https://github.com/revanced/revanced-patcher/commit/e47b67d7ec521f288644afb89baf4146dc9bc87d))
## [1.2.9](https://github.com/revanced/revanced-patcher/compare/v1.2.8...v1.2.9) (2022-06-20)
### Bug Fixes
* update apktool ([ab866bb](https://github.com/revanced/revanced-patcher/commit/ab866bb8ef4792d8f2a51edc79e687b5b636c621))
## [1.2.8](https://github.com/revanced/revanced-patcher/compare/v1.2.7...v1.2.8) (2022-06-18)
### Bug Fixes
* update apktool ([051afd9](https://github.com/revanced/revanced-patcher/commit/051afd98d065f71556392139d77c20b4c2dc7dd1))
## [1.2.7](https://github.com/revanced/revanced-patcher/compare/v1.2.6...v1.2.7) (2022-06-18)
### Bug Fixes
* version not working with apktool due to cache ([03f5ee0](https://github.com/revanced/revanced-patcher/commit/03f5ee088b1b96b88cb7aeb323443b6209a13950))
## [1.2.6](https://github.com/revanced/revanced-patcher/compare/v1.2.5...v1.2.6) (2022-06-18)
### Bug Fixes
* remove javadoc jar (also trigger release) ([56f6ca3](https://github.com/revanced/revanced-patcher/commit/56f6ca38919b522c0d5558eabffa4aee41cc0b0b))
## [1.2.5](https://github.com/revanced/revanced-patcher/compare/v1.2.4...v1.2.5) (2022-06-17)
### Bug Fixes
* goodbye security ([8f3ac77](https://github.com/revanced/revanced-patcher/commit/8f3ac7702a2b3ee98c55aeac6a1b9972f99664cc))
## [1.2.4](https://github.com/revanced/revanced-patcher/compare/v1.2.3...v1.2.4) (2022-06-15)
### Reverts
* "fix: enforce aapt v1" ([dfd8a24](https://github.com/revanced/revanced-patcher/commit/dfd8a245124f85b1b028bbba197c70c8dca689b6))
## [1.2.3](https://github.com/revanced/revanced-patcher/compare/v1.2.2...v1.2.3) (2022-06-14)
### Bug Fixes
* enforce aapt v1 ([cff87ff](https://github.com/revanced/revanced-patcher/commit/cff87ff0770d774d7ef79eec5a22462eadbcb9c5))
## [1.2.2](https://github.com/revanced/revanced-patcher/compare/v1.2.1...v1.2.2) (2022-06-14)
### Bug Fixes
* enforce aapt v2 ([b68b0bf](https://github.com/revanced/revanced-patcher/commit/b68b0bf3d735f54b92ad7dad8132f77e9007063f))
## [1.2.1](https://github.com/revanced/revanced-patcher/compare/v1.2.0...v1.2.1) (2022-06-14)
### Bug Fixes
* Patcher setting BuildOptions too late ([6a5c873](https://github.com/revanced/revanced-patcher/commit/6a5c8735fb8a5d6f7e9c606734b6684c7fa99e7f))
# [1.2.0](https://github.com/revanced/revanced-patcher/compare/v1.1.0...v1.2.0) (2022-06-14)
### Features
* allow custom framework path to be specified ([d3a580e](https://github.com/revanced/revanced-patcher/commit/d3a580ea19d7c2d5d8c97650b1e6396ea0a7fc25))
# [1.1.0](https://github.com/revanced/revanced-patcher/compare/v1.0.0...v1.1.0) (2022-06-11)
### Bug Fixes
* resource patcher ([31815ca](https://github.com/revanced/revanced-patcher/commit/31815ca9ea990f16b3600d61fd570c1805be1c82))
* update apktool to fork ([566ecef](https://github.com/revanced/revanced-patcher/commit/566ecefa2bd4cde5ebfb2b22dc56cd8bf9f396bd))
### Features
* allow custom aapt path to be specified ([8eb4a8f](https://github.com/revanced/revanced-patcher/commit/8eb4a8f87ae7679a272f3224273a37a31d4bb121))
# 1.0.0 (2022-06-05) # 1.0.0 (2022-06-05)

View File

@@ -1,38 +1,32 @@
plugins { plugins {
kotlin("jvm") version "1.6.21" kotlin("jvm") version "1.7.0"
java java
`maven-publish` `maven-publish`
} }
group = "app.revanced" group = "app.revanced"
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 { repositories {
mavenCentral() mavenCentral()
maven { maven {
url = uri("https://maven.pkg.github.com/revanced/multidexlib2") url = uri("https://maven.pkg.github.com/revanced/multidexlib2")
credentials { credentials {
// DO NOT set these variables in the project's gradle.properties. username = githubUsername
// Instead, you should set them in: password = githubPassword
// Windows: %homepath%\.gradle\gradle.properties
// Linux: ~/.gradle/gradle.properties
username =
project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") // DO NOT CHANGE!
password =
project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") // DO NOT CHANGE!
} }
} }
} }
dependencies { dependencies {
implementation(kotlin("stdlib")) implementation("xpp3:xpp3:1.1.4c")
implementation("app.revanced:multidexlib2:2.5.2.r2")
api("xpp3:xpp3:1.1.4c") implementation("org.smali:smali:2.5.2")
api("org.apktool:apktool-lib:2.6.1") implementation("org.apktool:apktool-lib:2.6.5-SNAPSHOT")
api("app.revanced:multidexlib2:2.5.2.r2")
api("org.smali:smali:2.5.2")
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
implementation(kotlin("reflect"))
} }
tasks { tasks {
@@ -46,14 +40,10 @@ tasks {
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar()
} }
val isGitHubCI = System.getenv("GITHUB_ACTOR") != null
publishing { publishing {
repositories { repositories {
if (isGitHubCI) {
maven { maven {
name = "GitHubPackages" name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
@@ -62,13 +52,10 @@ publishing {
password = System.getenv("GITHUB_TOKEN") password = System.getenv("GITHUB_TOKEN")
} }
} }
} else {
mavenLocal()
}
} }
publications { publications {
register<MavenPublication>("gpr") { register<MavenPublication>("gpr") {
from(components["java"]) from(components["java"])
} }
} }
} }

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 1.0.0 version = 1.7.2

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -0,0 +1,15 @@
package app.revanced.patcher
interface PatchLogger {
fun error(msg: String)
fun warn(msg: String)
fun info(msg: String)
fun trace(msg: String)
}
internal object NoopPatchLogger : PatchLogger {
override fun error(msg: String) {}
override fun warn(msg: String) {}
override fun info(msg: String) {}
override fun trace(msg: String) {}
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patcher package app.revanced.patcher
import app.revanced.patcher.data.PackageMetadata
import app.revanced.patcher.data.PatcherData import app.revanced.patcher.data.PatcherData
import app.revanced.patcher.data.base.Data import app.revanced.patcher.data.base.Data
import app.revanced.patcher.data.implementation.findIndexed import app.revanced.patcher.data.implementation.findIndexed
@@ -16,11 +17,13 @@ import app.revanced.patcher.signature.implementation.method.resolver.MethodSigna
import app.revanced.patcher.util.ListBackedSet import app.revanced.patcher.util.ListBackedSet
import brut.androlib.Androlib import brut.androlib.Androlib
import brut.androlib.meta.UsesFramework import brut.androlib.meta.UsesFramework
import brut.androlib.options.BuildOptions
import brut.androlib.res.AndrolibResources import brut.androlib.res.AndrolibResources
import brut.androlib.res.data.ResPackage import brut.androlib.res.data.ResPackage
import brut.androlib.res.decoder.AXmlResourceParser import brut.androlib.res.decoder.AXmlResourceParser
import brut.androlib.res.decoder.ResAttrDecoder import brut.androlib.res.decoder.ResAttrDecoder
import brut.androlib.res.decoder.XmlPullStreamDecoder import brut.androlib.res.decoder.XmlPullStreamDecoder
import brut.androlib.res.xml.ResXmlPatcher
import brut.directory.ExtFile import brut.directory.ExtFile
import lanchon.multidexlib2.BasicDexFileNamer import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.DexIO import lanchon.multidexlib2.DexIO
@@ -30,6 +33,7 @@ import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.DexFile import org.jf.dexlib2.iface.DexFile
import org.jf.dexlib2.writer.io.MemoryDataStore import org.jf.dexlib2.writer.io.MemoryDataStore
import java.io.File import java.io.File
import java.nio.file.Files
val NAMER = BasicDexFileNamer() val NAMER = BasicDexFileNamer()
@@ -37,36 +41,45 @@ val NAMER = BasicDexFileNamer()
* The ReVanced Patcher. * The ReVanced Patcher.
* @param options The options for the patcher. * @param options The options for the patcher.
*/ */
class Patcher( class Patcher(private val options: PatcherOptions) {
private val options: PatcherOptions private val logger = options.logger
) {
val packageVersion: String
val packageName: String
private lateinit var usesFramework: UsesFramework
private val patcherData: PatcherData
private val opcodes: Opcodes private val opcodes: Opcodes
val data: PatcherData
init { init {
val extFileInput = ExtFile(options.inputFile) val extInputFile = ExtFile(options.inputFile)
val outDir = File(options.resourceCacheDirectory) val outDir = File(options.resourceCacheDirectory)
if (outDir.exists()) {
logger.info("Deleting existing resource cache directory")
outDir.deleteRecursively()
}
outDir.mkdirs()
if (outDir.exists()) outDir.deleteRecursively() val androlib = Androlib(BuildOptions().also { it.setBuildOptions(options) })
outDir.mkdir() val resourceTable = androlib.getResTable(extInputFile, true)
// load the resource table from the input file val packageMetadata = PackageMetadata()
val androlib = Androlib()
val resourceTable = androlib.getResTable(extFileInput, true)
if (options.patchResources) { if (options.patchResources) {
// 1. decode resources to cache directory logger.info("Decoding resources using Androlib, this may take a long time...")
androlib.decodeManifestWithResources(extFileInput, outDir, resourceTable)
androlib.decodeResourcesFull(extFileInput, outDir, resourceTable) // decode resources to cache directory
androlib.decodeManifestWithResources(extInputFile, outDir, resourceTable)
androlib.decodeResourcesFull(extInputFile, outDir, resourceTable)
// read additional metadata from the resource table
packageMetadata.metaInfo.usesFramework = UsesFramework().also { framework ->
framework.ids = resourceTable.listFramePackages().map { it.id }.sorted()
}
packageMetadata.metaInfo.doNotCompress = buildList {
androlib.recordUncompressedFiles(extInputFile, this)
}
// 2. read framework ids from the resource table
usesFramework = UsesFramework()
usesFramework.ids = resourceTable.listFramePackages().map { it.id }.sorted()
} else { } else {
logger.info("Decoding resources manually because resource decoding is disabled!")
// create decoder for the resource table // create decoder for the resource table
val decoder = ResAttrDecoder() val decoder = ResAttrDecoder()
decoder.currentPackage = ResPackage(resourceTable, 0, null) decoder.currentPackage = ResPackage(resourceTable, 0, null)
@@ -80,19 +93,25 @@ class Patcher(
XmlPullStreamDecoder( XmlPullStreamDecoder(
axmlParser, AndrolibResources().resXmlSerializer axmlParser, AndrolibResources().resXmlSerializer
).decodeManifest( ).decodeManifest(
extFileInput.directory.getFileInput("AndroidManifest.xml"), nullOutputStream extInputFile.directory.getFileInput("AndroidManifest.xml"), nullOutputStream
) )
} }
// set package information packageMetadata.packageName = resourceTable.currentResPackage.name
packageVersion = resourceTable.versionInfo.versionName packageMetadata.packageVersion = resourceTable.versionInfo.versionName
packageName = resourceTable.currentResPackage.name packageMetadata.metaInfo.versionInfo = resourceTable.versionInfo
packageMetadata.metaInfo.sdkInfo = resourceTable.sdkInfo
// read dex files // read dex files
logger.info("Reading input as dex file")
val dexFile = MultiDexIO.readDexFile(true, options.inputFile, NAMER, null, null) val dexFile = MultiDexIO.readDexFile(true, options.inputFile, NAMER, null, null)
// get the opcodes
opcodes = dexFile.opcodes opcodes = dexFile.opcodes
// save to patcher data // finally create patcher data
patcherData = PatcherData(dexFile.classes.toMutableList(), options.resourceCacheDirectory) data = PatcherData(
dexFile.classes.toMutableList(), options.resourceCacheDirectory, packageMetadata
)
} }
/** /**
@@ -102,23 +121,32 @@ class Patcher(
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found. * @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
*/ */
fun addFiles( fun addFiles(
files: Iterable<File>, allowedOverwrites: Iterable<String> = emptyList(), throwOnDuplicates: Boolean = false files: List<File>,
allowedOverwrites: Iterable<String> = emptyList(),
throwOnDuplicates: Boolean = false,
callback: (File) -> Unit
) { ) {
for (file in files) { for (file in files) {
val dexFile = MultiDexIO.readDexFile(true, file, NAMER, null, null) var modified = false
for (classDef in dexFile.classes) { for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
val e = patcherData.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type } val e = data.bytecodeData.classes.internalClasses.findIndexed { it.type == classDef.type }
if (e != null) { if (e != null) {
if (throwOnDuplicates) { if (throwOnDuplicates) {
throw Exception("Class ${classDef.type} has already been added to the patcher.") throw Exception("Class ${classDef.type} has already been added to the patcher.")
} }
val (_, idx) = e val (_, idx) = e
if (allowedOverwrites.contains(classDef.type)) { if (allowedOverwrites.contains(classDef.type)) {
patcherData.bytecodeData.classes.internalClasses[idx] = classDef data.bytecodeData.classes.internalClasses[idx] = classDef
modified = true
} }
continue continue
} }
patcherData.bytecodeData.classes.internalClasses.add(classDef) data.bytecodeData.classes.internalClasses.add(classDef)
modified = true
}
if (modified) {
logger.trace("Added file ${file.name}")
callback(file)
} }
} }
} }
@@ -126,11 +154,60 @@ class Patcher(
/** /**
* Save the patched dex file. * Save the patched dex file.
*/ */
fun save(): Map<String, MemoryDataStore> { fun save(): PatcherResult {
val packageMetadata = data.packageMetadata
val metaInfo = packageMetadata.metaInfo
var resourceFile: File? = null
if (options.patchResources) {
logger.info("Patching resources")
val cacheDirectory = ExtFile(options.resourceCacheDirectory)
val androlibResources = AndrolibResources().also { resources ->
resources.buildOptions = BuildOptions().also { buildOptions ->
buildOptions.setBuildOptions(options)
buildOptions.isFramework = metaInfo.isFrameworkApk
buildOptions.resourcesAreCompressed = metaInfo.compressionType
buildOptions.doNotCompress = metaInfo.doNotCompress
}
resources.setSdkInfo(metaInfo.sdkInfo)
resources.setVersionInfo(metaInfo.versionInfo)
resources.setSharedLibrary(metaInfo.sharedLibrary)
resources.setSparseResources(metaInfo.sparseResources)
}
val manifestFile = cacheDirectory.resolve("AndroidManifest.xml")
ResXmlPatcher.fixingPublicAttrsInProviderAttributes(manifestFile)
val aaptFile = cacheDirectory.resolve("aapt_temp_file")
// delete if it exists
Files.deleteIfExists(aaptFile.toPath())
val resDirectory = cacheDirectory.resolve("res")
val includedFiles = metaInfo.usesFramework.ids.map { id ->
androlibResources.getFrameworkApk(
id,
metaInfo.usesFramework.tag
)
}.toTypedArray()
logger.trace("Packaging using aapt")
androlibResources.aaptPackage(
aaptFile, manifestFile, resDirectory, null,
null, includedFiles
)
resourceFile = aaptFile
}
logger.trace("Creating new dex file")
val newDexFile = object : DexFile { val newDexFile = object : DexFile {
override fun getClasses(): Set<ClassDef> { override fun getClasses(): Set<ClassDef> {
patcherData.bytecodeData.classes.applyProxies() data.bytecodeData.classes.applyProxies()
return ListBackedSet(patcherData.bytecodeData.classes.internalClasses) return ListBackedSet(data.bytecodeData.classes.internalClasses)
} }
override fun getOpcodes(): Opcodes { override fun getOpcodes(): Opcodes {
@@ -138,21 +215,21 @@ class Patcher(
} }
} }
// build modified resources // write modified dex files
if (options.patchResources) { logger.info("Writing modified dex files")
val extDir = ExtFile(options.resourceCacheDirectory) val dexFiles = mutableMapOf<String, MemoryDataStore>()
// TODO: figure out why a new instance of Androlib is necessary here
Androlib().buildResources(extDir, usesFramework)
}
// write dex modified files
val output = mutableMapOf<String, MemoryDataStore>()
MultiDexIO.writeDexFile( MultiDexIO.writeDexFile(
true, -1, // core count true, -1, // core count
output, NAMER, newDexFile, DexIO.DEFAULT_MAX_DEX_POOL_SIZE, null dexFiles, NAMER, newDexFile, DexIO.DEFAULT_MAX_DEX_POOL_SIZE, null
)
return PatcherResult(
dexFiles.map {
app.revanced.patcher.util.dex.DexFile(it.key, it.value.readAt(0))
},
metaInfo.doNotCompress.toList(),
resourceFile
) )
return output
} }
/** /**
@@ -160,7 +237,7 @@ class Patcher(
* @param patches [Patch]es The patches to add. * @param patches [Patch]es The patches to add.
*/ */
fun addPatches(patches: Iterable<Class<out Patch<Data>>>) { fun addPatches(patches: Iterable<Class<out Patch<Data>>>) {
patcherData.patches.addAll(patches) data.patches.addAll(patches)
} }
/** /**
@@ -170,12 +247,17 @@ class Patcher(
* @return The result of executing the [patch]. * @return The result of executing the [patch].
*/ */
private fun applyPatch( private fun applyPatch(
patch: Class<out Patch<Data>>, appliedPatches: MutableList<String> patch: Class<out Patch<Data>>,
appliedPatches: MutableList<String>
): PatchResult { ): PatchResult {
val patchName = patch.patchName val patchName = patch.patchName
logger.trace("Applying patch $patchName")
// if the patch has already applied silently skip it // if the patch has already applied silently skip it
if (appliedPatches.contains(patchName)) return PatchResultSuccess() if (appliedPatches.contains(patchName)) {
logger.trace("Skipping patch $patchName because it has already been applied")
return PatchResultSuccess()
}
appliedPatches.add(patchName) appliedPatches.add(patchName)
// recursively apply all dependency patches // recursively apply all dependency patches
@@ -193,18 +275,21 @@ class Patcher(
// if the current patch is a resource patch but resource patching is disabled, return an error // if the current patch is a resource patch but resource patching is disabled, return an error
val isResourcePatch = patchInstance is ResourcePatch val isResourcePatch = patchInstance is ResourcePatch
if (!options.patchResources && isResourcePatch) return PatchResultError("$patchName is a resource patch, but resource patching is disabled.") if (!options.patchResources && isResourcePatch) {
return PatchResultError("$patchName is a resource patch, but resource patching is disabled.")
}
// TODO: find a solution for this // TODO: find a solution for this
val data = if (isResourcePatch) { val data = if (isResourcePatch) {
patcherData.resourceData data.resourceData
} else { } else {
MethodSignatureResolver( MethodSignatureResolver(
patcherData.bytecodeData.classes.internalClasses, (patchInstance as BytecodePatch).signatures data.bytecodeData.classes.internalClasses, (patchInstance as BytecodePatch).signatures
).resolve(patcherData) ).resolve(data)
patcherData.bytecodeData data.bytecodeData
} }
logger.trace("Executing patch $patchName of type: ${if (isResourcePatch) "resource" else "bytecode"}")
return try { return try {
patchInstance.execute(data) patchInstance.execute(data)
} catch (e: Exception) { } catch (e: Exception) {
@@ -220,25 +305,31 @@ class Patcher(
* If the [Patch] failed to apply, an Exception will always be returned to the wrapping Result object. * If the [Patch] failed to apply, an Exception will always be returned to the wrapping Result object.
*/ */
fun applyPatches( fun applyPatches(
stopOnError: Boolean = false, callback: (String) -> Unit = {} stopOnError: Boolean = false,
callback: (Class<out Patch<Data>>, Boolean) -> Unit = { _, _ -> }
): Map<String, Result<PatchResultSuccess>> { ): Map<String, Result<PatchResultSuccess>> {
logger.trace("Applying all patches")
val appliedPatches = mutableListOf<String>() val appliedPatches = mutableListOf<String>()
return buildMap { return buildMap {
for (patch in patcherData.patches) { for (patch in data.patches) {
val result = applyPatch(patch, appliedPatches) val result = applyPatch(patch, appliedPatches)
val name = patch.patchName this[patch.patchName] = if (result.isSuccess()) {
callback(name)
this[name] = if (result.isSuccess()) {
Result.success(result.success()!!) Result.success(result.success()!!)
} else { } else {
Result.failure(result.error()!!) Result.failure(result.error()!!)
} }
callback(patch, result.isSuccess())
if (stopOnError && result.isError()) break if (stopOnError && result.isError()) break
} }
} }
} }
} }
private fun BuildOptions.setBuildOptions(options: PatcherOptions) {
this.aaptPath = options.aaptPath
this.useAapt2 = true
this.frameworkFolderLocation = options.frameworkFolderLocation
}

View File

@@ -3,13 +3,19 @@ package app.revanced.patcher
import java.io.File import java.io.File
/** /**
* Options for the [Patcher].
* @param inputFile The input file (usually an apk file). * @param inputFile The input file (usually an apk file).
* @param resourceCacheDirectory Directory to cache resources. * @param resourceCacheDirectory Directory to cache resources.
* @param patchResources Weather to use the resource patcher. Resources will still need to be decoded. * @param patchResources Weather to use the resource patcher. Resources will still need to be decoded.
* @param aaptPath Optional path to a custom aapt binary.
* @param frameworkFolderLocation Optional path to a custom framework folder.
* @param logger Custom logger implementation for the [Patcher].
*/ */
data class PatcherOptions( data class PatcherOptions(
internal val inputFile: File, internal val inputFile: File,
// TODO: maybe a file system in memory is better. Could cause high memory usage.
internal val resourceCacheDirectory: String, internal val resourceCacheDirectory: String,
internal val patchResources: Boolean = false internal val patchResources: Boolean = false,
internal val aaptPath: String = "",
internal val frameworkFolderLocation: String? = null,
internal val logger: PatchLogger = NoopPatchLogger
) )

View File

@@ -0,0 +1,16 @@
package app.revanced.patcher
import app.revanced.patcher.util.dex.DexFile
import java.io.File
/**
* The result of a patcher.
* @param dexFiles The patched dex files.
* @param doNotCompress List of relative paths to files to exclude from compressing.
* @param resourceFile File containing resources that need to be extracted into the APK.
*/
data class PatcherResult(
val dexFiles: List<DexFile>,
val doNotCompress: List<String>? = null,
val resourceFile: File?
)

View File

@@ -0,0 +1,13 @@
package app.revanced.patcher.data
import brut.androlib.meta.MetaInfo
/**
* Metadata about a package.
*/
class PackageMetadata {
lateinit var packageName: String
lateinit var packageVersion: String
internal val metaInfo: MetaInfo = MetaInfo()
}

View File

@@ -7,10 +7,12 @@ import app.revanced.patcher.patch.base.Patch
import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.ClassDef
import java.io.File import java.io.File
internal data class PatcherData( data class PatcherData(
val internalClasses: MutableList<ClassDef>, internal val internalClasses: MutableList<ClassDef>,
val resourceCacheDirectory: String internal val resourceCacheDirectory: String,
val packageMetadata: PackageMetadata
) { ) {
internal val patches = mutableListOf<Class<out Patch<Data>>>() internal val patches = mutableListOf<Class<out Patch<Data>>>()
internal val bytecodeData = BytecodeData(internalClasses) internal val bytecodeData = BytecodeData(internalClasses)

View File

@@ -34,7 +34,6 @@ class DomFileEditor internal constructor(private val domFile: File) : Closeable
init { init {
val factory = DocumentBuilderFactory.newInstance() val factory = DocumentBuilderFactory.newInstance()
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
val builder = factory.newDocumentBuilder() val builder = factory.newDocumentBuilder()

View File

@@ -41,13 +41,15 @@ object PatchExtensions {
val Class<out Patch<Data>>.patchName: String val Class<out Patch<Data>>.patchName: String
get() = recursiveAnnotation(Name::class)?.name ?: this.javaClass.simpleName get() = recursiveAnnotation(Name::class)?.name ?: this.javaClass.simpleName
val Class<out Patch<Data>>.version get() = recursiveAnnotation(Version::class)?.version val Class<out Patch<Data>>.version get() = recursiveAnnotation(Version::class)?.version
val Class<out Patch<Data>>.include get() = recursiveAnnotation(app.revanced.patcher.patch.annotations.Patch::class)!!.include
val Class<out Patch<Data>>.description get() = recursiveAnnotation(Description::class)?.description val Class<out Patch<Data>>.description get() = recursiveAnnotation(Description::class)?.description
val Class<out Patch<Data>>.dependencies get() = recursiveAnnotation(app.revanced.patcher.patch.annotations.Dependencies::class)?.dependencies val Class<out Patch<Data>>.dependencies get() = recursiveAnnotation(app.revanced.patcher.patch.annotations.Dependencies::class)?.dependencies
val Class<out Patch<Data>>.compatiblePackages get() = recursiveAnnotation(Compatibility::class)?.compatiblePackages val Class<out Patch<Data>>.compatiblePackages get() = recursiveAnnotation(Compatibility::class)?.compatiblePackages
} }
object MethodSignatureExtensions { object MethodSignatureExtensions {
val MethodSignature.name: String get() = javaClass.recursiveAnnotation(Name::class)?.name ?: this.javaClass.simpleName val MethodSignature.name: String
get() = javaClass.recursiveAnnotation(Name::class)?.name ?: this.javaClass.simpleName
val MethodSignature.version get() = javaClass.recursiveAnnotation(Version::class)?.version ?: "0.0.1" val MethodSignature.version get() = javaClass.recursiveAnnotation(Version::class)?.version ?: "0.0.1"
val MethodSignature.description get() = javaClass.recursiveAnnotation(Description::class)?.description val MethodSignature.description get() = javaClass.recursiveAnnotation(Description::class)?.description
val MethodSignature.compatiblePackages get() = javaClass.recursiveAnnotation(Compatibility::class)?.compatiblePackages val MethodSignature.compatiblePackages get() = javaClass.recursiveAnnotation(Compatibility::class)?.compatiblePackages

View File

@@ -1,6 +1,9 @@
package app.revanced.patcher.extensions package app.revanced.patcher.extensions
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.builder.MutableMethodImplementation
@@ -62,6 +65,22 @@ internal fun Method.clone(
) )
} }
/**
* Add smali instructions to the method.
* @param index The index to insert the instructions at.
* @param instruction The smali instruction to add.
*/
fun MutableMethod.addInstruction(index: Int, instruction: String) =
this.implementation!!.addInstruction(index, instruction.toInstruction(this))
/**
* Add smali instructions to the method.
* @param index The index to insert the instructions at.
* @param instructions The smali instructions to add.
*/
fun MutableMethod.addInstructions(index: Int, instructions: String) =
this.implementation!!.addInstructions(index, instructions.toInstructions(this))
/** /**
* Clones the method. * Clones the method.
* @param registerCount This parameter allows you to change the register count of the method. * @param registerCount This parameter allows you to change the register count of the method.

View File

@@ -6,11 +6,12 @@ import kotlin.reflect.KClass
/** /**
* Annotation to mark a Class as a patch. * Annotation to mark a Class as a patch.
* @param include If false, the patch should be treated as optional by default.
*/ */
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented @MustBeDocumented
annotation class Patch annotation class Patch(val include: Boolean = true)
/** /**
* Annotation for dependencies of [Patch]es . * Annotation for dependencies of [Patch]es .

View File

@@ -9,5 +9,5 @@ import app.revanced.patcher.signature.implementation.method.MethodSignature
* @param signatures A list of [MethodSignature] this patch relies on. * @param signatures A list of [MethodSignature] this patch relies on.
*/ */
abstract class BytecodePatch( abstract class BytecodePatch(
val signatures: Iterable<MethodSignature> internal val signatures: Iterable<MethodSignature>
) : Patch<BytecodeData>() ) : Patch<BytecodeData>()

View File

@@ -76,19 +76,17 @@ internal class MethodSignatureResolver(
signature.strings?.let { strings -> signature.strings?.let { strings ->
method.implementation ?: return null method.implementation ?: return null
method.implementation!!.instructions.let { instructions -> val stringsList = strings.toMutableList()
val stringsList = strings.toMutableList()
for (instruction in instructions) { for (instruction in method.implementation!!.instructions) {
if (instruction.opcode != Opcode.CONST_STRING) continue if (instruction.opcode != Opcode.CONST_STRING) continue
val string = ((instruction as Instruction21c).reference as StringReference).string val string = ((instruction as Instruction21c).reference as StringReference).string
val i = stringsList.indexOfFirst { it == string } val i = stringsList.indexOfFirst { it == string }
if (i != -1) stringsList.removeAt(i) if (i != -1) stringsList.removeAt(i)
}
if (stringsList.isNotEmpty()) return null
} }
if (stringsList.isNotEmpty()) return null
} }
return if (signature.opcodes == null) { return if (signature.opcodes == null) {

View File

@@ -0,0 +1,10 @@
package app.revanced.patcher.util.dex
import java.io.InputStream
/**
* Wrapper for dex files.
* @param name The original name of the dex file.
* @param dexFileInputStream The dex file as [InputStream].
*/
data class DexFile(val name: String, val dexFileInputStream: InputStream)

View File

@@ -3,8 +3,10 @@ package app.revanced.patcher.util.smali
import org.antlr.runtime.CommonTokenStream import org.antlr.runtime.CommonTokenStream
import org.antlr.runtime.TokenSource import org.antlr.runtime.TokenSource
import org.antlr.runtime.tree.CommonTreeNodeStream import org.antlr.runtime.tree.CommonTreeNodeStream
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcodes import org.jf.dexlib2.Opcodes
import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.writer.builder.DexBuilder import org.jf.dexlib2.writer.builder.DexBuilder
import org.jf.smali.LexerErrorInterface import org.jf.smali.LexerErrorInterface
import org.jf.smali.smaliFlexLexer import org.jf.smali.smaliFlexLexer
@@ -13,12 +15,12 @@ import org.jf.smali.smaliTreeWalker
import java.io.InputStreamReader import java.io.InputStreamReader
private const val METHOD_TEMPLATE = """ private const val METHOD_TEMPLATE = """
.class LInlineCompiler; .class LInlineCompiler;
.super Ljava/lang/Object; .super Ljava/lang/Object;
.method %s dummyMethod(%s)V .method %s dummyMethod(%s)V
.registers %d .registers %d
%s %s
.end method .end method
""" """
class InlineSmaliCompiler { class InlineSmaliCompiler {
@@ -32,13 +34,11 @@ class InlineSmaliCompiler {
* be messed up and results in broken Dalvik bytecode. * be messed up and results in broken Dalvik bytecode.
* FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter]. * FIXME: Fix the above issue. When this is fixed, add the proper conversions in [InstructionConverter].
*/ */
fun compileMethodInstructions( fun compile(
instructions: String, instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
parameters: String,
registers: Int,
forStaticMethod: Boolean
): List<BuilderInstruction> { ): List<BuilderInstruction> {
val input = METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions) val input =
METHOD_TEMPLATE.format(if (forStaticMethod) "static" else "", parameters, registers, instructions)
val reader = InputStreamReader(input.byteInputStream()) val reader = InputStreamReader(input.byteInputStream())
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15) val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
val tokens = CommonTokenStream(lexer as TokenSource) val tokens = CommonTokenStream(lexer as TokenSource)
@@ -59,8 +59,20 @@ class InlineSmaliCompiler {
} }
} }
fun String.toInstructions(parameters: String = "", registers: Int = 1, forStaticMethod: Boolean = true) = /**
InlineSmaliCompiler.compileMethodInstructions(this, parameters, registers, forStaticMethod) * Compile lines of Smali code to a list of instructions.
* @param templateMethod The method to compile the instructions against.
* @returns A list of instructions.
*/
fun String.toInstructions(templateMethod: Method? = null) = InlineSmaliCompiler.compile(this,
templateMethod?.parameters?.joinToString("") { it } ?: "",
templateMethod?.implementation?.registerCount ?: 1,
templateMethod?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true
)
fun String.toInstruction(parameters: String = "", registers: Int = 1, forStaticMethod: Boolean = true) = /**
this.toInstructions(parameters, registers, forStaticMethod).first() * Compile a line of Smali code to an instruction.
* @param templateMethod The method to compile the instructions against.
* @return The instruction.
*/
fun String.toInstruction(templateMethod: Method? = null) = this.toInstructions(templateMethod).first()

View File

@@ -15,7 +15,6 @@ import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibili
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstruction import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patcher.util.smali.toInstructions
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Format import org.jf.dexlib2.Format
@@ -47,7 +46,7 @@ class ExampleBytecodePatch : BytecodePatch(
// You can treat it as a constructor // You can treat it as a constructor
override fun execute(data: BytecodeData): PatchResult { override fun execute(data: BytecodeData): PatchResult {
// Get the resolved method for the signature from the resolver cache // Get the resolved method for the signature from the resolver cache
val result = signatures.first().result!! val result = ExampleSignature.result!!
// Get the implementation for the resolved method // Get the implementation for the resolved method
val implementation = result.method.implementation!! val implementation = result.method.implementation!!
@@ -126,8 +125,8 @@ class ExampleBytecodePatch : BytecodePatch(
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String; invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
move-result-object v1 move-result-object v1
invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
""".trimIndent().toInstructions() """
implementation.addInstructions(startIndex + 2, instructions) result.method.addInstructions(startIndex + 2, instructions)
// Finally, tell the patcher that this patch was a success. // Finally, tell the patcher that this patch was a success.
// You can also return PatchResultError with a message. // You can also return PatchResultError with a message.