Compare commits

...

92 Commits

Author SHA1 Message Date
semantic-release-bot
c45ed69adf chore(release): 4.4.2 [skip ci]
## [4.4.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2) (2024-03-10)
2024-03-10 15:44:08 +00:00
oSumAtrIX
8641d301b1 chore: Merge branch dev to main (#315) 2024-03-10 16:42:17 +01:00
semantic-release-bot
44b72ca99d chore(release): 4.4.2-dev.2 [skip ci]
## [4.4.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.2-dev.1...v4.4.2-dev.2) (2024-03-10)
2024-03-10 15:41:25 +00:00
oSumAtrIX
240f2cfb6b build(Needs bump): Bump dependencies to fix generating keystore 2024-03-10 16:39:43 +01:00
semantic-release-bot
304275ddbb chore(release): 4.4.2-dev.1 [skip ci]
## [4.4.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2-dev.1) (2024-03-09)
2024-03-09 04:22:02 +00:00
oSumAtrIX
483590726a build(Needs bump): Bump dependencies to fix signing issues 2024-03-09 05:20:11 +01:00
semantic-release-bot
cf20efd467 chore(release): 4.4.1 [skip ci]
## [4.4.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1) (2024-03-06)

### Bug Fixes

* Bump dependencies to support BCS keystore ([1c10a77](1c10a7760d))
2024-03-06 19:14:29 +00:00
oSumAtrIX
164d09dec1 chore: Merge branch dev to main (#309) 2024-03-06 20:12:35 +01:00
oSumAtrIX
1e92239616 build: Set target bytecode level to JVM 11 2024-03-04 19:16:09 +01:00
semantic-release-bot
a5a5085f0f chore(release): 4.4.1-dev.2 [skip ci]
## [4.4.1-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1-dev.1...v4.4.1-dev.2) (2024-03-04)

### Bug Fixes

* Bump dependencies to support BCS keystore ([1c10a77](1c10a7760d))
2024-03-04 14:50:04 +00:00
oSumAtrIX
1c10a7760d fix: Bump dependencies to support BCS keystore 2024-03-04 15:47:59 +01:00
oSumAtrIX
4ff697ef0b ci: Update action 2024-03-04 15:36:34 +01:00
oSumAtrIX
628b452b7e docs: Add features and documentation section to readme 2024-02-26 04:38:22 +01:00
oSumAtrIX
e622616628 docs: Fix broken links 2024-02-26 04:37:46 +01:00
oSumAtrIX
109b33f1ed chore: Rename issue templates 2024-02-25 03:37:53 +01:00
oSumAtrIX
9fe4795923 ci: Rename workflow file 2024-02-25 03:14:02 +01:00
oSumAtrIX
f21c56d8c0 ci: Fix indentation in workflow 2024-02-24 01:14:45 +01:00
oSumAtrIX
de63cfa426 refactor: Move code out of use block 2024-02-24 01:10:23 +01:00
oSumAtrIX
9c0ad4604a docs: Break long lines 2024-02-23 04:02:32 +01:00
oSumAtrIX
2fcb74e79d docs: Fix mistakes and wording 2024-02-23 03:57:02 +01:00
oSumAtrIX
f2368ccf27 docs: Format markdown code 2024-02-23 03:03:51 +01:00
oSumAtrIX
a4e8d2df0d docs: Fix incorrect punctuation 2024-02-23 03:00:35 +01:00
oSumAtrIX
724593a7b1 ci: Split release into a separate PR build workflow
Because the release workflow already runs on dev and main, it is not necessary to also trigger it for PRs.
ci: Do not start a Gradle daemon for PR builds
2024-02-23 02:26:12 +01:00
semantic-release-bot
4f1982e3ad chore(release): 4.4.1-dev.1 [skip ci]
## [4.4.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1-dev.1) (2024-02-21)
2024-02-21 03:58:27 +00:00
oSumAtrIX
f1d7d0dc62 build: Sign release artifacts 2024-02-21 04:52:53 +01:00
oSumAtrIX
40c90f5c1b build: Bump Gradle 2024-02-15 02:34:10 +01:00
oSumAtrIX
30b46bcb0f build(Needs bump): Bump dependencies 2024-02-15 02:34:10 +01:00
oSumAtrIX
b6f63c7d9d docs: Fix blockquote highlights not rendering
As of 14. Nov 2023 GitHub has decided to disable nested highlighted blockquotes: https://github.com/orgs/community/discussions/16925.
2024-02-04 18:35:41 +01:00
oSumAtrIX
b5bd988a1d ci: Use latest Node.js LTS version to fix builds 2024-01-26 22:52:38 +01:00
oSumAtrIX
95c998b0a6 ci: Add dependabot 2024-01-26 01:45:45 +01:00
oSumAtrIX
24a8f6575c build: Bump dependencies 2024-01-26 01:42:04 +01:00
oSumAtrIX
55f0c01e5a docs: Fix grammatic error 2024-01-12 11:45:39 +01:00
oSumAtrIX
ee1e96b2d5 docs: Simplify patch command 2024-01-12 09:42:05 +01:00
oSumAtrIX
0fc1d571e8 docs: Add JRE links to obtain 2024-01-11 23:37:20 +01:00
oSumAtrIX
4933fe0314 build: Bump dependencies 2024-01-10 09:33:54 +01:00
oSumAtrIX
2e2ddac273 chore: Add local.properties to .gitignore 2024-01-10 09:33:54 +01:00
semantic-release-bot
3c264572a2 chore(release): 4.4.0 [skip ci]
# [4.4.0](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0) (2023-12-28)

### Bug Fixes

* Add missing punctuation in command description ([8210351](821035107d))

### Features

* Log saved patched APK file path ([16109bd](16109bd8bc))
2023-12-28 21:34:45 +00:00
oSumAtrIX
63e8585652 chore: Merge branch dev to main (#305) 2023-12-28 22:33:09 +01:00
oSumAtrIX
8f59d94dc7 docs: Add building instructions 2023-12-21 15:10:02 +01:00
semantic-release-bot
3bcee04a7d chore(release): 4.4.0-dev.2 [skip ci]
# [4.4.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.0-dev.1...v4.4.0-dev.2) (2023-12-18)

### Bug Fixes

* Add missing punctuation in command description ([8210351](821035107d))
2023-12-18 18:47:08 +00:00
oSumAtrIX
821035107d fix: Add missing punctuation in command description 2023-12-18 19:45:35 +01:00
oSumAtrIX
8becebaa42 docs: Fix spelling mistakes 2023-12-12 13:43:36 +01:00
oSumAtrIX
fe563fff93 build: Simplify enabling local build cache 2023-12-10 21:57:12 +01:00
semantic-release-bot
2d17459fa3 chore(release): 4.4.0-dev.1 [skip ci]
# [4.4.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0-dev.1) (2023-12-01)

### Features

* Log saved patched APK file path ([16109bd](16109bd8bc))
2023-12-01 22:54:26 +00:00
oSumAtrIX
16109bd8bc feat: Log saved patched APK file path 2023-12-01 23:53:17 +01:00
semantic-release-bot
09bc652317 chore(release): 4.3.0 [skip ci]
# [4.3.0](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0) (2023-12-01)

### Features

* Add `list-versions` command ([a974b8e](a974b8ea80))
2023-12-01 22:29:44 +00:00
oSumAtrIX
1d051365f3 chore: Merge branch dev to main (#304) 2023-12-01 01:24:43 +01:00
oSumAtrIX
ab7d9d8e1e build: Bump dependencies 2023-12-01 01:22:06 +01:00
oSumAtrIX
5e089ea9af docs: Update to latest GitHub Markdown syntax changes 2023-12-01 01:12:26 +01:00
semantic-release-bot
06c6a97915 chore(release): 4.3.0-dev.1 [skip ci]
# [4.3.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0-dev.1) (2023-11-27)

### Features

* Add `list-versions` command ([a974b8e](a974b8ea80))
2023-11-27 22:12:44 +00:00
oSumAtrIX
a974b8ea80 feat: Add list-versions command 2023-11-27 23:11:23 +01:00
semantic-release-bot
89c35ee21b chore(release): 4.2.0 [skip ci]
# [4.2.0](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.2.0) (2023-11-26)

### Bug Fixes

* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](9d96bb7b4c))

### Features

* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](e7c3d64bf1))
* Exit application with CLI exit code ([36c6a6a](36c6a6a5f7))
* Make `--out´ option optional ([3765957](3765957043))
2023-11-26 05:03:52 +00:00
oSumAtrIX
41bdb04ab0 chore: Merge branch dev to main (#299) 2023-11-26 06:02:21 +01:00
semantic-release-bot
a5542467c8 chore(release): 4.2.0-dev.1 [skip ci]
# [4.2.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.1-dev.1...v4.2.0-dev.1) (2023-11-26)

### Features

* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](e7c3d64bf1))
* Exit application with CLI exit code ([36c6a6a](36c6a6a5f7))
* Make `--out´ option optional ([3765957](3765957043))
2023-11-26 04:58:20 +00:00
oSumAtrIX
5fd205f77d chore: Lint code 2023-11-26 05:56:31 +01:00
oSumAtrIX
e7c3d64bf1 feat: Allow selecting first Adb device, if none supplied automatically by updating dependencies 2023-11-26 05:55:49 +01:00
oSumAtrIX
3765957043 feat: Make `--out´ option optional 2023-11-26 05:27:31 +01:00
oSumAtrIX
5e63e0a276 refactor: Use a newline for annotation properties 2023-11-26 05:27:30 +01:00
oSumAtrIX
36c6a6a5f7 feat: Exit application with CLI exit code 2023-11-26 05:27:30 +01:00
semantic-release-bot
860fb7b957 chore(release): 4.1.1-dev.1 [skip ci]
## [4.1.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.1.1-dev.1) (2023-11-25)

### Bug Fixes

* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](9d96bb7b4c))
2023-11-25 22:48:42 +00:00
SandaruKasa
9d96bb7b4c fix: Fix typo (#300) 2023-11-25 23:47:13 +01:00
oSumAtrIX
3afa590616 chore: Add heading to issue templates 2023-11-23 00:56:53 +01:00
oSumAtrIX
db0b943ad3 chore: Update README heading 2023-11-22 23:41:26 +01:00
oSumAtrIX
8c3d4d3aa1 build: Bump Gradle wrapper 2023-11-22 00:59:45 +01:00
oSumAtrIX
04d312df31 build: Use dedicated Gradle cache action 2023-11-22 00:45:44 +01:00
oSumAtrIX
158f59ab88 build: Use Gradle build cache 2023-11-22 00:26:40 +01:00
oSumAtrIX
a078b53a21 ci: Simplify cache paths 2023-11-22 00:11:19 +01:00
oSumAtrIX
fb75b0f115 chore: Reword comment for first PR merge 2023-11-22 00:07:38 +01:00
oSumAtrIX
c52383eca0 chore: Add a newline between steps 2023-11-22 00:04:47 +01:00
oSumAtrIX
0562ee85c5 chore: Notice about contribution guidelines in issue templates 2023-11-22 00:01:25 +01:00
oSumAtrIX
1cde672a05 chore: Do not use a line break in issue template sentence 2023-11-21 23:48:30 +01:00
oSumAtrIX
d5419dbb6b build: Bump dependencies 2023-11-21 23:43:49 +01:00
oSumAtrIX
d29016b428 ci: Update cache key 2023-11-21 23:41:43 +01:00
oSumAtrIX
1eb51e9d4f chore: Update packages 2023-11-21 23:41:00 +01:00
semantic-release-bot
86b8415ac6 chore(release): 4.1.0 [skip ci]
# [4.1.0](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.1.0) (2023-11-04)

### Features

* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](b2055ce07d))
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](0139dfe0bf))

### Performance Improvements

* Use a `HashSet` to check for included and excluded patches ([616d14f](616d14f009))
2023-11-04 21:13:41 +00:00
oSumAtrIX
8f4aebc60b chore: Merge branch dev to main (#292) 2023-11-04 22:11:36 +01:00
semantic-release-bot
bd3171c7c5 chore(release): 4.1.0-dev.3 [skip ci]
# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
2023-11-03 17:27:32 +00:00
oSumAtrIX
6481ba68db build(Needs bump): Bump dependencies 2023-11-03 18:24:27 +01:00
semantic-release-bot
799882e6a6 chore(release): 4.1.0-dev.2 [skip ci]
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)

### Features

* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](b2055ce07d))

### Performance Improvements

* Use a `HashSet` to check for included and excluded patches ([616d14f](616d14f009))
2023-11-03 01:04:32 +00:00
oSumAtrIX
616d14f009 perf: Use a HashSet to check for included and excluded patches 2023-11-03 02:02:41 +01:00
oSumAtrIX
b2055ce07d feat: Include or exclude patches by their index in relation to supplied patch bundles 2023-11-03 02:02:40 +01:00
semantic-release-bot
4fc42089a5 chore(release): 4.1.0-dev.1 [skip ci]
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)

### Features

* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](0139dfe0bf))
2023-11-03 00:33:10 +00:00
SandaruKasa
0139dfe0bf feat: List patches which are compatible with any app (#297)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-11-03 01:31:45 +01:00
semantic-release-bot
7d1c0e663f chore(release): 4.0.3-dev.2 [skip ci]
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
2023-10-30 21:24:43 +00:00
taku
6cc6960493 build(Needs bump): Bump dependencies to support PatchOption#valueType (#296) 2023-10-30 22:22:50 +01:00
semantic-release-bot
9f15ac6ec5 chore(release): 4.0.3-dev.1 [skip ci]
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
2023-10-23 00:15:36 +00:00
oSumAtrIX
6670d89c74 build(Needs bump): Bump dependencies to support new patch options fields 2023-10-23 02:04:50 +02:00
oSumAtrIX
a60d07fc5d build: Bump Kotlin Gradle plugin version 2023-10-22 16:14:47 +02:00
oSumAtrIX
362e6f5904 docs: Use shorter heading 2023-10-21 12:07:40 +02:00
Palm
51402ab8a7 build: Bump dependencies 2023-10-12 21:57:50 +02:00
semantic-release-bot
a8c8682116 chore(release): 4.0.2 [skip ci]
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)

### Bug Fixes

* Move file to output even when mounting ([59dfc98](59dfc988e3))
* Use punctuation in option descriptions ([da4469f](da4469f402))

### Performance Improvements

* Use multiple threads for writing dex files ([28648a1](28648a1c53))
2023-10-12 17:58:47 +00:00
oSumAtrIX
a86919eb71 chore: Merge branch dev to main (#281) 2023-10-12 19:56:45 +02:00
36 changed files with 4033 additions and 2891 deletions

3
.editorconfig Normal file
View File

@@ -0,0 +1,3 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea
ktlint_standard_no-wildcard-imports = disabled

View File

@@ -1,49 +0,0 @@
name: 🐞 Bug report
description: Report a bug or an issue.
title: 'bug: '
labels: ['Bug report']
body:
- type: markdown
attributes:
value: |
# ReVanced CLI bug report
Please check for existing bug reports
[here](https://github.com/ReVanced/revanced-cli/labels/Bug%20report)
before creating a new one.
- type: textarea
attributes:
label: Bug description
description: |
- Describe your bug in detail
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
- Add images and videos if possible
- List used patches if applicable
validations:
required: true
- type: textarea
attributes:
label: Error logs
description: Exceptions can be captured by running `logcat | grep AndroidRuntime` in a shell.
render: shell
- type: textarea
attributes:
label: Solution
description: If applicable, add a possible solution to the bug.
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you don't follow the checklist below.
options:
- label: This request is not a duplicate of an existing issue.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true

110
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,110 @@
name: 🐞 Bug report
description: Report a bug or an issue.
title: 'bug: '
labels: ['Bug report']
body:
- type: markdown
attributes:
value: |
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
width="256px"
src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# ReVanced CLI bug report
Before creating a new bug report, please keep the following in mind:
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-cli/labels/Bug%20report).
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-cli/blob/main/CONTRIBUTING.md).
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
- type: textarea
attributes:
label: Bug description
description: |
- Describe your bug in detail
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
- Add images and videos if possible
- List used patches if applicable
validations:
required: true
- type: textarea
attributes:
label: Error logs
description: Exceptions can be captured by running `logcat | grep AndroidRuntime` in a shell.
render: shell
- type: textarea
attributes:
label: Solution
description: If applicable, add a possible solution to the bug.
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your bug report will be closed if you don't follow the checklist below.
options:
- label: This issue is not a duplicate of an existing bug report.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true

View File

@@ -1,45 +0,0 @@
name: ⭐ Feature request
description: Create a detailed request for a new feature.
title: 'feat: '
labels: ['Feature request']
body:
- type: markdown
attributes:
value: |
# ReVanced CLI feature request
Please check for existing feature requests
[here](https://github.com/ReVanced/revanced-cli/labels/Feature%20request)
before creating a new one.
- type: textarea
attributes:
label: Feature description
description: |
- Describe your feature in detail
- Add images, videos, links, examples, references, etc. if possible
- Add the target application name in case you request a new patch
- type: textarea
attributes:
label: Motivation
description: |
A strong motivation is necessary for a feature request to be considered.
- Why should this feature be implemented?
- What is the explicit use case?
- What are the benefits?
- What makes this feature important?
validations:
required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you don't follow the checklist below.
options:
- label: This request is not a duplicate of an existing issue.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true

View File

@@ -0,0 +1,106 @@
name: ⭐ Feature request
description: Create a detailed request for a new feature.
title: 'feat: '
labels: ['Feature request']
body:
- type: markdown
attributes:
value: |
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
width="256px"
src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br>
<br>
Continuing the legacy of Vanced
</p>
# ReVanced CLI feature request
Before creating a new feature request, please keep the following in mind:
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-cli//labels/Feature%20request).
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-cli//blob/main/CONTRIBUTING.md).
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
- type: textarea
attributes:
label: Feature description
description: |
- Describe your feature in detail
- Add images, videos, links, examples, references, etc. if possible
- Add the target application name in case you request a new patch
- type: textarea
attributes:
label: Motivation
description: |
A strong motivation is necessary for a feature request to be considered.
- Why should this feature be implemented?
- What is the explicit use case?
- What are the benefits?
- What makes this feature important?
validations:
required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your feature request will be closed if you don't follow the checklist below.
options:
- label: This issue is not a duplicate of an existing feature request.
required: true
- label: I have chosen an appropriate title.
required: true
- label: All requested information has been provided properly.
required: true

2
.github/config.yml vendored
View File

@@ -1,2 +1,2 @@
firstPRMergeComment: > firstPRMergeComment: >
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role. Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) to receive a role for your contribution.

22
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: github-actions
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly
- package-ecosystem: npm
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly
- package-ecosystem: gradle
labels: []
directory: /
target-branch: dev
schedule:
interval: monthly

View File

@@ -0,0 +1,25 @@
name: Build pull request
on:
workflow_dispatch:
pull_request:
branches:
- dev
jobs:
release:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build --no-daemon

View File

@@ -16,6 +16,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Open pull request - name: Open pull request
uses: repo-sync/pull-request@v2 uses: repo-sync/pull-request@v2
with: with:

View File

@@ -6,10 +6,6 @@ on:
branches: branches:
- main - main
- dev - dev
pull_request:
branches:
- main
- dev
jobs: jobs:
release: release:
@@ -23,23 +19,31 @@ jobs:
# https://github.com/cycjimmy/semantic-release-action#private-packages # https://github.com/cycjimmy/semantic-release-action#private-packages
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
- name: Cache
uses: actions/cache@v3 - name: Cache Gradle
with: uses: burrunan/gradle-cache-action@v1
path: |
${{ runner.home }}/.gradle/caches
${{ runner.home }}/.gradle/wrapper
.gradle
build
node_modules
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
- name: Build - name: Build
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Cleaning is necessary to avoid uploading two identical artifacts with different versions run: ./gradlew build clean
run: ./gradlew clean --no-daemon
- name: Setup semantic-release - name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
cache: 'npm'
- name: Install dependencies
run: npm install run: npm install
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
fingerprint: ${{ env.GPG_FINGERPRINT }}
- name: Release - name: Release
env: env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}

View File

@@ -11,7 +11,7 @@ jobs:
name: Dispatch event to documentation repository name: Dispatch event to documentation repository
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
steps: steps:
- uses: peter-evans/repository-dispatch@v2 - uses: peter-evans/repository-dispatch@v3
with: with:
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }} token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
repository: revanced/revanced-documentation repository: revanced/revanced-documentation

5
.gitignore vendored
View File

@@ -119,4 +119,7 @@ node_modules/
# ReVanced CLI # ReVanced CLI
revanced-cache/ revanced-cache/
options.toml options.toml
# Generated by an Android project (such as ReVanced Integrations)
local.properties

View File

@@ -31,7 +31,7 @@
{ {
"assets": [ "assets": [
{ {
"path": "build/libs/*all.jar" "path": "build/libs/*-all*"
} }
], ],
successComment: false successComment: false

View File

@@ -1,3 +1,146 @@
## [4.4.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2) (2024-03-10)
## [4.4.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.2-dev.1...v4.4.2-dev.2) (2024-03-10)
## [4.4.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2-dev.1) (2024-03-09)
## [4.4.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1) (2024-03-06)
### Bug Fixes
* Bump dependencies to support BCS keystore ([1c10a77](https://github.com/ReVanced/revanced-cli/commit/1c10a7760d76ea850260ca49b448be7ad121de44))
## [4.4.1-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1-dev.1...v4.4.1-dev.2) (2024-03-04)
### Bug Fixes
* Bump dependencies to support BCS keystore ([1c10a77](https://github.com/ReVanced/revanced-cli/commit/1c10a7760d76ea850260ca49b448be7ad121de44))
## [4.4.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1-dev.1) (2024-02-21)
# [4.4.0](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0) (2023-12-28)
### Bug Fixes
* Add missing punctuation in command description ([8210351](https://github.com/ReVanced/revanced-cli/commit/821035107d7264580275f395e9e3fcef91394afd))
### Features
* Log saved patched APK file path ([16109bd](https://github.com/ReVanced/revanced-cli/commit/16109bd8bc6236debf71cbc8db78fe452b2ed00d))
# [4.4.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.0-dev.1...v4.4.0-dev.2) (2023-12-18)
### Bug Fixes
* Add missing punctuation in command description ([8210351](https://github.com/ReVanced/revanced-cli/commit/821035107d7264580275f395e9e3fcef91394afd))
# [4.4.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0-dev.1) (2023-12-01)
### Features
* Log saved patched APK file path ([16109bd](https://github.com/ReVanced/revanced-cli/commit/16109bd8bc6236debf71cbc8db78fe452b2ed00d))
# [4.3.0](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0) (2023-12-01)
### Features
* Add `list-versions` command ([a974b8e](https://github.com/ReVanced/revanced-cli/commit/a974b8ea80acd85f8dc472a3f93b8fd7bea08007))
# [4.3.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0-dev.1) (2023-11-27)
### Features
* Add `list-versions` command ([a974b8e](https://github.com/ReVanced/revanced-cli/commit/a974b8ea80acd85f8dc472a3f93b8fd7bea08007))
# [4.2.0](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.2.0) (2023-11-26)
### Bug Fixes
* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](https://github.com/ReVanced/revanced-cli/commit/9d96bb7b4cc4538da416db50bd689af1a632fc45))
### Features
* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](https://github.com/ReVanced/revanced-cli/commit/e7c3d64bf15bf84f3853e7ef699511bf72c13767))
* Exit application with CLI exit code ([36c6a6a](https://github.com/ReVanced/revanced-cli/commit/36c6a6a5f75f2e770a7941b3f83f430f62de13de))
* Make `--out´ option optional ([3765957](https://github.com/ReVanced/revanced-cli/commit/3765957043989fe7a8932a0c548566a78d04fc41))
# [4.2.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.1-dev.1...v4.2.0-dev.1) (2023-11-26)
### Features
* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](https://github.com/ReVanced/revanced-cli/commit/e7c3d64bf15bf84f3853e7ef699511bf72c13767))
* Exit application with CLI exit code ([36c6a6a](https://github.com/ReVanced/revanced-cli/commit/36c6a6a5f75f2e770a7941b3f83f430f62de13de))
* Make `--out´ option optional ([3765957](https://github.com/ReVanced/revanced-cli/commit/3765957043989fe7a8932a0c548566a78d04fc41))
## [4.1.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.1.1-dev.1) (2023-11-25)
### Bug Fixes
* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](https://github.com/ReVanced/revanced-cli/commit/9d96bb7b4cc4538da416db50bd689af1a632fc45))
# [4.1.0](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.1.0) (2023-11-04)
### Features
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
### Performance Improvements
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)
### Features
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
### Performance Improvements
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)
### Features
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)
### Bug Fixes
* Move file to output even when mounting ([59dfc98](https://github.com/ReVanced/revanced-cli/commit/59dfc988e351374eb718923d19bd9bdd94e8d3c0))
* Use punctuation in option descriptions ([da4469f](https://github.com/ReVanced/revanced-cli/commit/da4469f402c26ad95898404236b0acf0202907e2))
### Performance Improvements
* Use multiple threads for writing dex files ([28648a1](https://github.com/ReVanced/revanced-cli/commit/28648a1c53520eef8c799504ff61a35947f878b8))
## [4.0.2-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.2...v4.0.2-dev.3) (2023-10-10) ## [4.0.2-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.2...v4.0.2-dev.3) (2023-10-10)

View File

@@ -6,53 +6,72 @@
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg" srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
> >
<img <img
width="256px"
src="assets/revanced-headline/revanced-headline-vertical-light.svg" src="assets/revanced-headline/revanced-headline-vertical-light.svg"
> >
</picture> </picture>
<br> <br>
<a href="https://revanced.app/"> <a href="https://revanced.app/">
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/revanced"> <a href="https://github.com/ReVanced">
<picture> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" /> <source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" /> <img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture> </picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord"> <a href="http://revanced.app/discord">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp"> <a href="https://reddit.com/r/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced"> <a href="https://t.me/app_revanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://twitter.com/revancedapp"> <a href="https://x.com/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" /> <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced"> <a href="https://www.youtube.com/@ReVanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" /> <picture>
</a>&nbsp;&nbsp;&nbsp; <source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a>
<br> <br>
<br> <br>
Continuing the legacy of Vanced Continuing the legacy of Vanced
</p> </p>
# 📙 ReVanced CLI contribution guidelines # 👋 Contribution guidelines
This document describes how to contribute to ReVanced CLI. This document describes how to contribute to ReVanced CLI.
## 📖 Resources to help you get started ## 📖 Resources to help you get started
* The [documentation](/docs) explains how to use ReVanced CLI - The [documentation](/docs) explains how to use ReVanced CLI
* [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on - [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
* [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests - [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests
## 🙏 Submitting a feature request ## 🙏 Submitting a feature request
Features can be requested by opening an issue using the Features can be requested by opening an issue using the
[Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature-request.yml&title=feat%3A+). [Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
> **Note** > **Note**
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced CLI. > Requests can be accepted or rejected at the discretion of maintainers of ReVanced CLI.
@@ -61,7 +80,7 @@ Features can be requested by opening an issue using the
## 🐞 Submitting a bug report ## 🐞 Submitting a bug report
If you encounter a bug while using ReVanced CLI, open an issue using the If you encounter a bug while using ReVanced CLI, open an issue using the
[Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+). [Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
## 📝 How to contribute ## 📝 How to contribute
@@ -69,11 +88,11 @@ If you encounter a bug while using ReVanced CLI, open an issue using the
with the maintainers of ReVanced CLI. This will help you determine whether your change is acceptable with the maintainers of ReVanced CLI. This will help you determine whether your change is acceptable
and whether it is worth your time to implement it and whether it is worth your time to implement it
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev` 2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
3. Commit your changes. 3. Commit your changes
4. Submit a pull request to the `dev` branch of the repository and reference issues 4. Submit a pull request to the `dev` branch of the repository and reference issues
that your pull request closes in the description of your pull request that your pull request closes in the description of your pull request
5. Our team will review your pull request and provide feedback. Once your pull request is approved, 5. Our team will review your pull request and provide feedback. Once your pull request is approved,
it will be merged into the `dev` branch and will be included in the next release of ReVanced CLI it will be merged into the `dev` branch and will be included in the next release of ReVanced CLI
❤️ Thank you for considering contributing to ReVanced CLI, ❤️ Thank you for considering contributing to ReVanced CLI,
ReVanced ReVanced

View File

@@ -6,43 +6,58 @@
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg" srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
> >
<img <img
width="256px"
src="assets/revanced-headline/revanced-headline-vertical-light.svg" src="assets/revanced-headline/revanced-headline-vertical-light.svg"
> >
</picture> </picture>
<br> <br>
<a href="https://revanced.app/"> <a href="https://revanced.app/">
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/revanced"> <a href="https://github.com/ReVanced">
<picture> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" /> <source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" /> <img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture> </picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord"> <a href="http://revanced.app/discord">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp"> <a href="https://reddit.com/r/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced"> <a href="https://t.me/app_revanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://x.com/revancedapp"> <a href="https://x.com/revancedapp">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png"> <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" /> <img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
<picture/> </picture>
</a>&nbsp;&nbsp;&nbsp; </a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/@ReVanced"> <a href="https://www.youtube.com/@ReVanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" /> <picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</picture>
</a> </a>
<br> <br>
<br> <br>
Continuing the legacy of Vanced Continuing the legacy of Vanced
</p> </p>
# 💻 ReVanced CLI # 💻 ReVanced CLI
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-cli/release.yml) ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-cli/release.yml)
@@ -52,13 +67,23 @@ Command line application to use ReVanced.
## ❓ About ## ❓ About
ReVanced CLI is a command line application to patch apps using ReVanced. ReVanced CLI is a command line application that uses [ReVanced Patcher](https://github.com/revanced/revanced-patcher) to patch Android apps.
ReVanced CLI also comes with commands to uninstall or install patched apps and list patches from supplied patch bundles.
## 🚀 Download ## 💪 Features
You can download the most recent version of ReVanced CLI from Some of the features ReVanced CLI provides are:
[here](https://github.com/ReVanced/revanced-cli/releases/latest). Learn how to use ReVanced CLI by following the [documentation](/docs).
- 💉 **Patch apps**: Harness ReVanced Patcher to patch Android apps
- 💾 **Install and uninstall apps**: Install and uninstall Apps via ADB,
using the Android package manager, or by mounting using root permissions
- 📃 **List patches from patch bundles**: List available patches, compatible packages, and versions
- 💪 **Flexibility and functionality**: Apply any combination of patches to any version of Android apps
## 🔽 Download
You can download the most recent version of ReVanced CLI from
[here](https://github.com/ReVanced/revanced-cli/releases/latest).
Learn how to use ReVanced CLI by following the [documentation](/docs).
## 📚 Everything else ## 📚 Everything else
@@ -69,10 +94,14 @@ You can find the contribution guidelines [here](CONTRIBUTING.md).
### 🛠️ Building ### 🛠️ Building
In order to build ReVanced CLI, you can follow the [documentation](/docs). To build a ReVanced CLI, you can follow the [documentation](/docs).
### 📃 Documentation
You can find the documentation of ReVanced CLI [here](/docs).
## 📜 Licence ## 📜 Licence
ReVanced CLI is licensed under the GPLv3 licence. Please see the [licence file](LICENSE) for more information. ReVanced CLI is licensed under the GPLv3 license. Please see the [license file](LICENSE) for more information.
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced CLI as long as you track changes/dates in source files. [tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced CLI as long as you track changes/dates in source files.
Any modifications to ReVanced CLI must also be made available under the GPL along with build & install instructions. Any modifications to ReVanced CLI must also be made available under the GPL, along with build & install instructions.

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,15 +1,31 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins { plugins {
kotlin("jvm") version "1.9.0" alias(libs.plugins.kotlin)
alias(libs.plugins.shadow) alias(libs.plugins.shadow)
application
`maven-publish`
signing
} }
group = "app.revanced" group = "app.revanced"
application {
mainClass = "app.revanced.cli.command.MainCommandKt"
}
repositories { repositories {
mavenCentral() mavenCentral()
mavenLocal() mavenLocal()
google() google()
maven { url = uri("https://jitpack.io") } maven {
// A repository must be speficied for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/revanced/registry")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
}
}
} }
dependencies { dependencies {
@@ -21,7 +37,15 @@ dependencies {
testImplementation(libs.kotlin.test) testImplementation(libs.kotlin.test)
} }
kotlin { jvmToolchain(11) } kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
java {
targetCompatibility = JavaVersion.VERSION_11
}
tasks { tasks {
test { test {
@@ -36,9 +60,6 @@ tasks {
} }
shadowJar { shadowJar {
manifest {
attributes("Main-Class" to "app.revanced.cli.command.MainCommandKt")
}
minimize { minimize {
exclude(dependency("org.jetbrains.kotlin:.*")) exclude(dependency("org.jetbrains.kotlin:.*"))
exclude(dependency("org.bouncycastle:.*")) exclude(dependency("org.bouncycastle:.*"))
@@ -46,25 +67,29 @@ tasks {
} }
} }
build { publish {
dependsOn(shadowJar) dependsOn(shadowJar)
} }
}
/* // Needed by gradle-semantic-release-plugin.
Dummy task to hack gradle-semantic-release-plugin to release this project. // Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
Explanation: // The maven-publish is also necessary to make the signing plugin work.
SemVer is a standard for versioning libraries. publishing {
For that reason the semantic-release plugin uses the "publish" task to publish libraries. repositories {
However, this subproject is not a library, and the "publish" task is not available for this subproject. mavenLocal()
Because semantic-release is not designed to handle this case, we need to hack it. }
RE: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 publications {
*/ create<MavenPublication>("revanced-cli-publication") {
from(components["java"])
register<DefaultTask>("publish") { }
group = "publishing"
description = "Dummy task to hack gradle-semantic-release-plugin to release ReVanced CLI"
dependsOn(build)
} }
} }
signing {
useGpgCmd()
sign(publishing.publications["revanced-cli-publication"])
}

View File

@@ -4,8 +4,8 @@ To use ReVanced CLI, you will need to fulfill specific requirements.
## 🤝 Requirements ## 🤝 Requirements
- Java SDK 11 (Azul Zulu JDK or OpenJDK) - Java Runtime Environment 11 ([Azul Zulu JRE](https://www.azul.com/downloads/?version=java-11-lts&package=jdk#zulu) or [OpenJDK](https://jdk.java.net/archive/))
- [Android Debug Bridge (adb)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device - [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device
- An ABI other than ARMv7 such as x86 or x86-64 (or a custom AAPT binary that supports ARMv7) - An ABI other than ARMv7 such as x86 or x86-64 (or a custom AAPT binary that supports ARMv7)
## ⏭️ Whats next ## ⏭️ Whats next

View File

@@ -1,6 +1,6 @@
# 🛠️ Using ReVanced CLI # 🛠️ Using ReVanced CLI
Learn how to ReVanced CLI. Learn how to use ReVanced CLI.
## 🔨 Usage ## 🔨 Usage
@@ -26,7 +26,7 @@ ReVanced CLI is divided into the following fundamental commands:
This will generate an `options.json` file for the patches from a list of supplied patch bundles. This will generate an `options.json` file for the patches from a list of supplied patch bundles.
The file can be supplied to ReVanced CLI later on. The file can be supplied to ReVanced CLI later on.
```bash ```bash
java -jar revanced-cli.jar options \ java -jar revanced-cli.jar options \
--path options.json \ --path options.json \
@@ -34,36 +34,29 @@ ReVanced CLI is divided into the following fundamental commands:
revanced-patches.jar [<patch-bundle> ...] revanced-patches.jar [<patch-bundle> ...]
``` ```
> [!NOTE] > ** Note**
> A default `options.json` file will be automatically created, if it does not exist > A default `options.json` file will be automatically created if it does not exist
without any need for intervention when using the `patch` command. > without any need for intervention when using the `patch` command.
- ### 💉 Patch an app - ### 💉 Patch an app
You can patch apps by supplying patch bundles and the app to patch. You can patch apps by supplying patch bundles and the app to patch.
After patching, ReVanced CLI can install the patched app on your device using two methods: After patching, ReVanced CLI can install the patched app on your device using two methods:
> [!NOTE] > **💡 Tip**
> For ReVanced CLI to be able to install the patched app on your device, make sure ADB is working: > For ReVanced CLI to be able to install the patched app on your device, make sure ADB is working:
> >
> ```bash > ```bash
> adb shell exit > adb shell exit
> ``` > ```
> >
> To get your device's serial, run the following command:
>
> ```bash
> adb devices
> ```
>
> If you want to mount the patched app on top of the un-patched app, make sure you have root permissions: > If you want to mount the patched app on top of the un-patched app, make sure you have root permissions:
> >
> ```bash > ```bash
> adb shell su -c exit > adb shell su -c exit
> ``` > ```
>
> [!WARNING] > **⚠️ Warning**
> Some patches may require integrations > 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 `--merge`. ReVanced Patcher will automatically determine if they are necessary. > Supply them with the option `--merge`. ReVanced Patcher will automatically determine if they are necessary.
@@ -73,16 +66,15 @@ ReVanced CLI is divided into the following fundamental commands:
```bash ```bash
java -jar revanced-cli.jar patch \ java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \ --patch-bundle revanced-patches.jar \
--out patched-app.apk \ -d \
--device-serial <device-serial> \
input.apk input.apk
``` ```
- #### 👾 Patch an app and mount it on top of the un-patched app with root permissions - #### 👾 Patch an app and mount it on top of the un-patched app with root permissions
> [!IMPORTANT] > **❗ Caution**
> Ensure sure the same app you are patching and mounting over is installed on your device: > Ensure that the same app you are patching and mounting over is installed on your device:
> >
> ```bash > ```bash
> adb install app.apk > adb install app.apk
> ``` > ```
@@ -91,33 +83,47 @@ ReVanced CLI is divided into the following fundamental commands:
java -jar revanced-cli.jar patch \ java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \ --patch-bundle revanced-patches.jar \
--include "Some patch" \ --include "Some patch" \
--ii 123 \
--exclude "Some other patch" \ --exclude "Some other patch" \
--out patched-app.apk \ -d \
--device-serial <device-serial> \
--mount \ --mount \
app.apk app.apk
``` ```
> **💡 Tip**
> You can use the option `--ii` to include or `--ie` to exclude
> patches by their index in relation to supplied patch bundles,
> similarly to the option `--include` and `--exclude`.
>
> This is useful in case two patches have the same name, and you must include or exclude one.
> The patch index is calculated by the position of the patch in the list of patches
> from patch bundles supplied using the option `--patch-bundle`.
>
> You can list all patches with their indices using the command `list-patches`.
>
> Keep in mind that the indices can change based on the order of the patch bundles supplied,
> as well if the patch bundles are updated because patches can be added or removed.
- ### 🗑️ Uninstall an app - ### 🗑️ Uninstall an app
```bash ```bash
java -jar revanced-cli.jar utility uninstall \ java -jar revanced-cli.jar utility uninstall \
--package-name <package-name> \ --package-name <package-name> \
<device-serial> [<device-serial>]
``` ```
> [!NOTE] > **💡 Tip**
> You can unmount an APK file > You can unmount an APK file
by adding the option `--unmount`. > by adding the option `--unmount`.
- ### 📦 Install an app - ### 📦 Install an app
```bash ```bash
java -jar revanced-cli.jar utility install \ java -jar revanced-cli.jar utility install \
-a input.apk \ -a input.apk \
<device-serial> [<device-serial>]
``` ```
> [!NOTE] > **💡 Tip**
> You can mount an APK file > 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`. > by supplying the app's package name to mount the supplied APK file over the option `-mount`.

26
docs/2_building.md Normal file
View File

@@ -0,0 +1,26 @@
# 🔨️ Building
Build ReVanced CLI from source.
## 📝 Requirements
- Java Development Kit 11 (Azul Zulu JRE or OpenJDK)
## 🏗️ Building
To build ReVanced CLI, follow these steps:
1. Clone the repository:
```bash
git clone git@github.com:ReVanced/revanced-cli.git
cd revanced-cli
```
2. Build the project:
```bash
./gradlew build
```
After the build succeeds, the built JAR file will be located at `build/libs/revanced-cli-<version>-all.jar`.

View File

@@ -1,8 +1,9 @@
# 💻 Documentation and guides of ReVanced CLI # 💻 Documentation and guides of ReVanced CLI
This documentation explains how to use [ReVanced CLI](https://github.com/revanced/revanced-cli). This documentation contains topics around [ReVanced CLI](https://github.com/revanced/revanced-cli).
## 📖 Table of contents ## 📖 Table of contents
1. [💼 Prerequisites](0_prerequisites.md) 1. [💼 Prerequisites](0_prerequisites.md)
2. [🛠️ Using ReVanced CLI](1_usage.md) 2. [🛠️ Using ReVanced CLI](1_usage.md)
3. [🔨 Building ReVanced CLI](2_building.md)

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 = 4.0.2-dev.3 version = 4.4.2

View File

@@ -1,17 +1,18 @@
[versions] [versions]
shadow = "8.1.1" shadow = "8.1.1"
kotlin-test = "1.8.20-RC" kotlin = "1.9.22"
kotlinx-coroutines-core = "1.7.3" kotlinx-coroutines-core = "1.7.3"
picocli = "4.7.3" picocli = "4.7.5"
revanced-patcher = "17.0.0" revanced-patcher = "19.3.1"
revanced-library = "1.1.3" revanced-library = "2.2.1"
[libraries] [libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
picocli = { module = "info.picocli:picocli", version.ref = "picocli" } picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
revanced-patcher = { module = "app.revanced.revanced-patcher:revanced-patcher", version.ref = "revanced-patcher" } revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
revanced-library = { module = "app.revanced:revanced-library", version.ref = "revanced-library" } revanced-library = { module = "app.revanced:revanced-library", version.ref = "revanced-library" }
[plugins] [plugins]
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" } shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

View File

@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000 distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dist

5377
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
{ {
"devDependencies": { "devDependencies": {
"@saithodev/semantic-release-backmerge": "^3.1.0", "@saithodev/semantic-release-backmerge": "^4.0.1",
"@semantic-release/changelog": "^6.0.2", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.6", "gradle-semantic-release-plugin": "^1.9.1",
"semantic-release": "^20.1.0" "semantic-release": "^23.0.2"
} }
} }

View File

@@ -1 +1,7 @@
rootProject.name = "revanced-cli" rootProject.name = "revanced-cli"
buildCache {
local {
isEnabled = "CI" !in System.getenv()
}
}

View File

@@ -0,0 +1,67 @@
package app.revanced.cli.command
import app.revanced.library.PackageName
import app.revanced.library.PatchUtils
import app.revanced.library.VersionMap
import app.revanced.patcher.PatchBundleLoader
import picocli.CommandLine
import java.io.File
import java.util.logging.Logger
@CommandLine.Command(
name = "list-versions",
description = [
"List the most common compatible versions of apps that are compatible " +
"with the patches in the supplied patch bundles.",
],
)
internal class ListCompatibleVersions : Runnable {
private val logger = Logger.getLogger(ListCompatibleVersions::class.java.name)
@CommandLine.Parameters(
description = ["Paths to patch bundles."],
arity = "1..*",
)
private lateinit var patchBundles: Array<File>
@CommandLine.Option(
names = ["-f", "--filter-package-names"],
description = ["Filter patches by package name."],
)
private var packageNames: Set<String>? = null
@CommandLine.Option(
names = ["-u", "--count-unused-patches"],
description = ["Count patches that are not used by default."],
showDefaultValue = CommandLine.Help.Visibility.ALWAYS,
)
private var countUnusedPatches: Boolean = false
override fun run() {
val patches = PatchBundleLoader.Jar(*patchBundles)
fun VersionMap.buildVersionsString(): String {
if (isEmpty()) return "Any"
fun buildPatchesCountString(count: Int) = if (count == 1) "1 patch" else "$count patches"
return entries.joinToString("\n") { (version, count) ->
"$version (${buildPatchesCountString(count)})"
}
}
fun buildString(entry: Map.Entry<PackageName, VersionMap>) =
buildString {
val (name, versions) = entry
appendLine("Package name: $name")
appendLine("Most common compatible versions:")
appendLine(versions.buildVersionsString().prependIndent("\t"))
}
PatchUtils.getMostCommonCompatibleVersions(
patches,
packageNames,
countUnusedPatches,
).entries.joinToString("\n", transform = ::buildString).let(logger::info)
}
}

View File

@@ -8,92 +8,132 @@ import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File import java.io.File
import java.util.logging.Logger import java.util.logging.Logger
@Command(
@Command(name = "list-patches", description = ["List patches from supplied patch bundles."]) 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) private val logger = Logger.getLogger(ListPatchesCommand::class.java.name)
@Parameters( @Parameters(
description = ["Paths to patch bundles."], arity = "1..*" description = ["Paths to patch bundles."],
arity = "1..*",
) )
private lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@Option( @Option(
names = ["-d", "--with-descriptions"], description = ["List their descriptions."], showDefaultValue = ALWAYS names = ["-d", "--with-descriptions"],
description = ["List their descriptions."],
showDefaultValue = ALWAYS,
) )
private 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,
) )
private 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 apps the patches are compatible with."], description = ["List the versions of the apps the patches are compatible with."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var withVersions: Boolean = false private var withVersions: Boolean = false
@Option( @Option(
names = ["-o", "--with-options"], description = ["List the options of the patches."], showDefaultValue = ALWAYS names = ["-o", "--with-options"],
description = ["List the options of the patches."],
showDefaultValue = ALWAYS,
) )
private var withOptions: Boolean = false private var withOptions: Boolean = false
@Option( @Option(
names = ["-f", "--filter-package-name"], description = ["Filter patches by package name."] names = ["-u", "--with-universal-patches"],
description = ["List patches which are compatible with any app."],
showDefaultValue = ALWAYS,
)
private var withUniversalPatches: Boolean = true
@Option(
names = ["-i", "--index"],
description = ["List the index of each patch in relation to the supplied patch bundles."],
showDefaultValue = ALWAYS,
)
private var withIndex: Boolean = true
@Option(
names = ["-f", "--filter-package-name"],
description = ["Filter patches by package name."],
) )
private var packageName: String? = null private var packageName: String? = null
override fun run() { override fun run() {
fun Patch.CompatiblePackage.buildString() = buildString { fun Patch.CompatiblePackage.buildString() =
if (withVersions && versions != null) { buildString {
appendLine("Package name: $name") if (withVersions && versions != null) {
appendLine("Compatible versions:") appendLine("Package name: $name")
append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t")) appendLine("Compatible versions:")
} else append("Package name: $name") append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t"))
} } else {
append("Package name: $name")
fun PatchOption<*>.buildString() = buildString { }
appendLine("Title: $title")
appendLine("Description: $description")
value?.let {
appendLine("Key: $key")
append("Value: $it")
} ?: append("Key: $key")
}
fun Patch<*>.buildString() = buildString {
append("Name: $name")
if (withDescriptions) append("\nDescription: $description")
if (withOptions && options.isNotEmpty()) {
appendLine("\nOptions:")
append(
options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t")
)
} }
if (withPackages && compatiblePackages != null) { fun PatchOption<*>.buildString() =
appendLine("\nCompatible packages:") buildString {
append( appendLine("Title: $title")
compatiblePackages!!.joinToString("\n") { it.buildString() }.prependIndent("\t") description?.let { appendLine("Description: $it") }
) default?.let {
appendLine("Key: $key")
append("Default: $it")
} ?: append("Key: $key")
values?.let { values ->
appendLine("\nValid values:")
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}
} }
}
fun Patch<*>.anyPackageName(name: String) = compatiblePackages?.any { it.name == name } == true fun IndexedValue<Patch<*>>.buildString() =
let { (index, patch) ->
buildString {
if (withIndex) appendLine("Index: $index")
val patches = PatchBundleLoader.Jar(*patchBundles) append("Name: ${patch.name}")
val filtered = packageName?.let { patches.filter { patch -> patch.anyPackageName(it) } } ?: patches if (withDescriptions) append("\nDescription: ${patch.description}")
if (withOptions && patch.options.isNotEmpty()) {
appendLine("\nOptions:")
append(
patch.options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t"),
)
}
if (withPackages && patch.compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(
patch.compatiblePackages!!.joinToString("\n") {
it.buildString()
}.prependIndent("\t"),
)
}
}
}
fun Patch<*>.filterCompatiblePackages(name: String) =
compatiblePackages?.any { it.name == name }
?: withUniversalPatches
val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList()
val filtered =
packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() }) if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
} }
} }

View File

@@ -7,21 +7,24 @@ import picocli.CommandLine.Command
import picocli.CommandLine.IVersionProvider import picocli.CommandLine.IVersionProvider
import java.util.* import java.util.*
fun main(args: Array<String>) { fun main(args: Array<String>) {
Logger.setDefault() Logger.setDefault()
CommandLine(MainCommand).execute(*args) CommandLine(MainCommand).execute(*args).let(System::exit)
} }
private object CLIVersionProvider : IVersionProvider { private object CLIVersionProvider : IVersionProvider {
override fun getVersion() = arrayOf( override fun getVersion() =
MainCommand::class.java.getResourceAsStream( arrayOf(
"/app/revanced/cli/version.properties" MainCommand::class.java.getResourceAsStream(
)?.use { stream -> "/app/revanced/cli/version.properties",
Properties().apply { load(stream) }.let { )?.use { stream ->
"ReVanced CLI v${it.getProperty("version")}" Properties().apply {
} load(stream)
} ?: "ReVanced CLI") }.let {
"ReVanced CLI v${it.getProperty("version")}"
}
} ?: "ReVanced CLI",
)
} }
@Command( @Command(
@@ -30,10 +33,11 @@ private object CLIVersionProvider : IVersionProvider {
mixinStandardHelpOptions = true, mixinStandardHelpOptions = true,
versionProvider = CLIVersionProvider::class, versionProvider = CLIVersionProvider::class,
subcommands = [ subcommands = [
ListPatchesCommand::class,
PatchCommand::class, PatchCommand::class,
OptionsCommand::class, OptionsCommand::class,
ListPatchesCommand::class,
ListCompatibleVersions::class,
UtilityCommand::class, UtilityCommand::class,
] ],
) )
private object MainCommand private object MainCommand

View File

@@ -16,39 +16,47 @@ internal object OptionsCommand : Runnable {
private val logger = Logger.getLogger(OptionsCommand::class.java.name) private val logger = Logger.getLogger(OptionsCommand::class.java.name)
@CommandLine.Parameters( @CommandLine.Parameters(
description = ["Paths to patch bundles."], arity = "1..*" description = ["Paths to patch bundles."],
arity = "1..*",
) )
private lateinit var patchBundles: Array<File> private lateinit var patchBundles: Array<File>
@CommandLine.Option( @CommandLine.Option(
names = ["-p", "--path"], description = ["Path to patch options JSON file."], showDefaultValue = ALWAYS names = ["-p", "--path"],
description = ["Path to patch options JSON file."],
showDefaultValue = ALWAYS,
) )
private var filePath: File = File("options.json") private var filePath: File = File("options.json")
@CommandLine.Option( @CommandLine.Option(
names = ["-o", "--overwrite"], description = ["Overwrite existing options file."], showDefaultValue = ALWAYS names = ["-o", "--overwrite"],
description = ["Overwrite existing options file."],
showDefaultValue = ALWAYS,
) )
private 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,
) )
private var update: Boolean = false private var update: Boolean = false
override fun run() = try { override fun run() =
PatchBundleLoader.Jar(*patchBundles).let { patches -> try {
val exists = filePath.exists() PatchBundleLoader.Jar(*patchBundles).let { patches ->
if (!exists || overwrite) { val exists = filePath.exists()
if (exists && update) patches.setOptions(filePath) if (!exists || overwrite) {
if (exists && update) patches.setOptions(filePath)
Options.serialize(patches, prettyPrint = true).let(filePath::writeText) Options.serialize(patches, prettyPrint = true).let(filePath::writeText)
} else throw OptionsFileAlreadyExistsException() } else {
throw OptionsFileAlreadyExistsException()
}
}
} catch (ex: OptionsFileAlreadyExistsException) {
logger.severe("Options file already exists, use --overwrite to override it")
} }
} catch (ex: OptionsFileAlreadyExistsException) {
logger.severe("Options file already exists, use --overwrite to override it")
}
class OptionsFileAlreadyExistsException : Exception() class OptionsFileAlreadyExistsException : Exception()
} }

View File

@@ -1,13 +1,15 @@
package app.revanced.cli.command package app.revanced.cli.command
import app.revanced.library.ApkUtils import app.revanced.library.ApkUtils
import app.revanced.library.ApkUtils.applyTo
import app.revanced.library.ApkUtils.sign
import app.revanced.library.Options import app.revanced.library.Options
import app.revanced.library.Options.setOptions import app.revanced.library.Options.setOptions
import app.revanced.library.adb.AdbManager import app.revanced.library.adb.AdbManager
import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet import app.revanced.patcher.PatchSet
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions import app.revanced.patcher.PatcherConfig
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import picocli.CommandLine import picocli.CommandLine
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
@@ -18,9 +20,9 @@ import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.util.logging.Logger import java.util.logging.Logger
@CommandLine.Command( @CommandLine.Command(
name = "patch", description = ["Patch an APK file."] name = "patch",
description = ["Patch an APK file."],
) )
internal object PatchCommand : Runnable { internal object PatchCommand : Runnable {
private val logger = Logger.getLogger(PatchCommand::class.java.name) private val logger = Logger.getLogger(PatchCommand::class.java.name)
@@ -30,121 +32,167 @@ internal object PatchCommand : Runnable {
private lateinit var apk: File private lateinit var apk: File
private var integrations = listOf<File>() private var integrations = setOf<File>()
private var patchBundles = emptyList<File>() private var patchBundles = emptySet<File>()
@CommandLine.Option( @CommandLine.Option(
names = ["-i", "--include"], description = ["List of patches to include."] names = ["-i", "--include"],
description = ["List of patches to include."],
) )
private var includedPatches = arrayOf<String>() private var includedPatches = hashSetOf<String>()
@CommandLine.Option( @CommandLine.Option(
names = ["-e", "--exclude"], description = ["List of patches to exclude."] names = ["--ii"],
description = ["List of patches to include by their index in relation to the supplied patch bundles."],
) )
private var excludedPatches = arrayOf<String>() private var includedPatchesByIndex = arrayOf<Int>()
@CommandLine.Option( @CommandLine.Option(
names = ["--options"], description = ["Path to patch options JSON file."], showDefaultValue = ALWAYS names = ["-e", "--exclude"],
description = ["List of patches to exclude."],
) )
private var optionsFile: File = File("options.json") private var excludedPatches = hashSetOf<String>()
@CommandLine.Option(
names = ["--ei"],
description = ["List of patches to exclude by their index in relation to the supplied patch bundles."],
)
private var excludedPatchesByIndex = arrayOf<Int>()
@CommandLine.Option(
names = ["--options"],
description = ["Path to patch options JSON file."],
)
private var optionsFile: File? = null
@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,
) )
private var exclusive = false private var exclusive = false
@CommandLine.Option( @CommandLine.Option(
names = ["-f","--force"], names = ["-f", "--force"],
description = ["Bypass compatibility checks for the supplied APK's version."], description = ["Bypass compatibility checks for the supplied APK's version."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var force: Boolean = false private var force: Boolean = false
@CommandLine.Option( private var outputFilePath: File? = null
names = ["-o", "--out"], description = ["Path to save the patched APK file to."], required = true
)
private lateinit var outputFilePath: File
@CommandLine.Option( @CommandLine.Option(
names = ["-d", "--device-serial"], description = ["ADB device serial to install to."], showDefaultValue = ALWAYS names = ["-o", "--out"],
description = ["Path to save the patched APK file to. Defaults to the same directory as the supplied APK file."],
)
private fun setOutputFilePath(outputFilePath: File?) {
this.outputFilePath = outputFilePath?.absoluteFile
}
@CommandLine.Option(
names = ["-d", "--device-serial"],
description = ["ADB device serial to install to. If not supplied, the first connected device will be used."],
// Empty string to indicate that the first connected device should be used.
fallbackValue = "",
arity = "0..1",
) )
private var deviceSerial: String? = null private var deviceSerial: String? = null
@CommandLine.Option( @CommandLine.Option(
names = ["--mount"], description = ["Install by mounting the patched APK file."], showDefaultValue = ALWAYS names = ["--mount"],
description = ["Install by mounting the patched APK file."],
showDefaultValue = ALWAYS,
) )
private var mount: Boolean = false private var mount: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["--keystore"], description = ["Path to the keystore to sign the patched APK file with."], names = ["--keystore"],
description = [
"Path to the keystore to sign the patched APK file with. " +
"Defaults to the same directory as the supplied APK file.",
],
) )
private var keystoreFilePath: File? = null private var keystoreFilePath: File? = null
// key store password // key store password
@CommandLine.Option( @CommandLine.Option(
names = ["--keystore-password"], names = ["--keystore-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. Empty password by default."],
) )
private var keyStorePassword: String? = null // Empty password by default private var keyStorePassword: String? = null // Empty password by default
@CommandLine.Option( @CommandLine.Option(
names = ["--alias"], description = ["The alias of the key from the keystore to sign the patched APK file with."], names = ["--alias"],
showDefaultValue = ALWAYS description = ["The alias of the key from the keystore to sign the patched APK file with."],
showDefaultValue = ALWAYS,
) )
private var alias = "ReVanced Key" private var alias = "ReVanced Key"
@CommandLine.Option( @CommandLine.Option(
names = ["--keystore-entry-password"], names = ["--keystore-entry-password"],
description = ["The password of the entry from the keystore for the key to sign the patched APK file with."] description = ["The password of the entry from the keystore for the key to sign the patched APK file with."],
) )
private var password = "" // Empty password by default private var password = "" // Empty password by default
@CommandLine.Option( @CommandLine.Option(
names = ["--signer"], description = ["The name of the signer to sign the patched APK file with."], names = ["--signer"],
showDefaultValue = ALWAYS description = ["The name of the signer to sign the patched APK file with."],
showDefaultValue = ALWAYS,
) )
private var signer = "ReVanced" private var signer = "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
) )
private var resourceCachePath = File("revanced-resource-cache.") private var resourceCachePath: File? = null
set(value) {
logger.warning("The --resource-cache option is deprecated. Use --temporary-files-patch instead.")
field = value
temporaryFilesPath = value
}
@CommandLine.Option(
names = ["-t", "--temporary-files-path"],
description = ["Path to temporary files directory."],
)
private var temporaryFilesPath: File? = null
private var aaptBinaryPath: File? = null private var aaptBinaryPath: File? = null
@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,
) )
private var purge: Boolean = false private var purge: Boolean = false
@CommandLine.Option( @CommandLine.Option(
names = ["-w", "--warn"], names = ["-w", "--warn"],
description = ["Warn if a patch can not be found in the supplied patch bundles."], description = ["Warn if a patch can not be found in the supplied patch bundles."],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var warn: Boolean = false private var warn: Boolean = false
@CommandLine.Parameters( @CommandLine.Parameters(
description = ["APK file to be patched."], arity = "1..1" description = ["APK file to be patched."],
arity = "1..1",
) )
@Suppress("unused") @Suppress("unused")
private fun setApk(apk: File) { private fun setApk(apk: File) {
if (!apk.exists()) throw CommandLine.ParameterException( if (!apk.exists()) {
spec.commandLine(), throw CommandLine.ParameterException(
"APK file ${apk.name} does not exist" spec.commandLine(),
) "APK file ${apk.name} does not exist",
)
}
this.apk = apk this.apk = apk
} }
@CommandLine.Option( @CommandLine.Option(
names = ["-m", "--merge"], description = ["One or more DEX files or containers to merge into the APK."] names = ["-m", "--merge"],
description = ["One or more DEX files or containers to merge into the APK."],
) )
@Suppress("unused") @Suppress("unused")
private fun setIntegrations(integrations: Array<File>) { private fun setIntegrations(integrations: Array<File>) {
@@ -155,30 +203,56 @@ internal object PatchCommand : Runnable {
} }
@CommandLine.Option( @CommandLine.Option(
names = ["-b", "--patch-bundle"], description = ["One or more bundles of patches."], required = true names = ["-b", "--patch-bundle"],
description = ["One or more bundles of patches."],
required = true,
) )
@Suppress("unused") @Suppress("unused")
private fun setPatchBundles(patchBundles: Array<File>) { private fun setPatchBundles(patchBundles: Set<File>) {
patchBundles.firstOrNull { !it.exists() }?.let { patchBundles.firstOrNull { !it.exists() }?.let {
throw CommandLine.ParameterException(spec.commandLine(), "Patch bundle ${it.name} does not exist") throw CommandLine.ParameterException(spec.commandLine(), "Patch bundle ${it.name} does not exist")
} }
this.patchBundles = patchBundles.toList() this.patchBundles = patchBundles
} }
@CommandLine.Option( @CommandLine.Option(
names = ["--custom-aapt2-binary"], description = ["Path to a custom AAPT binary to compile resources with."] names = ["--custom-aapt2-binary"],
description = ["Path to a custom AAPT binary to compile resources with."],
) )
@Suppress("unused") @Suppress("unused")
private fun setAaptBinaryPath(aaptBinaryPath: File) { private fun setAaptBinaryPath(aaptBinaryPath: File) {
if (!aaptBinaryPath.exists()) throw CommandLine.ParameterException( if (!aaptBinaryPath.exists()) {
spec.commandLine(), throw CommandLine.ParameterException(
"AAPT binary ${aaptBinaryPath.name} does not exist" spec.commandLine(),
) "AAPT binary ${aaptBinaryPath.name} does not exist",
)
}
this.aaptBinaryPath = aaptBinaryPath this.aaptBinaryPath = aaptBinaryPath
} }
override fun run() { override fun run() {
val adbManager = deviceSerial?.let { serial -> AdbManager.getAdbManager(serial, mount) } // region Setup
val outputFilePath =
outputFilePath ?: File("").absoluteFile.resolve(
"${apk.nameWithoutExtension}-patched.${apk.extension}",
)
val temporaryFilesPath =
temporaryFilesPath ?: outputFilePath.parentFile.resolve(
"${outputFilePath.nameWithoutExtension}-temporary-files",
)
val optionsFile =
optionsFile ?: outputFilePath.parentFile.resolve(
"${outputFilePath.nameWithoutExtension}-options.json",
)
val keystoreFilePath =
keystoreFilePath ?: outputFilePath.parentFile
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
// endregion
// region Load patches // region Load patches
@@ -187,38 +261,43 @@ internal object PatchCommand : Runnable {
val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray()) val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray())
// Warn if a patch can not be found in the supplied patch bundles. // Warn if a patch can not be found in the supplied patch bundles.
if (warn) patches.map { it.name }.toHashSet().let { availableNames -> if (warn) {
arrayOf(*includedPatches, *excludedPatches).filter { name -> patches.map { it.name }.toHashSet().let { availableNames ->
!availableNames.contains(name) (includedPatches + excludedPatches).filter { name ->
!availableNames.contains(name)
}
}.let { unknownPatches ->
if (unknownPatches.isEmpty()) return@let
logger.warning("Unknown input of patches:\n${unknownPatches.joinToString("\n")}")
} }
}.let { unknownPatches ->
if (unknownPatches.isEmpty()) return@let
logger.warning("Unknown input of patches:\n${unknownPatches.joinToString("\n")}")
} }
// endregion // endregion
val (packageName, patcherResult) = Patcher(
Patcher( PatcherConfig(
PatcherOptions(
apk, apk,
resourceCachePath, temporaryFilesPath,
aaptBinaryPath?.path, aaptBinaryPath?.path,
resourceCachePath.absolutePath, temporaryFilesPath.absolutePath,
true true,
) ),
).use { patcher -> ).use { patcher ->
val filteredPatches = patcher.filterPatchSelection(patches).also { patches -> val filteredPatches =
logger.info("Setting patch options") patcher.filterPatchSelection(patches).also { patches ->
logger.info("Setting patch options")
if (optionsFile.exists()) patches.setOptions(optionsFile) if (optionsFile.exists()) {
else Options.serialize(patches, prettyPrint = true).let(optionsFile::writeText) patches.setOptions(optionsFile)
} } else {
Options.serialize(patches, prettyPrint = true).let(optionsFile::writeText)
}
}
// region Patch // region Patch
val patcherResult = patcher.apply { patcher.context.packageMetadata.packageName to patcher.apply {
acceptIntegrations(integrations) acceptIntegrations(integrations)
acceptPatches(filteredPatches.toList()) acceptPatches(filteredPatches)
// Execute patches. // Execute patches.
runBlocking { runBlocking {
@@ -232,102 +311,109 @@ internal object PatchCommand : Runnable {
} }
} }
}.get() }.get()
// endregion // endregion
}
// region Save // region Save
val alignedFile = resourceCachePath.resolve(apk.name).apply { apk.copyTo(outputFilePath, overwrite = true)
ApkUtils.copyAligned(apk, this, patcherResult)
}
val keystoreFilePath = keystoreFilePath ?: outputFilePath.absoluteFile.parentFile patcherResult.applyTo(outputFilePath)
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
if (!mount) ApkUtils.sign( if (!mount) {
alignedFile, outputFilePath.sign(
outputFilePath,
ApkUtils.SigningOptions( ApkUtils.SigningOptions(
keystoreFilePath, keystoreFilePath,
keyStorePassword, keyStorePassword,
alias, alias,
password, password,
signer signer,
) ),
) )
else alignedFile.renameTo(outputFilePath)
// endregion
// region Install
adbManager?.install(AdbManager.Apk(outputFilePath, patcher.context.packageMetadata.packageName))
// endregion
} }
logger.info("Saved to $outputFilePath")
// endregion
// region Install
deviceSerial?.let { serial ->
AdbManager.getAdbManager(deviceSerial = serial.ifEmpty { null }, mount)
}?.install(AdbManager.Apk(outputFilePath, packageName))
// endregion
if (purge) { if (purge) {
logger.info("Purging temporary files") logger.info("Purging temporary files")
purge(resourceCachePath) purge(temporaryFilesPath)
} }
} }
/** /**
* Filter the patches to be added to the patcher. The filter is based on the following: * Filter the patches to be added to the patcher. The filter is based on the following:
* *
* @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: PatchSet): PatchSet = buildSet { private fun Patcher.filterPatchSelection(patches: PatchSet): PatchSet =
val packageName = context.packageMetadata.packageName buildSet {
val packageVersion = context.packageMetadata.packageVersion val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion
patches.forEach patch@{ patch -> patches.withIndex().forEach patch@{ (i, patch) ->
val patchName = patch.name!! val patchName = patch.name!!
val explicitlyExcluded = excludedPatches.contains(patchName) val explicitlyExcluded = excludedPatches.contains(patchName) || excludedPatchesByIndex.contains(i)
if (explicitlyExcluded) return@patch logger.info("Excluding $patchName") if (explicitlyExcluded) return@patch logger.info("Excluding $patchName")
// Make sure the patch is compatible with the supplied APK files package name and version. // 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 { val matchesVersion =
it.any { version -> version == packageVersion } force || `package`.versions?.let {
} ?: true it.any { version -> version == packageVersion }
} ?: true
if (!matchesVersion) return@patch logger.warning( if (!matchesVersion) {
"$patchName is incompatible with version $packageVersion. " return@patch logger.warning(
+ "This patch is only compatible with version " "$patchName is incompatible with version $packageVersion. " +
+ packages.joinToString(";") { pkg -> "This patch is only compatible with version " +
pkg.versions!!.joinToString(", ") packages.joinToString(";") { pkg ->
pkg.versions!!.joinToString(", ")
},
)
} }
} ?: return@patch logger.fine(
"$patchName is incompatible with $packageName. " +
"This patch is only compatible with " +
packages.joinToString(", ") { `package` -> `package`.name },
) )
} ?: return@patch logger.fine(
"$patchName is incompatible with $packageName. "
+ "This patch is only compatible with "
+ packages.joinToString(", ") { `package` -> `package`.name })
return@let return@let
} ?: logger.fine("$patchName has no constraint on packages.") } ?: logger.fine("$patchName has no constraint on packages.")
// If the patch is implicitly used, it will be only included if [exclusive] is false. // If the patch is implicitly used, it will be only included if [exclusive] is false.
val implicitlyIncluded = !exclusive && patch.use val implicitlyIncluded = !exclusive && patch.use
// If the patch is explicitly used, it will be included even if [exclusive] is false. // If the patch is explicitly used, it will be included even if [exclusive] is false.
val explicitlyIncluded = includedPatches.contains(patchName) val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i)
val included = implicitlyIncluded || explicitlyIncluded val included = implicitlyIncluded || explicitlyIncluded
if (!included) return@patch logger.info("$patchName excluded") // Case 1. if (!included) return@patch logger.info("$patchName excluded") // Case 1.
logger.fine("Adding $patchName") logger.fine("Adding $patchName")
add(patch) add(patch)
}
} }
}
private fun purge(resourceCachePath: File) { private fun purge(resourceCachePath: File) {
val result = if (resourceCachePath.deleteRecursively()) "Purged resource cache directory" val result =
else "Failed to purge resource cache directory" if (resourceCachePath.deleteRecursively()) {
"Purged resource cache directory"
} else {
"Failed to purge resource cache directory"
}
logger.info(result) logger.info(result)
} }
} }

View File

@@ -5,20 +5,23 @@ import picocli.CommandLine.*
import java.io.File import java.io.File
import java.util.logging.Logger import java.util.logging.Logger
@Command( @Command(
name = "install", description = ["Install an APK file to devices with the supplied ADB device serials"] name = "install",
description = ["Install an APK file to devices with the supplied ADB device serials"],
) )
internal object InstallCommand : Runnable { internal object InstallCommand : Runnable {
private val logger = Logger.getLogger(InstallCommand::class.java.name) private val logger = Logger.getLogger(InstallCommand::class.java.name)
@Parameters( @Parameters(
description = ["ADB device serials"], arity = "1..*" description = ["ADB device serials. If not supplied, the first connected device will be used."],
arity = "0..*",
) )
private lateinit var deviceSerials: Array<String> private var deviceSerials: Array<String>? = null
@Option( @Option(
names = ["-a", "--apk"], description = ["APK file to be installed"], required = true names = ["-a", "--apk"],
description = ["APK file to be installed"],
required = true,
) )
private lateinit var apk: File private lateinit var apk: File
@@ -28,11 +31,14 @@ internal object InstallCommand : Runnable {
) )
private var packageName: String? = null private var packageName: String? = null
override fun run() = deviceSerials.forEach { deviceSerial -> override fun run() {
try { fun install(deviceSerial: String? = null) =
AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName)) try {
} catch (e: AdbManager.DeviceNotFoundException) { AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName))
logger.severe(e.toString()) } catch (e: AdbManager.DeviceNotFoundException) {
} logger.severe(e.toString())
}
deviceSerials?.forEach(::install) ?: install()
} }
} }

View File

@@ -5,32 +5,41 @@ import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS import picocli.CommandLine.Help.Visibility.ALWAYS
import java.util.logging.Logger import java.util.logging.Logger
@Command( @Command(
name = "uninstall", name = "uninstall",
description = ["Uninstall a patched app from the devices with the supplied ADB device serials"] description = ["Uninstall a patched app from the devices with the supplied ADB device serials"],
) )
internal object UninstallCommand : Runnable { internal object UninstallCommand : Runnable {
private val logger = Logger.getLogger(UninstallCommand::class.java.name) private val logger = Logger.getLogger(UninstallCommand::class.java.name)
@Parameters(description = ["ADB device serials"], arity = "1..*") @Parameters(
private lateinit var deviceSerials: Array<String> description = ["ADB device serials. If not supplied, the first connected device will be used."],
arity = "0..*",
)
private var deviceSerials: Array<String>? = null
@Option(names = ["-p", "--package-name"], description = ["Package name of the app to uninstall"], required = true) @Option(
names = ["-p", "--package-name"],
description = ["Package name of the app to uninstall"],
required = true,
)
private lateinit var packageName: String private lateinit var packageName: String
@Option( @Option(
names = ["-u", "--unmount"], names = ["-u", "--unmount"],
description = ["Uninstall by unmounting the patched APK file"], description = ["Uninstall by unmounting the patched APK file"],
showDefaultValue = ALWAYS showDefaultValue = ALWAYS,
) )
private var unmount: Boolean = false private var unmount: Boolean = false
override fun run() = deviceSerials.forEach { deviceSerial -> override fun run() {
try { fun uninstall(deviceSerial: String? = null) =
AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName) try {
} catch (e: AdbManager.DeviceNotFoundException) { AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName)
logger.severe(e.toString()) } catch (e: AdbManager.DeviceNotFoundException) {
} logger.severe(e.toString())
}
deviceSerials?.forEach { uninstall(it) } ?: uninstall()
} }
} }

View File

@@ -4,7 +4,7 @@ import picocli.CommandLine
@CommandLine.Command( @CommandLine.Command(
name = "utility", name = "utility",
description = ["Commands for utility purposes"], description = ["Commands for utility purposes."],
subcommands = [InstallCommand::class, UninstallCommand::class], subcommands = [InstallCommand::class, UninstallCommand::class],
) )
internal object UtilityCommand internal object UtilityCommand