Compare commits

..

45 Commits

Author SHA1 Message Date
semantic-release-bot
847e384d9e chore(release): 3.1.2-dev.1 [skip ci]
## [3.1.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.1...v3.1.2-dev.1) (2023-09-12)

### Bug Fixes

* Log correct options command ([#262](https://github.com/ReVanced/revanced-cli/issues/262)) ([96c196d](96c196dcb1))
2023-09-12 17:17:00 +00:00
Sharun
96c196dcb1 fix: Log correct options command (#262) 2023-09-12 19:15:21 +02:00
semantic-release-bot
dfd535c201 chore(release): 3.1.1 [skip ci]
## [3.1.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.0...v3.1.1) (2023-09-09)

### Bug Fixes

* Create options if it does not exist when updating them ([ca809f0](ca809f0948))
2023-09-09 15:26:51 +00:00
oSumAtrIX
2b6051e7f3 chore: merge branch dev to main (#259) 2023-09-09 17:25:04 +02:00
semantic-release-bot
0304988733 chore(release): 3.1.1-dev.1 [skip ci]
## [3.1.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.0...v3.1.1-dev.1) (2023-09-03)

### Bug Fixes

* Create options if it does not exist when updating them ([ca809f0](ca809f0948))
2023-09-03 20:42:58 +00:00
oSumAtrIX
ca809f0948 fix: Create options if it does not exist when updating them
Previously, the file could not be read to be updated. If the file does not exist, simply serialize the options to the file.
2023-09-03 22:41:20 +02:00
semantic-release-bot
5d50d1a622 chore(release): 3.1.0 [skip ci]
# [3.1.0](https://github.com/ReVanced/revanced-cli/compare/v3.0.1...v3.1.0) (2023-08-31)

### Bug Fixes

* check for package compatibility at first ([9fe5a0b](9fe5a0b6d9))
* do not filter explicitly included patches ([a3d8f00](a3d8f004ec))
* format patches input ([bbb1a63](bbb1a63abd))

### Features

* Simplify command description ([3b3f7c7](3b3f7c7a7a))
2023-08-31 20:32:08 +00:00
oSumAtrIX
83c28d9f71 chore: merge branch dev to main (#255) 2023-08-31 22:30:35 +02:00
semantic-release-bot
93cbcc28aa chore(release): 3.1.0-dev.1 [skip ci]
# [3.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.2-dev.2...v3.1.0-dev.1) (2023-08-28)

### Bug Fixes

* format patches input ([bbb1a63](bbb1a63abd))

### Features

* Simplify command description ([3b3f7c7](3b3f7c7a7a))
2023-08-28 18:18:56 +00:00
oSumAtrIX
3b3f7c7a7a feat: Simplify command description 2023-08-28 20:17:12 +02:00
oSumAtrIX
bbb1a63abd fix: format patches input
Previously you could not use the original patches names because they were formatted but not the input
2023-08-28 20:16:00 +02:00
semantic-release-bot
f7fcbc55bb chore(release): 3.0.2-dev.2 [skip ci]
## [3.0.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v3.0.2-dev.1...v3.0.2-dev.2) (2023-08-28)

### Bug Fixes

* check for package compatibility at first ([9fe5a0b](9fe5a0b6d9))
2023-08-28 16:38:55 +00:00
oSumAtrIX
9fe5a0b6d9 fix: check for package compatibility at first 2023-08-28 18:37:11 +02:00
semantic-release-bot
4f2d2568d3 chore(release): 3.0.2-dev.1 [skip ci]
## [3.0.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.1...v3.0.2-dev.1) (2023-08-28)

### Bug Fixes

* do not filter explicitly included patches ([a3d8f00](a3d8f004ec))
2023-08-28 15:59:00 +00:00
semantic-release-bot
a3d8f004ec fix: do not filter explicitly included patches 2023-08-28 17:56:47 +02:00
semantic-release-bot
41ffc99ad0 chore(release): 3.0.1 [skip ci]
## [3.0.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.0...v3.0.1) (2023-08-28)
2023-08-28 13:23:57 +00:00
oSumAtrIX
1121376018 chore: merge branch dev to main (#254) 2023-08-28 15:21:55 +02:00
semantic-release-bot
48e1689223 chore(release): 3.0.1-dev.1 [skip ci]
## [3.0.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.0...v3.0.1-dev.1) (2023-08-28)
2023-08-28 13:18:00 +00:00
oSumAtrIX
7580f5c2fc build(Needs bump): bump dependencies
This fixes an issue with flagging the resource table with sparse incorrectly.
2023-08-28 15:14:53 +02:00
semantic-release-bot
dd6c1392eb chore(release): 3.0.0 [skip ci]
# [3.0.0](https://github.com/ReVanced/revanced-cli/compare/v2.22.0...v3.0.0) (2023-08-26)

### Bug Fixes

* also delete temporary files when uninstalling ([52c3be2](52c3be23f2))
* delete temporary files after root installation ([a3d8705](a3d8705e89))
* do not delete output file ([0f3e090](0f3e090418))
* do not use absolute path from custom AAPT2 binary option ([a9c2a5f](a9c2a5f096))
* filtration of patches malfunctioning ([2d5a7fd](2d5a7fdf1e))
* fix running commands not running ([2c7fcaf](2c7fcaf4ad))
* only check once for patch options ([11c3a6c](11c3a6cfd4))
* print original instead of kebab cased names ([5eaad33](5eaad33dc1))
* print stack trace when a patch failed ([924c1f8](924c1f80ec))
* specify correct class containing entry-point ([1fcc591](1fcc591222))
* use correct option name ([f8972ea](f8972eac3e))

* refactor!: restructure code ([07da528](07da528ce2))

### Features

* add install command ([0350b7f](0350b7f1a2))
* add options command ([9edbbf3](9edbbf3163))
* Check for missing integrations ([c93186f](c93186fb97))
* Improve command line argument descriptions ([f9cf7d2](f9cf7d21b7))
* properly make use of logging facade ([41898d7](41898d7547))
* show full package name when listing patches ([#240](https://github.com/ReVanced/revanced-cli/issues/240)) ([7174364](7174364ef8))
* use better logging text ([b0e748d](b0e748daff))
* use friendly descriptions ([3dd875d](3dd875d14c))
* use separate command to list patches ([b74213f](b74213f66e))
* use separate command to patch ([32da961](32da961d57))
* use separate command to uninstall ([c0cc909](c0cc909626))
* use simpler log ([ba758f0](ba758f00f4))

### BREAKING CHANGES

* This introduces major changes to how ReVanced CLI is used from the command line.
2023-08-26 23:23:34 +00:00
oSumAtrIX
2a3dbafd17 chore: merge branch dev to main (#236) 2023-08-27 01:21:45 +02:00
semantic-release-bot
9e39a6f8e4 chore(release): 3.0.0-dev.10 [skip ci]
# [3.0.0-dev.10](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.9...v3.0.0-dev.10) (2023-08-25)

### Bug Fixes

* filtration of patches malfunctioning ([2d5a7fd](2d5a7fdf1e))
2023-08-25 21:48:59 +00:00
oSumAtrIX
2d5a7fdf1e fix: filtration of patches malfunctioning
Apparently, you were not able to include patches explicitly
2023-08-25 23:47:18 +02:00
semantic-release-bot
be5d812dff chore(release): 3.0.0-dev.9 [skip ci]
# [3.0.0-dev.9](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.8...v3.0.0-dev.9) (2023-08-25)

### Features

* Check for missing integrations ([c93186f](c93186fb97))
2023-08-25 00:28:57 +00:00
oSumAtrIX
c93186fb97 feat: Check for missing integrations
Check, if the integrations file exists at first.
2023-08-25 02:26:38 +02:00
semantic-release-bot
3a198052bb chore(release): 3.0.0-dev.8 [skip ci]
# [3.0.0-dev.8](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.7...v3.0.0-dev.8) (2023-08-24)

### Bug Fixes

* do not delete output file ([0f3e090](0f3e090418))
2023-08-24 23:32:29 +00:00
oSumAtrIX
0f3e090418 fix: do not delete output file
This fixes the output file to be deleted when the option `--purge` was used.
2023-08-25 01:30:28 +02:00
semantic-release-bot
6aed946183 chore(release): 3.0.0-dev.7 [skip ci]
# [3.0.0-dev.7](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.6...v3.0.0-dev.7) (2023-08-24)

### Bug Fixes

* print stack trace when a patch failed ([924c1f8](924c1f80ec))
2023-08-24 21:47:17 +00:00
oSumAtrIX
924c1f80ec fix: print stack trace when a patch failed 2023-08-24 23:45:10 +02:00
semantic-release-bot
8dd709b6ef chore(release): 3.0.0-dev.6 [skip ci]
# [3.0.0-dev.6](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.5...v3.0.0-dev.6) (2023-08-24)
2023-08-24 16:11:51 +00:00
oSumAtrIX
139e7facac build(Needs bump): depend on build task when publishing
This fixes the issue that no builds are generated
2023-08-24 18:09:35 +02:00
semantic-release-bot
1d26e572f7 chore(release): 3.0.0-dev.5 [skip ci]
# [3.0.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.4...v3.0.0-dev.5) (2023-08-24)

### Bug Fixes

* also delete temporary files when uninstalling ([52c3be2](52c3be23f2))
* delete temporary files after root installation ([a3d8705](a3d8705e89))
* fix running commands not running ([2c7fcaf](2c7fcaf4ad))
* only check once for patch options ([11c3a6c](11c3a6cfd4))

### Features

* add install command ([0350b7f](0350b7f1a2))
* use friendly descriptions ([3dd875d](3dd875d14c))
2023-08-24 15:53:09 +00:00
oSumAtrIX
2c7fcaf4ad fix: fix running commands not running 2023-08-24 17:51:31 +02:00
oSumAtrIX
52c3be23f2 fix: also delete temporary files when uninstalling 2023-08-24 16:54:08 +02:00
oSumAtrIX
3dd875d14c feat: use friendly descriptions 2023-08-24 16:53:31 +02:00
oSumAtrIX
0350b7f1a2 feat: add install command
This introduces a separate utility subcommand.
2023-08-24 16:50:10 +02:00
oSumAtrIX
a3d8705e89 fix: delete temporary files after root installation 2023-08-24 16:24:33 +02:00
oSumAtrIX
a536c9f815 refactor: use better identifiers 2023-08-24 16:24:18 +02:00
oSumAtrIX
11c3a6cfd4 fix: only check once for patch options
This prevents checking for the same patches options multiple times when it is already determined to not have any options
2023-08-24 15:52:12 +02:00
oSumAtrIX
a5851f0c1a build: clean after building 2023-08-24 15:35:27 +02:00
oSumAtrIX
963ae3a5fa docs: add missing inline docs 2023-08-24 15:35:27 +02:00
semantic-release-bot
93f338a731 chore(release): 3.0.0-dev.4 [skip ci]
# [3.0.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.3...v3.0.0-dev.4) (2023-08-24)

### Features

* properly make use of logging facade ([41898d7](41898d7547))
2023-08-24 02:56:08 +00:00
oSumAtrIX
7dcf15e03b build: bump dependencies 2023-08-24 04:52:53 +02:00
oSumAtrIX
41898d7547 feat: properly make use of logging facade 2023-08-24 04:41:44 +02:00
oSumAtrIX
45dd15f679 build: do not use a daemon when building
This decreases build times
2023-08-23 16:43:57 +02:00
23 changed files with 515 additions and 385 deletions

View File

@@ -33,10 +33,11 @@ jobs:
build build
node_modules node_modules
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }} key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
- name: Build with Gradle - name: Build
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build # Cleaning is necessary to avoid uploading two identical artifacts with different versions
run: ./gradlew clean --no-daemon
- name: Setup semantic-release - name: Setup semantic-release
run: npm install run: npm install
- name: Release - name: Release

View File

@@ -1,3 +1,162 @@
## [3.1.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.1...v3.1.2-dev.1) (2023-09-12)
### Bug Fixes
* Log correct options command ([#262](https://github.com/ReVanced/revanced-cli/issues/262)) ([96c196d](https://github.com/ReVanced/revanced-cli/commit/96c196dcb14e37ad91b751af61ee8382547c1ca3))
## [3.1.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.0...v3.1.1) (2023-09-09)
### Bug Fixes
* Create options if it does not exist when updating them ([ca809f0](https://github.com/ReVanced/revanced-cli/commit/ca809f0948379e3a825f24d7a49aba8b6b8767d1))
## [3.1.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.1.0...v3.1.1-dev.1) (2023-09-03)
### Bug Fixes
* Create options if it does not exist when updating them ([ca809f0](https://github.com/ReVanced/revanced-cli/commit/ca809f0948379e3a825f24d7a49aba8b6b8767d1))
# [3.1.0](https://github.com/ReVanced/revanced-cli/compare/v3.0.1...v3.1.0) (2023-08-31)
### Bug Fixes
* check for package compatibility at first ([9fe5a0b](https://github.com/ReVanced/revanced-cli/commit/9fe5a0b6d93304f630436ed0e954723d9a27b0f6))
* do not filter explicitly included patches ([a3d8f00](https://github.com/ReVanced/revanced-cli/commit/a3d8f004ec405f696d99d96c74ca41b573ecf425))
* format patches input ([bbb1a63](https://github.com/ReVanced/revanced-cli/commit/bbb1a63abd80dcbecdcf362158c0429cf3e6318f))
### Features
* Simplify command description ([3b3f7c7](https://github.com/ReVanced/revanced-cli/commit/3b3f7c7a7a7b2795e3d1fad776f6b457f2e68c7b))
# [3.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.2-dev.2...v3.1.0-dev.1) (2023-08-28)
### Bug Fixes
* format patches input ([bbb1a63](https://github.com/ReVanced/revanced-cli/commit/bbb1a63abd80dcbecdcf362158c0429cf3e6318f))
### Features
* Simplify command description ([3b3f7c7](https://github.com/ReVanced/revanced-cli/commit/3b3f7c7a7a7b2795e3d1fad776f6b457f2e68c7b))
## [3.0.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v3.0.2-dev.1...v3.0.2-dev.2) (2023-08-28)
### Bug Fixes
* check for package compatibility at first ([9fe5a0b](https://github.com/ReVanced/revanced-cli/commit/9fe5a0b6d93304f630436ed0e954723d9a27b0f6))
## [3.0.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.1...v3.0.2-dev.1) (2023-08-28)
### Bug Fixes
* do not filter explicitly included patches ([a3d8f00](https://github.com/ReVanced/revanced-cli/commit/a3d8f004ec405f696d99d96c74ca41b573ecf425))
## [3.0.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.0...v3.0.1) (2023-08-28)
## [3.0.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v3.0.0...v3.0.1-dev.1) (2023-08-28)
# [3.0.0](https://github.com/ReVanced/revanced-cli/compare/v2.22.0...v3.0.0) (2023-08-26)
### Bug Fixes
* also delete temporary files when uninstalling ([52c3be2](https://github.com/ReVanced/revanced-cli/commit/52c3be23f2915dccaee7f9941413c8f81e14acc8))
* delete temporary files after root installation ([a3d8705](https://github.com/ReVanced/revanced-cli/commit/a3d8705e89732a0dd4f51de28c405b6af13c8633))
* do not delete output file ([0f3e090](https://github.com/ReVanced/revanced-cli/commit/0f3e090418771e951dfd15e5c193421f72cbe459))
* do not use absolute path from custom AAPT2 binary option ([a9c2a5f](https://github.com/ReVanced/revanced-cli/commit/a9c2a5f096627dbbf8ab1b8da26fb14529ce6bc3))
* filtration of patches malfunctioning ([2d5a7fd](https://github.com/ReVanced/revanced-cli/commit/2d5a7fdf1eb2e13f5013a790b03f09851b167fe0))
* fix running commands not running ([2c7fcaf](https://github.com/ReVanced/revanced-cli/commit/2c7fcaf4add65a12052afc5bef779dbc73debd69))
* only check once for patch options ([11c3a6c](https://github.com/ReVanced/revanced-cli/commit/11c3a6cfd4fe59ba5d703358634a1853e1cc22a5))
* print original instead of kebab cased names ([5eaad33](https://github.com/ReVanced/revanced-cli/commit/5eaad33dc1fbd24c36e1498f04e21d068e85f53e))
* print stack trace when a patch failed ([924c1f8](https://github.com/ReVanced/revanced-cli/commit/924c1f80ec0d17a3bdc07a0fb2015e44c49162e4))
* specify correct class containing entry-point ([1fcc591](https://github.com/ReVanced/revanced-cli/commit/1fcc591222ab67112f2b78174a8b94106846838c))
* use correct option name ([f8972ea](https://github.com/ReVanced/revanced-cli/commit/f8972eac3e5ee0a4a186c12cbe711925656d657b))
* refactor!: restructure code ([07da528](https://github.com/ReVanced/revanced-cli/commit/07da528ce2223582f84bf64d2fec69714c647ddc))
### Features
* add install command ([0350b7f](https://github.com/ReVanced/revanced-cli/commit/0350b7f1a276d9dc795b22442ba4f202855ea090))
* add options command ([9edbbf3](https://github.com/ReVanced/revanced-cli/commit/9edbbf31635603f89fc7bc5dcc6c023d4cdbb5a6))
* Check for missing integrations ([c93186f](https://github.com/ReVanced/revanced-cli/commit/c93186fb9700907e65f33442e88073783cc163de))
* Improve command line argument descriptions ([f9cf7d2](https://github.com/ReVanced/revanced-cli/commit/f9cf7d21b7f1c2f11234d604a1047b9d2b165f83))
* properly make use of logging facade ([41898d7](https://github.com/ReVanced/revanced-cli/commit/41898d7547690e3130372414515c5645e5dc2634))
* show full package name when listing patches ([#240](https://github.com/ReVanced/revanced-cli/issues/240)) ([7174364](https://github.com/ReVanced/revanced-cli/commit/7174364ef8ef5d6ce8351a8340f9c1a5b58eac3c))
* use better logging text ([b0e748d](https://github.com/ReVanced/revanced-cli/commit/b0e748daff527ee7f417b3069882e074896fc131))
* use friendly descriptions ([3dd875d](https://github.com/ReVanced/revanced-cli/commit/3dd875d14cca488ade6d21bbd4cce0d481692134))
* use separate command to list patches ([b74213f](https://github.com/ReVanced/revanced-cli/commit/b74213f66e0d04d3a0ae6197d069631388e06580))
* use separate command to patch ([32da961](https://github.com/ReVanced/revanced-cli/commit/32da961d57537e99b39fd92b625a1c73f8314bc6))
* use separate command to uninstall ([c0cc909](https://github.com/ReVanced/revanced-cli/commit/c0cc90962646cfffd5e2730ae556423271a7990b))
* use simpler log ([ba758f0](https://github.com/ReVanced/revanced-cli/commit/ba758f00f4ce18791439b7e72fe1ad2e7f11f8af))
### BREAKING CHANGES
* This introduces major changes to how ReVanced CLI is used from the command line.
# [3.0.0-dev.10](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.9...v3.0.0-dev.10) (2023-08-25)
### Bug Fixes
* filtration of patches malfunctioning ([2d5a7fd](https://github.com/ReVanced/revanced-cli/commit/2d5a7fdf1eb2e13f5013a790b03f09851b167fe0))
# [3.0.0-dev.9](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.8...v3.0.0-dev.9) (2023-08-25)
### Features
* Check for missing integrations ([c93186f](https://github.com/ReVanced/revanced-cli/commit/c93186fb9700907e65f33442e88073783cc163de))
# [3.0.0-dev.8](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.7...v3.0.0-dev.8) (2023-08-24)
### Bug Fixes
* do not delete output file ([0f3e090](https://github.com/ReVanced/revanced-cli/commit/0f3e090418771e951dfd15e5c193421f72cbe459))
# [3.0.0-dev.7](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.6...v3.0.0-dev.7) (2023-08-24)
### Bug Fixes
* print stack trace when a patch failed ([924c1f8](https://github.com/ReVanced/revanced-cli/commit/924c1f80ec0d17a3bdc07a0fb2015e44c49162e4))
# [3.0.0-dev.6](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.5...v3.0.0-dev.6) (2023-08-24)
# [3.0.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.4...v3.0.0-dev.5) (2023-08-24)
### Bug Fixes
* also delete temporary files when uninstalling ([52c3be2](https://github.com/ReVanced/revanced-cli/commit/52c3be23f2915dccaee7f9941413c8f81e14acc8))
* delete temporary files after root installation ([a3d8705](https://github.com/ReVanced/revanced-cli/commit/a3d8705e89732a0dd4f51de28c405b6af13c8633))
* fix running commands not running ([2c7fcaf](https://github.com/ReVanced/revanced-cli/commit/2c7fcaf4add65a12052afc5bef779dbc73debd69))
* only check once for patch options ([11c3a6c](https://github.com/ReVanced/revanced-cli/commit/11c3a6cfd4fe59ba5d703358634a1853e1cc22a5))
### Features
* add install command ([0350b7f](https://github.com/ReVanced/revanced-cli/commit/0350b7f1a276d9dc795b22442ba4f202855ea090))
* use friendly descriptions ([3dd875d](https://github.com/ReVanced/revanced-cli/commit/3dd875d14cca488ade6d21bbd4cce0d481692134))
# [3.0.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.3...v3.0.0-dev.4) (2023-08-24)
### Features
* properly make use of logging facade ([41898d7](https://github.com/ReVanced/revanced-cli/commit/41898d7547690e3130372414515c5645e5dc2634))
# [3.0.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.2...v3.0.0-dev.3) (2023-08-23) # [3.0.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.2...v3.0.0-dev.3) (2023-08-23)
# [3.0.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.1...v3.0.0-dev.2) (2023-08-23) # [3.0.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v3.0.0-dev.1...v3.0.0-dev.2) (2023-08-23)

View File

@@ -52,5 +52,6 @@ tasks {
register<DefaultTask>("publish") { register<DefaultTask>("publish") {
group = "publish" group = "publish"
description = "Dummy task" description = "Dummy task"
dependsOn(build)
} }
} }

View File

@@ -86,12 +86,26 @@ Learn how to ReVanced CLI.
> **Note**: Some patches may require integrations > **Note**: Some patches may require integrations
such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations). such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations).
Supply them with the option `-m`. If any patches accepted by ReVanced Patcher require ReVanced Integrations, Supply them with the option `--merge`. If any patches accepted by ReVanced Patcher require ReVanced Integrations,
they will be merged into the APK file automatically. they will be merged into the APK file automatically.
- ### 🗑️ Uninstall a patched APK file - ### 🗑️ Uninstall a patched APK file
```bash ```bash
java -jar revanced-cli.jar uninstall \ java -jar revanced-cli.jar utility uninstall \
--package-name <package-name> \ --package-name <package-name> \
<device-serial> <device-serial>
``` ```
> **Note**: You can unmount an APK file
with the option `--unmount`.
- ### ⚙️ Manually install an APK file
```bash
java -jar revanced-cli.jar utility install \
-a input.apk \
<device-serial>
```
> **Note**: You can mount an APK file
by supplying the package name of the app to mount the supplied APK file to over the option `--mount`.

View File

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

View File

@@ -1,6 +1,6 @@
[versions] [versions]
shadow = "8.1.1" shadow = "8.1.1"
apksig = "8.1.0" apksig = "8.1.1"
bcpkix-jdk15on = "1.70" bcpkix-jdk15on = "1.70"
jackson-module-kotlin = "2.14.3" jackson-module-kotlin = "2.14.3"
jadb = "2531a28109" jadb = "2531a28109"
@@ -8,7 +8,7 @@ kotlin-reflect = "1.9.0"
kotlin-test = "1.8.20-RC" kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.1" kotlinx-coroutines-core = "1.7.1"
picocli = "4.7.3" picocli = "4.7.3"
revanced-patcher = "14.0.0" revanced-patcher = "14.2.1"
[libraries] [libraries]
apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" } apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" }

View File

@@ -11,43 +11,41 @@ import app.revanced.patcher.patch.PatchOption
import picocli.CommandLine.* import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File import java.io.File
import java.util.logging.Logger
@Command(name = "list-patches", description = ["List patches from supplied patch bundles"]) @Command(name = "list-patches", description = ["List patches from supplied patch bundles"])
internal object ListPatchesCommand : Runnable { internal object ListPatchesCommand : Runnable {
private val logger = Logger.getLogger(ListPatchesCommand::class.java.name)
@Parameters( @Parameters(
description = ["Paths to patch bundles"], description = ["Paths to patch bundles"], arity = "1..*"
arity = "1..*"
) )
lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@Option( @Option(
names = ["-d", "--with-descriptions"], names = ["-d", "--with-descriptions"], description = ["List their descriptions"], showDefaultValue = ALWAYS
description = ["List their descriptions"],
showDefaultValue = ALWAYS
) )
var withDescriptions: Boolean = true private var withDescriptions: Boolean = true
@Option( @Option(
names = ["-p", "--with-packages"], names = ["-p", "--with-packages"],
description = ["List the packages the patches are compatible with"], description = ["List the packages the patches are compatible with"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var withPackages: Boolean = false private var withPackages: Boolean = false
@Option( @Option(
names = ["-v", "--with-versions"], names = ["-v", "--with-versions"],
description = ["List the versions of the packages the patches are compatible with"], description = ["List the versions of the apps the patches are compatible with"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var withVersions: Boolean = false private var withVersions: Boolean = false
@Option( @Option(
names = ["-o", "--with-options"], names = ["-o", "--with-options"], description = ["List the options of the patches"], showDefaultValue = ALWAYS
description = ["List the options of the patches"],
showDefaultValue = ALWAYS
) )
var withOptions: Boolean = false private var withOptions: Boolean = false
override fun run() { override fun run() {
fun Package.buildString() = buildString { fun Package.buildString() = buildString {
@@ -55,8 +53,7 @@ internal object ListPatchesCommand : Runnable {
appendLine("Package name: $name") appendLine("Package name: $name")
appendLine("Compatible versions:") appendLine("Compatible versions:")
append(versions.joinToString("\n") { version -> version }.prependIndent("\t")) append(versions.joinToString("\n") { version -> version }.prependIndent("\t"))
} else } else append("Package name: $name")
append("Package name: $name")
} }
fun PatchOption<*>.buildString() = buildString { fun PatchOption<*>.buildString() = buildString {

View File

@@ -1,21 +1,48 @@
package app.revanced.cli.command package app.revanced.cli.command
import app.revanced.cli.logging.impl.DefaultCliLogger import app.revanced.cli.command.utility.UtilityCommand
import app.revanced.patcher.patch.PatchClass import app.revanced.patcher.patch.PatchClass
import picocli.CommandLine import picocli.CommandLine
import picocli.CommandLine.Command import picocli.CommandLine.Command
import picocli.CommandLine.IVersionProvider import picocli.CommandLine.IVersionProvider
import java.util.* import java.util.*
import java.util.logging.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
System.setProperty("java.util.logging.SimpleFormatter.format", "%4\$s: %5\$s %n")
Logger.getLogger("").apply {
handlers.forEach {
it.close()
removeHandler(it)
}
object : Handler() {
override fun publish(record: LogRecord) = formatter.format(record).toByteArray().let {
if (record.level.intValue() > Level.INFO.intValue())
System.err.write(it)
else
System.out.write(it)
}
override fun flush() {
System.out.flush()
System.err.flush()
}
override fun close() = flush()
}.also {
it.level = Level.ALL
it.formatter = SimpleFormatter()
}.let(::addHandler)
}
CommandLine(MainCommand).execute(*args) CommandLine(MainCommand).execute(*args)
} }
internal typealias PatchList = List<PatchClass> internal typealias PatchList = List<PatchClass>
internal val logger = DefaultCliLogger() private object CLIVersionProvider : IVersionProvider {
object CLIVersionProvider : IVersionProvider {
override fun getVersion(): Array<String> { override fun getVersion(): Array<String> {
Properties().apply { Properties().apply {
load(MainCommand::class.java.getResourceAsStream("/app/revanced/cli/version.properties")) load(MainCommand::class.java.getResourceAsStream("/app/revanced/cli/version.properties"))
@@ -33,8 +60,8 @@ object CLIVersionProvider : IVersionProvider {
subcommands = [ subcommands = [
ListPatchesCommand::class, ListPatchesCommand::class,
PatchCommand::class, PatchCommand::class,
UninstallCommand::class,
OptionsCommand::class, OptionsCommand::class,
UtilityCommand::class,
] ]
) )
internal object MainCommand private object MainCommand

View File

@@ -6,45 +6,41 @@ import app.revanced.utils.Options.setOptions
import picocli.CommandLine import picocli.CommandLine
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File import java.io.File
import java.util.logging.Logger
@CommandLine.Command( @CommandLine.Command(
name = "options", name = "options",
description = ["Generate options file from patches"], description = ["Generate options file from patches"],
) )
internal object OptionsCommand : Runnable { internal object OptionsCommand : Runnable {
private val logger = Logger.getLogger(OptionsCommand::class.java.name)
@CommandLine.Parameters( @CommandLine.Parameters(
description = ["Paths to patch bundles"], description = ["Paths to patch bundles"], arity = "1..*"
arity = "1..*"
) )
lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@CommandLine.Option( @CommandLine.Option(
names = ["-p", "--path"], names = ["-p", "--path"], description = ["Path to patch options JSON file"], showDefaultValue = ALWAYS
description = ["Path to patch options JSON file"],
showDefaultValue = ALWAYS
) )
var path: File = File("options.json") private var filePath: File = File("options.json")
@CommandLine.Option( @CommandLine.Option(
names = ["-o", "--overwrite"], names = ["-o", "--overwrite"], description = ["Overwrite existing options file"], showDefaultValue = ALWAYS
description = ["Overwrite existing options file"],
showDefaultValue = ALWAYS
) )
var overwrite: Boolean = false private var overwrite: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["-u", "--update"], names = ["-u", "--update"],
description = ["Update existing options by adding missing and removing non-existent options"], description = ["Update existing options by adding missing and removing non-existent options"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var update: Boolean = false private var update: Boolean = false
override fun run() = if (!path.exists() || overwrite) override fun run() = if (!filePath.exists() || overwrite) with(PatchBundleLoader.Jar(*patchBundles)) {
with(PatchBundleLoader.Jar(*patchBundles)) { if (update && filePath.exists()) setOptions(filePath)
if (update) setOptions(path, logger)
Options.serialize(this, prettyPrint = true) Options.serialize(this, prettyPrint = true).let(filePath::writeText)
.let(path::writeText)
} }
else logger.error("Options file already exists, use --override to override it") else logger.severe("Options file already exists, use --overwrite to override it")
} }

View File

@@ -1,6 +1,5 @@
package app.revanced.cli.command package app.revanced.cli.command
import app.revanced.cli.patcher.logging.impl.PatcherLogger
import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherOptions
@@ -20,85 +19,75 @@ import kotlinx.coroutines.runBlocking
import picocli.CommandLine import picocli.CommandLine
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import java.util.logging.Logger
@CommandLine.Command( @CommandLine.Command(
name = "patch", name = "patch", description = ["Patch an APK file"]
description = ["Patch the supplied APK file with the supplied patches and integrations"]
) )
internal object PatchCommand: Runnable { internal object PatchCommand : Runnable {
private val logger = Logger.getLogger(PatchCommand::class.java.name)
@CommandLine.Parameters( @CommandLine.Parameters(
description = ["APK file to be patched"], description = ["APK file to be patched"], arity = "1..1"
arity = "1..1"
) )
lateinit var apk: File private lateinit var apk: File
@CommandLine.Option( @CommandLine.Option(
names = ["-b", "--patch-bundle"], names = ["-b", "--patch-bundle"], description = ["One or more bundles of patches"], required = true
description = ["One or more bundles of patches"],
required = true
) )
var patchBundles = emptyList<File>() private var patchBundles = emptyList<File>()
@CommandLine.Option( @CommandLine.Option(
names = ["-m", "--merge"], names = ["-m", "--merge"], description = ["One or more DEX files or containers to merge into the APK"]
description = ["One or more DEX files or containers to merge into the APK"]
) )
var integrations = listOf<File>() private var integrations = listOf<File>()
@CommandLine.Option( @CommandLine.Option(
names = ["-i", "--include"], names = ["-i", "--include"], description = ["List of patches to include"]
description = ["List of patches to include"]
) )
var includedPatches = arrayOf<String>() private var includedPatches = arrayOf<String>()
@CommandLine.Option( @CommandLine.Option(
names = ["-e", "--exclude"], names = ["-e", "--exclude"], description = ["List of patches to exclude"]
description = ["List of patches to exclude"]
) )
var excludedPatches = arrayOf<String>() private var excludedPatches = arrayOf<String>()
@CommandLine.Option( @CommandLine.Option(
names = ["--options"], names = ["--options"], description = ["Path to patch options JSON file"], showDefaultValue = ALWAYS
description = ["Path to patch options JSON file"],
showDefaultValue = ALWAYS
) )
var optionsFile: File = File("options.json") private var optionsFile: File = File("options.json")
@CommandLine.Option( @CommandLine.Option(
names = ["--exclusive"], names = ["--exclusive"],
description = ["Only include patches that are explicitly specified to be included"], description = ["Only include patches that are explicitly specified to be included"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var exclusive = false private var exclusive = false
@CommandLine.Option( @CommandLine.Option(
names = ["--experimental"], names = ["-f","--force"],
description = ["Ignore patches incompatibility to versions"], description = ["Force inclusion of patches that are incompatible with the supplied APK file's version"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var experimental: Boolean = false private var force: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["-o", "--out"], names = ["-o", "--out"], description = ["Path to save the patched APK file to"], required = true
description = ["Path to save the patched APK file to"],
required = true
) )
lateinit var outputFilePath: File private lateinit var outputFilePath: File
@CommandLine.Option( @CommandLine.Option(
names = ["-d", "--device-serial"], names = ["-d", "--device-serial"], description = ["ADB device serial to install to"], showDefaultValue = ALWAYS
description = ["ADB device serial to install to"],
showDefaultValue = ALWAYS
) )
var deviceSerial: String? = null private var deviceSerial: String? = null
@CommandLine.Option( @CommandLine.Option(
names = ["--mount"], names = ["--mount"], description = ["Install by mounting the patched APK file"], showDefaultValue = ALWAYS
description = ["Install by mounting the patched package"],
showDefaultValue = ALWAYS
) )
var mount: Boolean = false private var mount: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["--common-name"], names = ["--common-name"],
@@ -106,53 +95,57 @@ internal object PatchCommand: Runnable {
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var commonName = "ReVanced" private var commonName = "ReVanced"
@CommandLine.Option( @CommandLine.Option(
names = ["--keystore"], names = ["--keystore"], description = ["Path to the keystore to sign the patched APK file with"]
description = ["Path to the keystore to sign the patched APK file with"]
) )
var keystorePath: String? = null private var keystorePath: String? = null
@CommandLine.Option( @CommandLine.Option(
names = ["--password"], names = ["--password"], description = ["The password of the keystore to sign the patched APK file with"]
description = ["The password of the keystore to sign the patched APK file with"]
) )
var password = "ReVanced" private var password = "ReVanced"
@CommandLine.Option( @CommandLine.Option(
names = ["-r", "--resource-cache"], names = ["-r", "--resource-cache"],
description = ["Path to temporary resource cache directory"], description = ["Path to temporary resource cache directory"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var resourceCachePath = File("revanced-resource-cache") private var resourceCachePath = File("revanced-resource-cache")
@CommandLine.Option( @CommandLine.Option(
names = ["--custom-aapt2-binary"], names = ["--custom-aapt2-binary"], description = ["Path to a custom AAPT binary to compile resources with"]
description = ["Path to a custom AAPT binary to compile resources with"]
) )
var aaptBinaryPath = File("") private var aaptBinaryPath = File("")
@CommandLine.Option( @CommandLine.Option(
names = ["-p", "--purge"], names = ["-p", "--purge"],
description = ["Purge the temporary resource cache directory after patching"], description = ["Purge the temporary resource cache directory after patching"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS
) )
var purge: Boolean = false private var purge: Boolean = false
override fun run() { override fun run() {
// region Prepare // region Prepare
if (!apk.exists()) { if (!apk.exists()) {
logger.error("Input file ${apk.name} does not exist") logger.severe("APK file ${apk.name} does not exist")
return
}
integrations.filter { !it.exists() }.let {
if (it.isEmpty()) return@let
it.forEach { integration ->
logger.severe("Integration file ${integration.name} does not exist")
}
return return
} }
val adbManager = deviceSerial?.let { serial -> val adbManager = deviceSerial?.let { serial ->
if (mount) AdbManager.RootAdbManager(serial, logger) else AdbManager.UserAdbManager( if (mount) AdbManager.RootAdbManager(serial)
serial, else AdbManager.UserAdbManager(serial)
logger
)
} }
// endregion // endregion
@@ -167,7 +160,7 @@ internal object PatchCommand: Runnable {
logger.info("Setting patch options") logger.info("Setting patch options")
optionsFile.let { optionsFile.let {
if (it.exists()) patches.setOptions(it, logger) if (it.exists()) patches.setOptions(it)
else Options.serialize(patches, prettyPrint = true).let(it::writeText) else Options.serialize(patches, prettyPrint = true).let(it::writeText)
} }
@@ -181,7 +174,6 @@ internal object PatchCommand: Runnable {
resourceCachePath, resourceCachePath,
aaptBinaryPath.path, aaptBinaryPath.path,
resourceCachePath.absolutePath, resourceCachePath.absolutePath,
PatcherLogger
) )
) )
@@ -193,7 +185,10 @@ internal object PatchCommand: Runnable {
runBlocking { runBlocking {
apply(false).collect { patchResult -> apply(false).collect { patchResult ->
patchResult.exception?.let { patchResult.exception?.let {
logger.error("${patchResult.patchName} failed:\n${patchResult.exception}") StringWriter().use { writer ->
it.printStackTrace(PrintWriter(writer))
logger.severe("${patchResult.patchName} failed: $writer")
}
} ?: logger.info("${patchResult.patchName} succeeded") } ?: logger.info("${patchResult.patchName} succeeded")
} }
} }
@@ -207,8 +202,7 @@ internal object PatchCommand: Runnable {
val alignAndSignedFile = sign( val alignAndSignedFile = sign(
apk.newAlignedFile( apk.newAlignedFile(
result, result, resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_aligned.apk")
resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_aligned.apk")
) )
) )
@@ -219,7 +213,6 @@ internal object PatchCommand: Runnable {
if (purge) { if (purge) {
logger.info("Purging temporary files") logger.info("Purging temporary files")
outputFilePath.delete()
purge(resourceCachePath) purge(resourceCachePath)
} }
@@ -232,104 +225,59 @@ internal object PatchCommand: Runnable {
* - [includedPatches] (explicitly included) * - [includedPatches] (explicitly included)
* - [excludedPatches] (explicitly excluded) * - [excludedPatches] (explicitly excluded)
* - [exclusive] (only include patches that are explicitly included) * - [exclusive] (only include patches that are explicitly included)
* - [experimental] (ignore patches incompatibility to versions) * - [force] (ignore patches incompatibility to versions)
* - package name and version of the input APK file (if [experimental] is false) * - Package name and version of the input APK file (if [force] is false)
* *
* @param patches The patches to filter. * @param patches The patches to filter.
* @return The filtered patches. * @return The filtered patches.
*/ */
private fun Patcher.filterPatchSelection(patches: PatchList) = buildList { private fun Patcher.filterPatchSelection(patches: PatchList) = buildList {
// TODO: Remove this eventually because
// patches named "patch-name" and "patch name" will conflict.
fun String.format() = lowercase().replace(" ", "-")
val formattedExcludedPatches = excludedPatches.map { it.format() }
val formattedIncludedPatches = includedPatches.map { it.format() }
val packageName = context.packageMetadata.packageName val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion val packageVersion = context.packageMetadata.packageVersion
patches.forEach patch@{ patch -> patches.forEach patch@{ patch ->
val formattedPatchName = patch.patchName.lowercase().replace(" ", "-") val formattedPatchName = patch.patchName.format()
/** val explicitlyExcluded = formattedExcludedPatches.contains(formattedPatchName)
* Check if the patch is explicitly excluded. if (explicitlyExcluded) return@patch logger.info("Excluding ${patch.patchName}")
*
* Cases:
* 1. -e patch.name
* 2. -i patch.name -e patch.name
*/
/**
* Check if the patch is explicitly excluded.
*
* Cases:
* 1. -e patch.name
* 2. -i patch.name -e patch.name
*/
val excluded = excludedPatches.contains(formattedPatchName)
if (excluded) return@patch logger.info("Excluding ${patch.patchName}")
/**
* Check if the patch is constrained to packages.
*/
/**
* Check if the patch is constrained to packages.
*/
// Make sure the patch is compatible with the supplied APK files package name and version.
patch.compatiblePackages?.let { packages -> patch.compatiblePackages?.let { packages ->
packages.singleOrNull { it.name == packageName }?.let { `package` -> packages.singleOrNull { it.name == packageName }?.let { `package` ->
/** val matchesVersion = force || `package`.versions.let {
* Check if the package version matches.
* If experimental is true, version matching will be skipped.
*/
/**
* Check if the package version matches.
* If experimental is true, version matching will be skipped.
*/
val matchesVersion = experimental || `package`.versions.let {
it.isEmpty() || it.any { version -> version == packageVersion } it.isEmpty() || it.any { version -> version == packageVersion }
} }
if (!matchesVersion) return@patch logger.warn( if (!matchesVersion) return@patch logger.warning(
"${patch.patchName} is incompatible with version $packageVersion. " + "${patch.patchName} is incompatible with version $packageVersion. "
"This patch is only compatible with version " + + "This patch is only compatible with version "
packages.joinToString(";") { pkg -> + packages.joinToString(";") { pkg ->
"${pkg.name}: ${pkg.versions.joinToString(", ")}" "${pkg.name}: ${pkg.versions.joinToString(", ")}"
} }
) )
} ?: return@patch logger.fine("${patch.patchName} is incompatible with $packageName. "
} ?: return@patch logger.trace( + "This patch is only compatible with "
"${patch.patchName} is incompatible with $packageName. " + + packages.joinToString(", ") { `package` -> `package`.name })
"This patch is only compatible with " +
packages.joinToString(", ") { `package` -> `package`.name }
)
return@let return@let
} ?: logger.trace("$formattedPatchName: No constraint on packages.") } ?: logger.fine("$formattedPatchName: No constraint on packages.")
/** // If the patch is implicitly included, it will be only included if [exclusive] is false.
* Check if the patch is explicitly included. val implicitlyIncluded = !exclusive && patch.include
* // If the patch is explicitly included, it will be included even if [exclusive] is false.
* Cases: val explicitlyIncluded = formattedIncludedPatches.contains(formattedPatchName)
* 1. --exclusive
* 2. --exclusive -i patch.name
*/
/** val included = implicitlyIncluded || explicitlyIncluded
* Check if the patch is explicitly included.
*
* Cases:
* 1. --exclusive
* 2. --exclusive -i patch.name
*/
val explicitlyIncluded = includedPatches.contains(formattedPatchName)
val implicitlyIncluded = !exclusive && patch.include // Case 3.
val exclusivelyIncluded = exclusive && explicitlyIncluded // Case 2.
val included = implicitlyIncluded || exclusivelyIncluded
if (!included) return@patch logger.info("${patch.patchName} excluded by default") // Case 1. if (!included) return@patch logger.info("${patch.patchName} excluded by default") // Case 1.
logger.trace("Adding $formattedPatchName") logger.fine("Adding $formattedPatchName")
add(patch) add(patch)
} }
@@ -342,8 +290,7 @@ internal object PatchCommand: Runnable {
* @param outputFile The file to save the aligned APK to. * @param outputFile The file to save the aligned APK to.
*/ */
private fun File.newAlignedFile( private fun File.newAlignedFile(
result: PatcherResult, result: PatcherResult, outputFile: File
outputFile: File
): File { ): File {
logger.info("Aligning $name") logger.info("Aligning $name")
@@ -352,23 +299,20 @@ internal object PatchCommand: Runnable {
ZipFile(outputFile).use { file -> ZipFile(outputFile).use { file ->
result.dexFiles.forEach { result.dexFiles.forEach {
file.addEntryCompressData( file.addEntryCompressData(
ZipEntry.createWithName(it.name), ZipEntry.createWithName(it.name), it.stream.readBytes()
it.stream.readBytes()
) )
} }
result.resourceFile?.let { result.resourceFile?.let {
file.copyEntriesFromFileAligned( file.copyEntriesFromFileAligned(
ZipFile(it), ZipFile(it), ZipAligner::getEntryAlignment
ZipAligner::getEntryAlignment
) )
} }
// TODO: Do not compress result.doNotCompress // TODO: Do not compress result.doNotCompress
file.copyEntriesFromFileAligned( file.copyEntriesFromFileAligned(
ZipFile(this), ZipFile(this), ZipAligner::getEntryAlignment
ZipAligner::getEntryAlignment
) )
} }
@@ -381,32 +325,25 @@ internal object PatchCommand: Runnable {
* @param inputFile The APK file to sign. * @param inputFile The APK file to sign.
* @return The signed APK file. If [mount] is true, the input file will be returned. * @return The signed APK file. If [mount] is true, the input file will be returned.
*/ */
private fun sign(inputFile: File) = if (mount) private fun sign(inputFile: File) = if (mount) inputFile
inputFile
else { else {
logger.info("Signing ${inputFile.name}") logger.info("Signing ${inputFile.name}")
val keyStoreFilePath = keystorePath ?: outputFilePath val keyStoreFilePath = keystorePath
.absoluteFile.parentFile.resolve("${outputFilePath.nameWithoutExtension}.keystore").canonicalPath ?: outputFilePath.absoluteFile.parentFile.resolve("${outputFilePath.nameWithoutExtension}.keystore").canonicalPath
val options = SigningOptions( val options = SigningOptions(
commonName, commonName, password, keyStoreFilePath
password,
keyStoreFilePath
) )
ApkSigner(options) ApkSigner(options).signApk(
.signApk( inputFile, resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_signed.apk")
inputFile,
resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_signed.apk")
) )
} }
private fun purge(resourceCachePath: File) { private fun purge(resourceCachePath: File) {
val result = if (resourceCachePath.deleteRecursively()) val result = if (resourceCachePath.deleteRecursively()) "Purged resource cache directory"
"Purged resource cache directory" else "Failed to purge resource cache directory"
else
"Failed to purge resource cache directory"
logger.info(result) logger.info(result)
} }
} }

View File

@@ -1,44 +0,0 @@
package app.revanced.cli.command
import app.revanced.utils.adb.AdbManager
import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS
@Command(
name = "uninstall",
description = ["Uninstall a patched APK file from the devices with the supplied ADB device serials"]
)
internal object UninstallCommand : Runnable {
@Parameters(
description = ["ADB device serials"],
arity = "1..*"
)
lateinit var deviceSerials: Array<String>
@Option(
names = ["-p", "--package-name"],
description = ["Package name to uninstall"],
required = true
)
lateinit var packageName: String
@Option(
names = ["-u", "--unmount"],
description = ["Uninstall by unmounting the patched package"],
showDefaultValue = ALWAYS
)
var unmount: Boolean = false
override fun run() = try {
deviceSerials.forEach {deviceSerial ->
if (unmount) {
AdbManager.RootAdbManager(deviceSerial, logger)
} else {
AdbManager.UserAdbManager(deviceSerial, logger)
}.uninstall(packageName)
}
} catch (e: AdbManager.DeviceNotFoundException) {
logger.error(e.toString())
}
}

View File

@@ -0,0 +1,42 @@
package app.revanced.cli.command.utility
import app.revanced.utils.adb.AdbManager
import picocli.CommandLine.*
import java.io.File
import java.util.logging.Logger
@Command(
name = "install", description = ["Install an APK file to devices with the supplied ADB device serials"]
)
internal object InstallCommand : Runnable {
private val logger = Logger.getLogger(InstallCommand::class.java.name)
@Parameters(
description = ["ADB device serials"], arity = "1..*"
)
private lateinit var deviceSerials: Array<String>
@Option(
names = ["-a", "--apk"], description = ["APK file to be installed"], required = true
)
private lateinit var apk: File
@Option(
names = ["-m", "--mount"],
description = ["Mount the supplied APK file over the app with the supplied package name"],
)
private var packageName: String? = null
override fun run() = try {
deviceSerials.forEach { deviceSerial ->
if (packageName != null) {
AdbManager.RootAdbManager(deviceSerial)
} else {
AdbManager.UserAdbManager(deviceSerial)
}.install(AdbManager.Apk(apk, packageName))
}
} catch (e: AdbManager.DeviceNotFoundException) {
logger.severe(e.toString())
}
}

View File

@@ -0,0 +1,40 @@
package app.revanced.cli.command.utility
import app.revanced.utils.adb.AdbManager
import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS
import java.util.logging.Logger
@Command(
name = "uninstall",
description = ["Uninstall a patched app from the devices with the supplied ADB device serials"]
)
internal object UninstallCommand : Runnable {
private val logger = Logger.getLogger(UninstallCommand::class.java.name)
@Parameters(description = ["ADB device serials"], arity = "1..*")
private lateinit var deviceSerials: Array<String>
@Option(names = ["-p", "--package-name"], description = ["Package name of the app to uninstall"], required = true)
private lateinit var packageName: String
@Option(
names = ["-u", "--unmount"],
description = ["Uninstall by unmounting the patched APK file"],
showDefaultValue = ALWAYS
)
private var unmount: Boolean = false
override fun run() = try {
deviceSerials.forEach { deviceSerial ->
if (unmount) {
AdbManager.RootAdbManager(deviceSerial)
} else {
AdbManager.UserAdbManager(deviceSerial)
}.uninstall(packageName)
}
} catch (e: AdbManager.DeviceNotFoundException) {
logger.severe(e.toString())
}
}

View File

@@ -0,0 +1,10 @@
package app.revanced.cli.command.utility
import picocli.CommandLine
@CommandLine.Command(
name = "utility",
description = ["Commands for utility purposes"],
subcommands = [InstallCommand::class, UninstallCommand::class],
)
internal object UtilityCommand

View File

@@ -1,8 +0,0 @@
package app.revanced.cli.logging
internal interface CliLogger {
fun error(msg: String)
fun info(msg: String)
fun trace(msg: String)
fun warn(msg: String)
}

View File

@@ -1,30 +0,0 @@
package app.revanced.cli.logging.impl
import app.revanced.cli.command.MainCommand
import app.revanced.cli.logging.CliLogger
import java.util.logging.Logger
import java.util.logging.SimpleFormatter
internal class DefaultCliLogger(
private val logger: Logger = Logger.getLogger(MainCommand::class.java.name),
private val errorLogger: Logger = Logger.getLogger(logger.name + "Err")
) : CliLogger {
init {
logger.useParentHandlers = false
if (logger.handlers.isEmpty()) {
logger.addHandler(FlushingStreamHandler(System.out, SimpleFormatter()))
}
}
companion object {
init {
System.setProperty("java.util.logging.SimpleFormatter.format", "%4\$s: %5\$s %n")
}
}
override fun error(msg: String) = errorLogger.severe(msg)
override fun info(msg: String) = logger.info(msg)
override fun trace(msg: String) = logger.finest(msg)
override fun warn(msg: String) = errorLogger.warning(msg)
}

View File

@@ -1,13 +0,0 @@
package app.revanced.cli.logging.impl
import java.io.OutputStream
import java.util.logging.Formatter
import java.util.logging.LogRecord
import java.util.logging.StreamHandler
internal class FlushingStreamHandler(out: OutputStream, format: Formatter) : StreamHandler(out, format) {
override fun publish(record: LogRecord) {
super.publish(record)
flush()
}
}

View File

@@ -1,13 +0,0 @@
package app.revanced.cli.patcher.logging.impl
import app.revanced.cli.logging.impl.DefaultCliLogger
import java.util.logging.Logger
internal object PatcherLogger : app.revanced.patcher.logging.Logger{
private val logger = DefaultCliLogger(Logger.getLogger(app.revanced.patcher.Patcher::class.java.name))
override fun error(msg: String) = logger.error(msg)
override fun info(msg: String) = logger.info(msg)
override fun warn(msg: String)= logger.warn(msg)
override fun trace(msg: String)= logger.trace(msg)
}

View File

@@ -1,16 +1,18 @@
package app.revanced.utils package app.revanced.utils
import app.revanced.cli.command.PatchList import app.revanced.cli.command.PatchList
import app.revanced.cli.logging.CliLogger
import app.revanced.patcher.extensions.PatchExtensions.options import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.NoSuchOptionException import app.revanced.patcher.patch.NoSuchOptionException
import app.revanced.utils.Options.PatchOption.Option import app.revanced.utils.Options.PatchOption.Option
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.File import java.io.File
import java.util.logging.Logger
internal object Options { internal object Options {
private val logger = Logger.getLogger(Options::class.java.name)
private var mapper = jacksonObjectMapper() private var mapper = jacksonObjectMapper()
/** /**
@@ -53,22 +55,24 @@ internal object Options {
* Sets the options for the patches in the list. * Sets the options for the patches in the list.
* *
* @param json The JSON string containing the options. * @param json The JSON string containing the options.
* @param logger The logger to use for logging.
*/ */
fun PatchList.setOptions(json: String, logger: CliLogger? = null) { fun PatchList.setOptions(json: String) {
filter { it.options?.any() == true }.let { patches -> filter { it.options?.any() == true }.let { patches ->
if (patches.isEmpty()) return if (patches.isEmpty()) return
val patchOptions = deserialize(json) val patchOptions = deserialize(json)
patches.forEach { patch -> patches.forEach patch@{ patch ->
patchOptions.find { option -> option.patchName == patch.patchName }?.let { patchOptions.find { option -> option.patchName == patch.patchName }?.let {
it.options.forEach { option -> it.options.forEach { option ->
try { try {
patch.options?.set(option.key, option.value) patch.options?.set(option.key, option.value)
?: logger?.warn("${patch.patchName} has no options") ?: run{
logger.warning("${patch.patchName} has no options")
return@patch
}
} catch (e: NoSuchOptionException) { } catch (e: NoSuchOptionException) {
logger?.error(e.message ?: "Unknown error") logger.info(e.toString())
} }
} }
} }
@@ -80,10 +84,9 @@ internal object Options {
* Sets the options for the patches in the list. * Sets the options for the patches in the list.
* *
* @param file The file containing the JSON string containing the options. * @param file The file containing the JSON string containing the options.
* @param logger The logger to use for logging.
* @see setOptions * @see setOptions
*/ */
fun PatchList.setOptions(file: File, logger: CliLogger? = null) = setOptions(file.readText(), logger) fun PatchList.setOptions(file: File) = setOptions(file.readText())
/** /**
* Data class for a patch and its [Option]s. * Data class for a patch and its [Option]s.

View File

@@ -1,36 +1,38 @@
package app.revanced.utils.adb package app.revanced.utils.adb
import app.revanced.cli.logging.CliLogger
import app.revanced.utils.adb.AdbManager.Apk import app.revanced.utils.adb.AdbManager.Apk
import app.revanced.utils.adb.Constants.COMMAND_CREATE_DIR import app.revanced.utils.adb.Constants.CREATE_DIR
import app.revanced.utils.adb.Constants.COMMAND_DELETE import app.revanced.utils.adb.Constants.DELETE
import app.revanced.utils.adb.Constants.COMMAND_INSTALL_MOUNT import app.revanced.utils.adb.Constants.INSTALLATION_PATH
import app.revanced.utils.adb.Constants.COMMAND_PREPARE_MOUNT_APK import app.revanced.utils.adb.Constants.INSTALL_MOUNT
import app.revanced.utils.adb.Constants.COMMAND_RESTART import app.revanced.utils.adb.Constants.INSTALL_PATCHED_APK
import app.revanced.utils.adb.Constants.COMMAND_UMOUNT import app.revanced.utils.adb.Constants.MOUNT_PATH
import app.revanced.utils.adb.Constants.CONTENT_MOUNT_SCRIPT import app.revanced.utils.adb.Constants.MOUNT_SCRIPT
import app.revanced.utils.adb.Constants.PATH_INIT_PUSH import app.revanced.utils.adb.Constants.PATCHED_APK_PATH
import app.revanced.utils.adb.Constants.PATH_INSTALLATION
import app.revanced.utils.adb.Constants.PATH_MOUNT
import app.revanced.utils.adb.Constants.PATH_PATCHED_APK
import app.revanced.utils.adb.Constants.PLACEHOLDER import app.revanced.utils.adb.Constants.PLACEHOLDER
import app.revanced.utils.adb.Constants.RESTART
import app.revanced.utils.adb.Constants.TMP_PATH
import app.revanced.utils.adb.Constants.UMOUNT
import se.vidstige.jadb.JadbConnection import se.vidstige.jadb.JadbConnection
import se.vidstige.jadb.managers.Package import se.vidstige.jadb.managers.Package
import se.vidstige.jadb.managers.PackageManager import se.vidstige.jadb.managers.PackageManager
import java.io.Closeable import java.io.Closeable
import java.io.File import java.io.File
import java.util.logging.Logger
/** /**
* Adb manager. Used to install and uninstall [Apk] files. * Adb manager. Used to install and uninstall [Apk] files.
* *
* @param deviceSerial The serial of the device. * @param deviceSerial The serial of the device.
*/ */
internal sealed class AdbManager(deviceSerial: String? = null, protected val logger: CliLogger? = null) : Closeable { internal sealed class AdbManager(deviceSerial: String? = null) : Closeable {
protected val logger: Logger = Logger.getLogger(AdbManager::class.java.name)
protected val device = JadbConnection().devices.find { device -> device.serial == deviceSerial } protected val device = JadbConnection().devices.find { device -> device.serial == deviceSerial }
?: throw DeviceNotFoundException(deviceSerial) ?: throw DeviceNotFoundException(deviceSerial)
init { init {
logger?.trace("Established connection to $deviceSerial") logger.fine("Established connection to $deviceSerial")
} }
/** /**
@@ -39,7 +41,7 @@ internal sealed class AdbManager(deviceSerial: String? = null, protected val log
* @param apk The [Apk] file. * @param apk The [Apk] file.
*/ */
open fun install(apk: Apk) { open fun install(apk: Apk) {
logger?.info("Finished installing ${apk.file.name}") logger.info("Finished installing ${apk.file.name}")
} }
/** /**
@@ -48,51 +50,53 @@ internal sealed class AdbManager(deviceSerial: String? = null, protected val log
* @param packageName The package name. * @param packageName The package name.
*/ */
open fun uninstall(packageName: String) { open fun uninstall(packageName: String) {
logger?.info("Finished uninstalling $packageName") logger.info("Finished uninstalling $packageName")
} }
/** /**
* Closes the [AdbManager] instance. * Closes the [AdbManager] instance.
*/ */
override fun close() { override fun close() {
logger?.trace("Closed") logger.fine("Closed")
} }
class RootAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) { class RootAdbManager(deviceSerial: String) : AdbManager(deviceSerial) {
init { init {
if (!device.hasSu()) throw IllegalArgumentException("Root required on $deviceSerial. Task failed") if (!device.hasSu()) throw IllegalArgumentException("Root required on $deviceSerial. Task failed")
} }
override fun install(apk: Apk) { override fun install(apk: Apk) {
logger?.info("Installing by mounting") logger.info("Installing by mounting")
val applyReplacement = getPlaceholderReplacement( val applyReplacement = getPlaceholderReplacement(
apk.packageName ?: throw IllegalArgumentException("Package name is required") apk.packageName ?: throw IllegalArgumentException("Package name is required")
) )
device.copyFile(apk.file, PATH_INIT_PUSH) device.push(apk.file, TMP_PATH)
device.run("$COMMAND_CREATE_DIR $PATH_INSTALLATION") device.run("$CREATE_DIR $INSTALLATION_PATH")
device.run(COMMAND_PREPARE_MOUNT_APK.applyReplacement()) device.run(INSTALL_PATCHED_APK.applyReplacement())
device.createFile(PATH_INIT_PUSH, CONTENT_MOUNT_SCRIPT.applyReplacement()) device.createFile(TMP_PATH, MOUNT_SCRIPT.applyReplacement())
device.run(COMMAND_INSTALL_MOUNT.applyReplacement()) device.run(INSTALL_MOUNT.applyReplacement())
device.run(COMMAND_UMOUNT.applyReplacement()) // Sanity check. device.run(UMOUNT.applyReplacement()) // Sanity check.
device.run(PATH_MOUNT.applyReplacement()) device.run(MOUNT_PATH.applyReplacement())
device.run(COMMAND_RESTART.applyReplacement()) device.run(RESTART.applyReplacement())
device.run(DELETE.applyReplacement(TMP_PATH).applyReplacement())
super.install(apk) super.install(apk)
} }
override fun uninstall(packageName: String) { override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName by unmounting and deleting the package") logger.info("Uninstalling $packageName by unmounting")
val applyReplacement = getPlaceholderReplacement(packageName) val applyReplacement = getPlaceholderReplacement(packageName)
device.run(COMMAND_UMOUNT.applyReplacement(packageName)) device.run(UMOUNT.applyReplacement(packageName))
device.run(COMMAND_DELETE.applyReplacement(PATH_PATCHED_APK).applyReplacement()) device.run(DELETE.applyReplacement(PATCHED_APK_PATH).applyReplacement())
device.run(COMMAND_DELETE.applyReplacement(PATH_MOUNT).applyReplacement()) device.run(DELETE.applyReplacement(MOUNT_PATH).applyReplacement())
device.run(DELETE.applyReplacement(TMP_PATH).applyReplacement())
super.uninstall(packageName) super.uninstall(packageName)
} }
@@ -103,7 +107,7 @@ internal sealed class AdbManager(deviceSerial: String? = null, protected val log
} }
} }
class UserAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) { class UserAdbManager(deviceSerial: String) : AdbManager(deviceSerial) {
private val packageManager = PackageManager(device) private val packageManager = PackageManager(device)
override fun install(apk: Apk) { override fun install(apk: Apk) {
@@ -113,7 +117,7 @@ internal sealed class AdbManager(deviceSerial: String? = null, protected val log
} }
override fun uninstall(packageName: String) { override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName") logger.info("Uninstalling $packageName")
packageManager.uninstall(Package(packageName)) packageManager.uninstall(Package(packageName))
@@ -125,6 +129,7 @@ internal sealed class AdbManager(deviceSerial: String? = null, protected val log
* Apk file for [AdbManager]. * Apk file for [AdbManager].
* *
* @param file The [Apk] file. * @param file The [Apk] file.
* @param packageName The package name of the [Apk] file.
*/ */
internal class Apk(val file: File, val packageName: String? = null) internal class Apk(val file: File, val packageName: String? = null)

View File

@@ -2,24 +2,28 @@ package app.revanced.utils.adb
import se.vidstige.jadb.JadbDevice import se.vidstige.jadb.JadbDevice
import se.vidstige.jadb.RemoteFile import se.vidstige.jadb.RemoteFile
import se.vidstige.jadb.ShellProcessBuilder
import java.io.File import java.io.File
import java.util.concurrent.Callable
import java.util.concurrent.Executors
// return the input or output stream, depending on which first returns a value
internal fun JadbDevice.run(command: String, su: Boolean = false) = with(this.startCommand(command, su)) { internal fun JadbDevice.buildCommand(command: String, su: Boolean = true): ShellProcessBuilder {
Executors.newFixedThreadPool(2).let { service -> if (su) return shellProcessBuilder("su -c \'$command\'")
arrayOf(inputStream, errorStream).map { stream ->
Callable { stream.bufferedReader().use { it.readLine() } } val args = command.split(" ") as ArrayList<String>
}.let { tasks -> service.invokeAny(tasks).also { service.shutdown() } } val cmd = args.removeFirst()
}
return shellProcessBuilder(cmd, *args.toTypedArray())
}
internal fun JadbDevice.run(command: String, su: Boolean = true): Int {
return this.buildCommand(command, su).start().waitFor()
} }
internal fun JadbDevice.hasSu() = internal fun JadbDevice.hasSu() =
this.startCommand("su -h", false).waitFor() == 0 this.startCommand("su -h", false).waitFor() == 0
internal fun JadbDevice.copyFile(file: File, targetFile: String) = internal fun JadbDevice.push(file: File, targetFilePath: String) =
push(file, RemoteFile(targetFile)) push(file, RemoteFile(targetFilePath))
internal fun JadbDevice.createFile(targetFile: String, content: String) = internal fun JadbDevice.createFile(targetFile: String, content: String) =
push(content.byteInputStream(), System.currentTimeMillis(), 644, RemoteFile(targetFile)) push(content.byteInputStream(), System.currentTimeMillis(), 644, RemoteFile(targetFile))

View File

@@ -1,40 +1,40 @@
package app.revanced.utils.adb package app.revanced.utils.adb
internal object Constants { internal object Constants {
internal const val PLACEHOLDER = "TEMPLATE_PACKAGE_NAME" internal const val PLACEHOLDER = "PLACEHOLDER"
internal const val PATH_INIT_PUSH = "/data/local/tmp/revanced.delete" internal const val TMP_PATH = "/data/local/tmp/revanced.tmp"
internal const val PATH_INSTALLATION = "/data/adb/revanced/" internal const val INSTALLATION_PATH = "/data/adb/revanced/"
internal const val PATH_PATCHED_APK = "$PATH_INSTALLATION$PLACEHOLDER.apk" internal const val PATCHED_APK_PATH = "$INSTALLATION_PATH$PLACEHOLDER.apk"
internal const val PATH_MOUNT = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh" internal const val MOUNT_PATH = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
internal const val COMMAND_DELETE = "rm -rf $PLACEHOLDER" internal const val DELETE = "rm -rf $PLACEHOLDER"
internal const val COMMAND_CREATE_DIR = "mkdir -p" internal const val CREATE_DIR = "mkdir -p"
internal const val COMMAND_RESTART = "pm resolve-activity --brief $PLACEHOLDER | tail -n 1 | " + internal const val RESTART = "pm resolve-activity --brief $PLACEHOLDER | tail -n 1 | " +
"xargs am start -n && kill ${'$'}(pidof -s $PLACEHOLDER)" "xargs am start -n && kill ${'$'}(pidof -s $PLACEHOLDER)"
internal const val COMMAND_PREPARE_MOUNT_APK = "base_path=\"$PATH_PATCHED_APK\" && " + internal const val INSTALL_PATCHED_APK = "base_path=\"$PATCHED_APK_PATH\" && " +
"mv $PATH_INIT_PUSH ${'$'}base_path && " + "mv $TMP_PATH ${'$'}base_path && " +
"chmod 644 ${'$'}base_path && " + "chmod 644 ${'$'}base_path && " +
"chown system:system ${'$'}base_path && " + "chown system:system ${'$'}base_path && " +
"chcon u:object_r:apk_data_file:s0 ${'$'}base_path" "chcon u:object_r:apk_data_file:s0 ${'$'}base_path"
internal const val COMMAND_UMOUNT = internal const val UMOUNT =
"grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d \" \" -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done" "grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d \" \" -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && chmod +x $PATH_MOUNT" internal const val INSTALL_MOUNT = "mv $TMP_PATH $MOUNT_PATH && chmod +x $MOUNT_PATH"
internal const val CONTENT_MOUNT_SCRIPT = internal val MOUNT_SCRIPT =
""" """
#!/system/bin/sh #!/system/bin/sh
MAGISKTMP="${'$'}(magisk --path)" || MAGISKTMP=/sbin MAGISKTMP="${'$'}(magisk --path)" || MAGISKTMP=/sbin
MIRROR="${'$'}MAGISKTMP/.magisk/mirror" MIRROR="${'$'}MAGISKTMP/.magisk/mirror"
while [ "${'$'}(getprop sys.boot_completed | tr -d '\r')" != "1" ]; do sleep 1; done while [ "${'$'}(getprop sys.boot_completed | tr -d '\r')" != "1" ]; do sleep 1; done
base_path="$PATH_PATCHED_APK" base_path="$PATCHED_APK_PATH"
stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' ) stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' )
chcon u:object_r:apk_data_file:s0 ${'$'}base_path chcon u:object_r:apk_data_file:s0 ${'$'}base_path
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
""" """.trimIndent()
} }

View File

@@ -1,6 +1,5 @@
package app.revanced.utils.signing package app.revanced.utils.signing
import app.revanced.cli.command.logger
import com.android.apksig.ApkSigner import com.android.apksig.ApkSigner
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
@@ -16,10 +15,13 @@ import java.math.BigInteger
import java.security.* import java.security.*
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.util.* import java.util.*
import java.util.logging.Logger
internal class ApkSigner( internal class ApkSigner(
private val signingOptions: SigningOptions private val signingOptions: SigningOptions
) { ) {
private val logger = Logger.getLogger(ApkSigner::class.java.name)
private val signer: ApkSigner.Builder private val signer: ApkSigner.Builder
private val passwordCharArray = signingOptions.password.toCharArray() private val passwordCharArray = signingOptions.password.toCharArray()