mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-11 20:03:55 +01:00
Compare commits
2 Commits
v4.14.2-de
...
v2.200.1-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1041238632 | ||
|
|
e88d6a8bba |
@@ -1,3 +0,0 @@
|
|||||||
[*.{kt,kts}]
|
|
||||||
ktlint_code_style = intellij_idea
|
|
||||||
ktlint_standard_no-wildcard-imports = disabled
|
|
||||||
@@ -70,7 +70,7 @@ body:
|
|||||||
|
|
||||||
Before creating a new bug report, please keep the following in mind:
|
Before creating a new bug report, please keep the following in mind:
|
||||||
|
|
||||||
- **Do not submit a duplicate bug report**: Search for existing bug reports [here](https://github.com/ReVanced/revanced-patches/issues?q=label%3A%22Bug+report%22).
|
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-patches/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-patches/blob/main/CONTRIBUTING.md).
|
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-patches/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).
|
- **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
|
- type: textarea
|
||||||
@@ -102,7 +102,7 @@ body:
|
|||||||
label: Acknowledgements
|
label: Acknowledgements
|
||||||
description: Your bug report will be closed if you don't follow the checklist below.
|
description: Your bug report will be closed if you don't follow the checklist below.
|
||||||
options:
|
options:
|
||||||
- label: I have checked all open and closed bug reports and this is not a duplicate.
|
- label: This issue is not a duplicate of an existing bug report.
|
||||||
required: true
|
required: true
|
||||||
- label: I have chosen an appropriate title.
|
- label: I have chosen an appropriate title.
|
||||||
required: true
|
required: true
|
||||||
@@ -70,8 +70,8 @@ body:
|
|||||||
|
|
||||||
Before creating a new feature request, please keep the following in mind:
|
Before creating a new feature request, please keep the following in mind:
|
||||||
|
|
||||||
- **Do not submit a duplicate feature request**: Search for existing feature requests [here](https://github.com/ReVanced/revanced-patches/issues?q=label%3A%22Feature+request%22).
|
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-patches/labels/Feature%20request).
|
||||||
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-patches/blob/main/CONTRIBUTING.md).
|
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-patches/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).
|
- **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
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
@@ -98,7 +98,7 @@ body:
|
|||||||
label: Acknowledgements
|
label: Acknowledgements
|
||||||
description: Your feature request will be closed if you don't follow the checklist below.
|
description: Your feature request will be closed if you don't follow the checklist below.
|
||||||
options:
|
options:
|
||||||
- label: I have checked all open and closed feature requests and this is not a duplicate
|
- label: This issue is not a duplicate of an existing feature request.
|
||||||
required: true
|
required: true
|
||||||
- label: I have chosen an appropriate title.
|
- label: I have chosen an appropriate title.
|
||||||
required: true
|
required: true
|
||||||
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
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
|
|
||||||
25
.github/workflows/build_pull_request.yml
vendored
25
.github/workflows/build_pull_request.yml
vendored
@@ -1,25 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -20,8 +20,8 @@ jobs:
|
|||||||
- name: Open pull request
|
- name: Open pull request
|
||||||
uses: repo-sync/pull-request@v2
|
uses: repo-sync/pull-request@v2
|
||||||
with:
|
with:
|
||||||
destination_branch: "main"
|
destination_branch: 'main'
|
||||||
pr_title: "chore: ${{ env.MESSAGE }}"
|
pr_title: 'chore: ${{ env.MESSAGE }}'
|
||||||
pr_body: |
|
pr_body: |
|
||||||
This pull request will ${{ env.MESSAGE }}.
|
This pull request will ${{ env.MESSAGE }}.
|
||||||
|
|
||||||
35
.github/workflows/pull_strings.yml
vendored
35
.github/workflows/pull_strings.yml
vendored
@@ -1,35 +0,0 @@
|
|||||||
name: Pull strings
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: 0 0 1 * *
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
pull:
|
|
||||||
name: Pull strings
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: dev
|
|
||||||
|
|
||||||
- name: Pull strings
|
|
||||||
uses: crowdin/github-action@v2
|
|
||||||
with:
|
|
||||||
config: crowdin.yml
|
|
||||||
download_translations: true
|
|
||||||
localization_branch_name: feat/translations
|
|
||||||
create_pull_request: true
|
|
||||||
pull_request_title: "chore: Sync translations"
|
|
||||||
pull_request_body: "Sync translations from [crowdin.com/project/revanced](https://crowdin.com/project/revanced)"
|
|
||||||
pull_request_base_branch_name: "dev"
|
|
||||||
commit_message: "chore: Sync translations"
|
|
||||||
github_user_name: revanced-bot
|
|
||||||
github_user_email: github@revanced.app
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
|
||||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
|
||||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
|
||||||
29
.github/workflows/push_strings.yml
vendored
29
.github/workflows/push_strings.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
name: Push strings
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- src/main/resources/addresources/values/strings.xml
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
push:
|
|
||||||
name: Push strings
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Push strings
|
|
||||||
uses: crowdin/github-action@v2
|
|
||||||
with:
|
|
||||||
config: crowdin.yml
|
|
||||||
upload_sources: true
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
|
||||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
|
||||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
|
||||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -6,6 +6,10 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -20,30 +24,24 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Cache Node modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
node_modules
|
||||||
|
key: npm-${{ hashFiles('package-lock.json') }}
|
||||||
|
|
||||||
- name: Cache Gradle
|
- name: Cache Gradle
|
||||||
uses: burrunan/gradle-cache-action@v1
|
uses: burrunan/gradle-cache-action@v1
|
||||||
|
|
||||||
- name: Build
|
- name: Build with Gradle
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew generateMeta clean
|
run: ./gradlew generateMeta clean
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup semantic-release
|
||||||
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: ${{ vars.GPG_FINGERPRINT }}
|
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||||
|
|||||||
18
.github/workflows/update-gradle-wrapper.yml
vendored
18
.github/workflows/update-gradle-wrapper.yml
vendored
@@ -1,18 +0,0 @@
|
|||||||
name: Update Gradle wrapper
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 1 * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Update Gradle Wrapper
|
|
||||||
uses: gradle-update/update-gradle-wrapper-action@v1
|
|
||||||
with:
|
|
||||||
target-branch: dev
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
{
|
{
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"path": "build/libs/revanced-patches*"
|
"path": "build/libs/*.jar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "patches.json"
|
"path": "patches.json"
|
||||||
|
|||||||
2112
CHANGELOG.md
2112
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -64,15 +64,15 @@ This document describes how to contribute to ReVanced Patches.
|
|||||||
|
|
||||||
## 📖 Resources to help you get started
|
## 📖 Resources to help you get started
|
||||||
|
|
||||||
* The [documentation](https://github.com/ReVanced/revanced-patcher/tree/main/docs) contains the fundamentals
|
* The [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs) provides the fundamentals of patches
|
||||||
of ReVanced Patcher and how to use ReVanced Patcher to create patches
|
and everything necessary to create your own patch from scratch
|
||||||
* [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-patches/issues) are where we keep track of bugs and feature requests
|
* [Issues](https://github.com/ReVanced/revanced-patches/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-patches/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
|
[Feature request issue template](https://github.com/ReVanced/revanced-patches/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 Patches.
|
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Patches.
|
||||||
@@ -81,11 +81,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 Patches, open an issue using the
|
If you encounter a bug while using ReVanced Patches, open an issue using the
|
||||||
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
|
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+).
|
||||||
|
|
||||||
## 🌐 Submitting translations
|
|
||||||
|
|
||||||
You can contribute translations at [translate.revanced.app](https://translate.revanced.app).
|
|
||||||
|
|
||||||
## 🧑⚖️ Guidelines for requesting or contributing patches
|
## 🧑⚖️ Guidelines for requesting or contributing patches
|
||||||
|
|
||||||
@@ -111,6 +107,7 @@ are unaffected by this change.
|
|||||||
* Payment circumvention: We do not accept patches that exist solely to bypass payment for the app or any of its features
|
* Payment circumvention: We do not accept patches that exist solely to bypass payment for the app or any of its features
|
||||||
* Malicious patches: Patches that are malicious in nature are not allowed
|
* Malicious patches: Patches that are malicious in nature are not allowed
|
||||||
|
|
||||||
|
|
||||||
## 📝 How to contribute
|
## 📝 How to contribute
|
||||||
|
|
||||||
1. Before contributing, it is recommended to open an issue to discuss your change
|
1. Before contributing, it is recommended to open an issue to discuss your change
|
||||||
@@ -118,7 +115,7 @@ with the maintainers of ReVanced Patches. This will help you determine whether y
|
|||||||
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. In case you are contributing a new patch, make sure to follow the conventions for patches
|
3. Commit your changes. In case you are contributing a new patch, make sure to follow the conventions for patches
|
||||||
described in the [ReVanced Patcher documentation](https://github.com/ReVanced/revanced-patcher/tree/main/docs)
|
described in the [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs)
|
||||||
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,
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -67,7 +67,7 @@ This repository contains a collection of ReVanced Patches.
|
|||||||
|
|
||||||
## ❓ About
|
## ❓ About
|
||||||
|
|
||||||
Patches are small modifications to Android apps that allow you to change the behavior of or add new features,
|
Patches are small modifications to Android apps that allow you to change the behaviour of or add new features,
|
||||||
block ads, customize the appearance, and much more.
|
block ads, customize the appearance, and much more.
|
||||||
|
|
||||||
## 💪 Features
|
## 💪 Features
|
||||||
@@ -81,7 +81,7 @@ Some of the features the patches provide are:
|
|||||||
export activities, etc.
|
export activities, etc.
|
||||||
* ✨ **And much more!**
|
* ✨ **And much more!**
|
||||||
|
|
||||||
For a complete list of all available patches, visit [revanced.app/patches](https://revanced.app/patches).
|
For a full list of all available patches, visit [revanced.app/patches](https://revanced.app/patches).
|
||||||
|
|
||||||
## 🚀 How to get started
|
## 🚀 How to get started
|
||||||
|
|
||||||
@@ -93,13 +93,17 @@ You can use [ReVanced CLI](https://github.com/ReVanced/revanced-cli) or [ReVance
|
|||||||
|
|
||||||
Thank you for considering contributing to ReVanced Patches. You can find the contribution guidelines [here](CONTRIBUTING.md).
|
Thank you for considering contributing to ReVanced Patches. You can find the contribution guidelines [here](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
### 📃 Documentation
|
||||||
|
|
||||||
|
The documentation provides the fundamentals of patches and everything necessary to create your own patch from scratch.
|
||||||
|
You can find it [here](https://github.com/ReVanced/revanced-patches/tree/docs/docs).
|
||||||
|
|
||||||
### 🛠️ Building
|
### 🛠️ Building
|
||||||
|
|
||||||
To build ReVanced Patches, you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
|
In order to build ReVanced Patches, you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
|
||||||
|
|
||||||
## 📜 Licence
|
## 📜 Licence
|
||||||
|
|
||||||
ReVanced Patches is licensed under the GPLv3 license. Please see the [license file](LICENSE) for more information.
|
ReVanced Patches is licensed under the GPLv3 licence. Please see the [licence 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 Patches 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 patches as long as you track changes/dates in source files.
|
||||||
Any modifications to ReVanced Patches must also be made available under the GPL,
|
Any modifications to ReVanced Patches must also be made available under the GPL along with build & install instructions.
|
||||||
along with build & install instructions.
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,8 @@
|
|||||||
import org.gradle.kotlin.dsl.support.listFilesOrdered
|
import org.gradle.kotlin.dsl.support.listFilesOrdered
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin)
|
kotlin("jvm") version "1.9.10"
|
||||||
alias(libs.plugins.binary.compatibility.validator)
|
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
signing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "app.revanced"
|
group = "app.revanced"
|
||||||
@@ -14,12 +11,12 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
google()
|
google()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
|
// Required for FlexVer-Java
|
||||||
maven {
|
maven {
|
||||||
// A repository must be specified for some reason. "registry" is a dummy.
|
url = uri("https://repo.sleeping.town")
|
||||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
content {
|
||||||
credentials {
|
includeGroup("com.unascribed")
|
||||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
|
||||||
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,40 +28,18 @@ dependencies {
|
|||||||
implementation(libs.guava)
|
implementation(libs.guava)
|
||||||
// Used in JsonGenerator.
|
// Used in JsonGenerator.
|
||||||
implementation(libs.gson)
|
implementation(libs.gson)
|
||||||
// Android API stubs defined here.
|
|
||||||
compileOnly(project(":stub"))
|
// A dependency to the Android library unfortunately fails the build, which is why this is required.
|
||||||
|
compileOnly(project("dummy"))
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
compilerOptions {
|
jvmToolchain(11)
|
||||||
jvmTarget.set(JvmTarget.JVM_11)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
withType(Jar::class) {
|
register<DefaultTask>("generateBundle") {
|
||||||
exclude("app/revanced/meta")
|
description = "Generate dex files from build and bundle them in the jar file"
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes["Name"] = "ReVanced Patches"
|
|
||||||
attributes["Description"] = "Patches for ReVanced."
|
|
||||||
attributes["Version"] = version
|
|
||||||
attributes["Timestamp"] = System.currentTimeMillis().toString()
|
|
||||||
attributes["Source"] = "git@github.com:revanced/revanced-patches.git"
|
|
||||||
attributes["Author"] = "ReVanced"
|
|
||||||
attributes["Contact"] = "contact@revanced.app"
|
|
||||||
attributes["Origin"] = "https://revanced.app"
|
|
||||||
attributes["License"] = "GNU General Public License v3.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register("buildDexJar") {
|
|
||||||
description = "Build and add a DEX to the JAR file"
|
|
||||||
group = "build"
|
|
||||||
|
|
||||||
dependsOn(build)
|
dependsOn(build)
|
||||||
|
|
||||||
@@ -72,50 +47,39 @@ tasks {
|
|||||||
val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools")
|
val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools")
|
||||||
.listFilesOrdered().last().resolve("d8").absolutePath
|
.listFilesOrdered().last().resolve("d8").absolutePath
|
||||||
|
|
||||||
val patchesJar = configurations.archives.get().allArtifacts.files.files.first().absolutePath
|
val artifacts = configurations.archives.get().allArtifacts.files.files.first().absolutePath
|
||||||
val workingDirectory = layout.buildDirectory.dir("libs").get().asFile
|
val workingDirectory = layout.buildDirectory.dir("libs").get().asFile
|
||||||
|
|
||||||
exec {
|
exec {
|
||||||
workingDir = workingDirectory
|
workingDir = workingDirectory
|
||||||
commandLine = listOf(d8, "--release", patchesJar)
|
commandLine = listOf(d8, artifacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
exec {
|
exec {
|
||||||
workingDir = workingDirectory
|
workingDir = workingDirectory
|
||||||
commandLine = listOf("zip", "-u", patchesJar, "classes.dex")
|
commandLine = listOf("zip", "-u", artifacts, "classes.dex")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register<JavaExec>("generatePatchesFiles") {
|
register<JavaExec>("generateMeta") {
|
||||||
description = "Generate patches files"
|
description = "Generate metadata for this bundle"
|
||||||
|
|
||||||
dependsOn(build)
|
dependsOn(build)
|
||||||
|
|
||||||
classpath = sourceSets["main"].runtimeClasspath
|
classpath = sourceSets["main"].runtimeClasspath
|
||||||
mainClass.set("app.revanced.generator.MainKt")
|
mainClass.set("app.revanced.meta.PatchesFileGenerator")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed by gradle-semantic-release-plugin.
|
// Required to run tasks because Gradle semantic-release plugin runs the publish task.
|
||||||
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
||||||
publish {
|
named("publish") {
|
||||||
dependsOn("buildDexJar")
|
dependsOn("generateBundle")
|
||||||
dependsOn("generatePatchesFiles")
|
dependsOn("generateMeta")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name = "GitHubPackages"
|
|
||||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patches")
|
|
||||||
credentials {
|
|
||||||
username = System.getenv("GITHUB_ACTOR")
|
|
||||||
password = System.getenv("GITHUB_TOKEN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publications {
|
publications {
|
||||||
create<MavenPublication>("revanced-patches-publication") {
|
create<MavenPublication>("revanced-patches-publication") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
@@ -147,9 +111,3 @@ publishing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signing {
|
|
||||||
useGpgCmd()
|
|
||||||
|
|
||||||
sign(publishing.publications["revanced-patches-publication"])
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
project_id_env: "CROWDIN_PROJECT_ID"
|
|
||||||
api_token_env: "CROWDIN_PERSONAL_TOKEN"
|
|
||||||
|
|
||||||
preserve_hierarchy: false
|
|
||||||
files:
|
|
||||||
- source: src/main/resources/addresources/values/strings.xml
|
|
||||||
translation: src/main/resources/addresources/values-%android_code%/strings.xml
|
|
||||||
skip_untranslated_strings: true
|
|
||||||
9
dummy/build.gradle.kts
Normal file
9
dummy/build.gradle.kts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(11))
|
||||||
|
}
|
||||||
|
}
|
||||||
9
dummy/src/main/java/android/os/Environment.java
Normal file
9
dummy/src/main/java/android/os/Environment.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package android.os;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public final class Environment {
|
||||||
|
public static File getExternalStorageDirectory() {
|
||||||
|
throw new UnsupportedOperationException("Stub");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.14.2-dev.2
|
version = 2.200.1-dev.1
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
[versions]
|
[versions]
|
||||||
revanced-patcher = "19.3.1"
|
revanced-patcher = "19.0.0"
|
||||||
#noinspection GradleDependency
|
smali = "3.0.3"
|
||||||
smali = "3.0.5" # 3.0.7 breaks binary compatibility. Tracking https://github.com/google/smali/issues/58.
|
guava = "32.1.2-jre"
|
||||||
guava = "33.2.1-jre"
|
gson = "2.10.1"
|
||||||
gson = "2.11.0"
|
|
||||||
binary-compatibility-validator = "0.15.1"
|
|
||||||
kotlin = "2.0.0"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
||||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||||
|
|
||||||
[plugins]
|
|
||||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
8
gradle/wrapper/gradle-wrapper.properties
vendored
8
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,8 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dist
|
||||||
17
gradlew
vendored
17
gradlew
vendored
@@ -83,8 +83,7 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -145,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@@ -153,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -202,11 +201,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command;
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
# and any embedded shellness will be escaped.
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
|||||||
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|||||||
11421
package-lock.json
generated
11421
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
"@saithodev/semantic-release-backmerge": "^3.2.1",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.9.2",
|
"gradle-semantic-release-plugin": "^1.8.0",
|
||||||
"semantic-release": "^24.0.0"
|
"semantic-release": "^22.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
patches.json
Normal file
1
patches.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,9 +1,9 @@
|
|||||||
|
include("dummy")
|
||||||
|
|
||||||
rootProject.name = "revanced-patches"
|
rootProject.name = "revanced-patches"
|
||||||
|
|
||||||
buildCache {
|
buildCache {
|
||||||
local {
|
local {
|
||||||
isEnabled = "CI" !in System.getenv()
|
isEnabled = !System.getenv().containsKey("CI")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
include(":stub")
|
|
||||||
|
|||||||
127
src/main/kotlin/app/revanced/extensions/Extensions.kt
Normal file
127
src/main/kotlin/app/revanced/extensions/Extensions.kt
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package app.revanced.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.patcher.patch.PatchException
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||||
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
|
import org.w3c.dom.Node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [PatchException] of failing to resolve a [MethodFingerprint].
|
||||||
|
*
|
||||||
|
* @return The [PatchException].
|
||||||
|
*/
|
||||||
|
val MethodFingerprint.exception
|
||||||
|
get() = PatchException("Failed to resolve ${this.javaClass.simpleName}")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the [MutableMethod] from a given [Method] in a [MutableClass].
|
||||||
|
*
|
||||||
|
* @param method The [Method] to find.
|
||||||
|
* @return The [MutableMethod].
|
||||||
|
*/
|
||||||
|
fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first {
|
||||||
|
MethodUtil.methodSignaturesMatch(it, method)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* apply a transform to all methods of the class.
|
||||||
|
*
|
||||||
|
* @param transform the transformation function. original method goes in, transformed method goes out.
|
||||||
|
*/
|
||||||
|
fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) {
|
||||||
|
val transformedMethods = methods.map { it.transform() }
|
||||||
|
methods.clear()
|
||||||
|
methods.addAll(transformedMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Node.doRecursively(action: (Node) -> Unit) {
|
||||||
|
action(this)
|
||||||
|
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MutableMethod.injectHideViewCall(
|
||||||
|
insertIndex: Int,
|
||||||
|
viewRegister: Int,
|
||||||
|
classDescriptor: String,
|
||||||
|
targetMethod: String
|
||||||
|
) = addInstruction(
|
||||||
|
insertIndex,
|
||||||
|
"invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the index of the first instruction with the id of the given resource name.
|
||||||
|
*
|
||||||
|
* @param resourceName the name of the resource to find the id for.
|
||||||
|
* @return the index of the first instruction with the id of the given resource name, or -1 if not found.
|
||||||
|
*/
|
||||||
|
fun Method.findIndexForIdResource(resourceName: String): Int {
|
||||||
|
fun getIdResourceId(resourceName: String) = ResourceMappingPatch.resourceMappings.single {
|
||||||
|
it.type == "id" && it.name == resourceName
|
||||||
|
}.id
|
||||||
|
|
||||||
|
return indexOfFirstWideLiteralInstructionValue(getIdResourceId(resourceName))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the index of the first wide literal instruction with the given value.
|
||||||
|
*
|
||||||
|
* @return the first literal instruction with the value, or -1 if not found.
|
||||||
|
*/
|
||||||
|
fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let {
|
||||||
|
it.instructions.indexOfFirst { instruction ->
|
||||||
|
(instruction as? WideLiteralInstruction)?.wideLiteral == literal
|
||||||
|
}
|
||||||
|
} ?: -1
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the method contains a literal with the given value.
|
||||||
|
*
|
||||||
|
* @return if the method contains a literal with the given value.
|
||||||
|
*/
|
||||||
|
fun Method.containsWideLiteralInstructionValue(literal: Long) =
|
||||||
|
indexOfFirstWideLiteralInstructionValue(literal) >= 0
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverse the class hierarchy starting from the given root class.
|
||||||
|
*
|
||||||
|
* @param targetClass the class to start traversing the class hierarchy from.
|
||||||
|
* @param callback function that is called for every class in the hierarchy.
|
||||||
|
*/
|
||||||
|
fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) {
|
||||||
|
callback(targetClass)
|
||||||
|
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
|
||||||
|
traverseClassHierarchy(it, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the [Reference] of an [Instruction] as [T].
|
||||||
|
*
|
||||||
|
* @param T The type of [Reference] to cast to.
|
||||||
|
* @return The [Reference] as [T] or null
|
||||||
|
* if the [Instruction] is not a [ReferenceInstruction] or the [Reference] is not of type [T].
|
||||||
|
* @see ReferenceInstruction
|
||||||
|
*/
|
||||||
|
inline fun <reified T : Reference> Instruction.getReference() = (this as? ReferenceInstruction)?.reference as? T
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the first [Instruction] that matches the predicate.
|
||||||
|
*
|
||||||
|
* @param predicate The predicate to match.
|
||||||
|
* @return The index of the first [Instruction] that matches the predicate.
|
||||||
|
*/
|
||||||
|
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) =
|
||||||
|
this.implementation!!.instructions.indexOfFirst(predicate)
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app.revanced.generator
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchBundleLoader
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
internal fun main() = PatchBundleLoader.Jar(
|
|
||||||
File("build/libs/").listFiles { it -> it.name.endsWith(".jar") }!!.first(),
|
|
||||||
).also { loader ->
|
|
||||||
if (loader.isEmpty()) throw IllegalStateException("No patches found")
|
|
||||||
}.let { bundle ->
|
|
||||||
arrayOf(JsonPatchesFileGenerator()).forEach { generator -> generator.generate(bundle) }
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.generator
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchSet
|
|
||||||
|
|
||||||
internal interface PatchesFileGenerator {
|
|
||||||
fun generate(patches: PatchSet)
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package app.revanced.generator
|
package app.revanced.meta
|
||||||
|
|
||||||
import app.revanced.patcher.PatchSet
|
import app.revanced.patcher.PatchSet
|
||||||
import app.revanced.patcher.patch.Patch
|
import app.revanced.patcher.patch.Patch
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class JsonPatchesFileGenerator : PatchesFileGenerator {
|
internal class JsonGenerator : PatchesFileGenerator {
|
||||||
override fun generate(patches: PatchSet) = patches.map {
|
override fun generate(patches: PatchSet) = patches.map {
|
||||||
JsonPatch(
|
JsonPatch(
|
||||||
it.name!!,
|
it.name!!,
|
||||||
@@ -20,9 +20,9 @@ internal class JsonPatchesFileGenerator : PatchesFileGenerator {
|
|||||||
option.values,
|
option.values,
|
||||||
option.title,
|
option.title,
|
||||||
option.description,
|
option.description,
|
||||||
option.required,
|
option.required
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
}.let {
|
}.let {
|
||||||
File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it))
|
File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it))
|
||||||
@@ -35,7 +35,7 @@ internal class JsonPatchesFileGenerator : PatchesFileGenerator {
|
|||||||
val compatiblePackages: Set<Patch.CompatiblePackage>? = null,
|
val compatiblePackages: Set<Patch.CompatiblePackage>? = null,
|
||||||
val use: Boolean = true,
|
val use: Boolean = true,
|
||||||
val requiresIntegrations: Boolean = false,
|
val requiresIntegrations: Boolean = false,
|
||||||
val options: List<Option>,
|
val options: List<Option>
|
||||||
) {
|
) {
|
||||||
class Option(
|
class Option(
|
||||||
val key: String,
|
val key: String,
|
||||||
20
src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt
Normal file
20
src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package app.revanced.meta
|
||||||
|
|
||||||
|
import app.revanced.patcher.PatchBundleLoader
|
||||||
|
import app.revanced.patcher.PatchSet
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal interface PatchesFileGenerator {
|
||||||
|
fun generate(patches: PatchSet)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) = PatchBundleLoader.Jar(
|
||||||
|
File("build/libs/").listFiles { it -> it.name.endsWith(".jar") }!!.first()
|
||||||
|
).also { loader ->
|
||||||
|
if (loader.isEmpty()) throw IllegalStateException("No patches found")
|
||||||
|
}.let { bundle ->
|
||||||
|
arrayOf(JsonGenerator()).forEach { generator -> generator.generate(bundle) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,16 +7,14 @@ import app.revanced.patcher.patch.annotation.Patch
|
|||||||
@Patch(
|
@Patch(
|
||||||
name = "Export all activities",
|
name = "Export all activities",
|
||||||
description = "Makes all app activities exportable.",
|
description = "Makes all app activities exportable.",
|
||||||
use = false,
|
use = false
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ExportAllActivitiesPatch : ResourcePatch() {
|
object ExportAllActivitiesPatch : ResourcePatch() {
|
||||||
private const val EXPORTED_FLAG = "android:exported"
|
private const val EXPORTED_FLAG = "android:exported"
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val document = editor.file
|
val document = editor.file
|
||||||
|
|
||||||
val activities = document.getElementsByTagName("activity")
|
val activities = document.getElementsByTagName("activity")
|
||||||
|
|
||||||
for(i in 0..activities.length) {
|
for(i in 0..activities.length) {
|
||||||
@@ -24,14 +22,12 @@ object ExportAllActivitiesPatch : ResourcePatch() {
|
|||||||
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
|
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
|
||||||
|
|
||||||
if (exportedAttribute != null) {
|
if (exportedAttribute != null) {
|
||||||
if (exportedAttribute.nodeValue != "true") {
|
if (exportedAttribute.nodeValue != "true")
|
||||||
exportedAttribute.nodeValue = "true"
|
exportedAttribute.nodeValue = "true"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Reason why the attribute is added in the case it does not exist:
|
// Reason why the attribute is added in the case it does not exist:
|
||||||
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
|
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
|
||||||
else {
|
else document.createAttribute(EXPORTED_FLAG)
|
||||||
document.createAttribute(EXPORTED_FLAG)
|
|
||||||
.apply { value = "true" }
|
.apply { value = "true" }
|
||||||
.let(attributes::setNamedItem)
|
.let(attributes::setNamedItem)
|
||||||
}
|
}
|
||||||
@@ -39,4 +35,3 @@ object ExportAllActivitiesPatch : ResourcePatch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package app.revanced.patches.all.connectivity.wifi.spoof
|
|||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
import app.revanced.util.patch.IMethodCall
|
||||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
import app.revanced.util.patch.Instruction35cInfo
|
||||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
import app.revanced.util.patch.filterMapInstruction35c
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
@@ -17,8 +17,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|||||||
requiresIntegrations = true
|
requiresIntegrations = true
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object SpoofWifiPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
object SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/integrations/all/connectivity/wifi/spoof/SpoofWifiPatch"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch"
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
||||||
|
|
||||||
override fun filterMap(
|
override fun filterMap(
|
||||||
@@ -40,7 +40,7 @@ object SpoofWifiPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
|||||||
|
|
||||||
|
|
||||||
// Information about method calls we want to replace
|
// Information about method calls we want to replace
|
||||||
private enum class MethodCall(
|
enum class MethodCall(
|
||||||
override val definedClassName: String,
|
override val definedClassName: String,
|
||||||
override val methodName: String,
|
override val methodName: String,
|
||||||
override val methodParams: Array<String>,
|
override val methodParams: Array<String>,
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
package app.revanced.patches.all.directory
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Change data directory location",
|
|
||||||
description = "Changes the data directory in the application from " +
|
|
||||||
"the app internal storage directory to /sdcard/android/data accessible by root-less devices." +
|
|
||||||
"Using this patch can cause unexpected issues with some apps.",
|
|
||||||
use = false,
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object ChangeDataDirectoryLocationPatch : BaseTransformInstructionsPatch<Int>() {
|
|
||||||
override fun filterMap(
|
|
||||||
classDef: ClassDef,
|
|
||||||
method: Method,
|
|
||||||
instruction: Instruction,
|
|
||||||
instructionIndex: Int,
|
|
||||||
): Int? {
|
|
||||||
val reference = instruction.getReference<MethodReference>() ?: return null
|
|
||||||
|
|
||||||
if (!MethodUtil.methodSignaturesMatch(reference, MethodCall.GetDir.reference)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return instructionIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transform(
|
|
||||||
mutableMethod: MutableMethod,
|
|
||||||
entry: Int,
|
|
||||||
) = transformMethodCall(entry, mutableMethod)
|
|
||||||
|
|
||||||
private fun transformMethodCall(
|
|
||||||
instructionIndex: Int,
|
|
||||||
mutableMethod: MutableMethod,
|
|
||||||
) {
|
|
||||||
val getDirInstruction = mutableMethod.getInstruction<Instruction35c>(instructionIndex)
|
|
||||||
val contextRegister = getDirInstruction.registerC
|
|
||||||
val dataRegister = getDirInstruction.registerD
|
|
||||||
|
|
||||||
mutableMethod.replaceInstruction(
|
|
||||||
instructionIndex,
|
|
||||||
"invoke-virtual { v$contextRegister, v$dataRegister }, " +
|
|
||||||
"Landroid/content/Context;->getExternalFilesDir(Ljava/lang/String;)Ljava/io/File;",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum class MethodCall(
|
|
||||||
val reference: MethodReference,
|
|
||||||
) {
|
|
||||||
GetDir(
|
|
||||||
ImmutableMethodReference(
|
|
||||||
"Landroid/content/Context;",
|
|
||||||
"getDir",
|
|
||||||
listOf("Ljava/lang/String;", "I"),
|
|
||||||
"Ljava/io/File;",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
|||||||
@Patch(
|
@Patch(
|
||||||
name = "Predictive back gesture",
|
name = "Predictive back gesture",
|
||||||
description = "Enables the predictive back gesture introduced on Android 13.",
|
description = "Enables the predictive back gesture introduced on Android 13.",
|
||||||
use = false,
|
use = false
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object PredictiveBackGesturePatch : ResourcePatch() {
|
object PredictiveBackGesturePatch : ResourcePatch() {
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
@file:Suppress("unused")
|
|
||||||
|
|
||||||
package app.revanced.patches.all.location.hide
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
|
||||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
|
||||||
import app.revanced.patches.all.misc.transformation.fromMethodReference
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Hide mock location",
|
|
||||||
description = "Prevents the app from knowing the device location is being mocked by a third party app.",
|
|
||||||
use = false
|
|
||||||
)
|
|
||||||
object HideMockLocationPatch : BaseTransformInstructionsPatch<Pair<Instruction, Int>>() {
|
|
||||||
override fun filterMap(
|
|
||||||
classDef: ClassDef,
|
|
||||||
method: Method,
|
|
||||||
instruction: Instruction,
|
|
||||||
instructionIndex: Int
|
|
||||||
): Pair<Instruction, Int>? {
|
|
||||||
val reference = instruction.getReference<MethodReference>() ?: return null
|
|
||||||
if (fromMethodReference<MethodCall>(reference) == null) return null
|
|
||||||
|
|
||||||
return instruction to instructionIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transform(mutableMethod: MutableMethod, entry: Pair<Instruction, Int>) {
|
|
||||||
val (instruction, index) = entry
|
|
||||||
instruction as FiveRegisterInstruction
|
|
||||||
|
|
||||||
// Replace return value with a constant `false` boolean.
|
|
||||||
mutableMethod.replaceInstruction(
|
|
||||||
index + 1,
|
|
||||||
"const/4 v${instruction.registerC}, 0x0"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum class MethodCall(
|
|
||||||
override val definedClassName: String,
|
|
||||||
override val methodName: String,
|
|
||||||
override val methodParams: Array<String>,
|
|
||||||
override val returnType: String
|
|
||||||
) : IMethodCall {
|
|
||||||
IsMock("Landroid/location/Location;", "isMock", emptyArray(), "Z"),
|
|
||||||
IsFromMockProvider("Landroid/location/Location;", "isFromMockProvider", emptyArray(), "Z")
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
package app.revanced.patches.all.misc.build
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|
||||||
|
|
||||||
abstract class BaseSpoofBuildInfoPatch : BaseTransformInstructionsPatch<Pair<Int, Pair<String, String>>>() {
|
|
||||||
// The build information supported32BitAbis, supported64BitAbis, and supportedAbis are not supported for now,
|
|
||||||
// because initializing an array in transform is a bit more complex.
|
|
||||||
|
|
||||||
protected open val board: String? = null
|
|
||||||
|
|
||||||
protected open val bootloader: String? = null
|
|
||||||
|
|
||||||
protected open val brand: String? = null
|
|
||||||
|
|
||||||
protected open val cpuAbi: String? = null
|
|
||||||
|
|
||||||
protected open val cpuAbi2: String? = null
|
|
||||||
|
|
||||||
protected open val device: String? = null
|
|
||||||
|
|
||||||
protected open val display: String? = null
|
|
||||||
|
|
||||||
protected open val fingerprint: String? = null
|
|
||||||
|
|
||||||
protected open val hardware: String? = null
|
|
||||||
|
|
||||||
protected open val host: String? = null
|
|
||||||
|
|
||||||
protected open val id: String? = null
|
|
||||||
|
|
||||||
protected open val manufacturer: String? = null
|
|
||||||
|
|
||||||
protected open val model: String? = null
|
|
||||||
|
|
||||||
protected open val odmSku: String? = null
|
|
||||||
|
|
||||||
protected open val product: String? = null
|
|
||||||
|
|
||||||
protected open val radio: String? = null
|
|
||||||
|
|
||||||
protected open val serial: String? = null
|
|
||||||
|
|
||||||
protected open val sku: String? = null
|
|
||||||
|
|
||||||
protected open val socManufacturer: String? = null
|
|
||||||
|
|
||||||
protected open val socModel: String? = null
|
|
||||||
|
|
||||||
protected open val tags: String? = null
|
|
||||||
|
|
||||||
protected open val time: Long? = null
|
|
||||||
|
|
||||||
protected open val type: String? = null
|
|
||||||
|
|
||||||
protected open val user: String? = null
|
|
||||||
|
|
||||||
|
|
||||||
// Lazy, so that patch options above are initialized before they are accessed.
|
|
||||||
private val replacements: Map<String, Pair<String, String>> by lazy {
|
|
||||||
buildMap {
|
|
||||||
if (board != null) put("BOARD", "const-string" to "\"$board\"")
|
|
||||||
if (bootloader != null) put("BOOTLOADER", "const-string" to "\"$bootloader\"")
|
|
||||||
if (brand != null) put("BRAND", "const-string" to "\"$brand\"")
|
|
||||||
if (cpuAbi != null) put("CPU_ABI", "const-string" to "\"$cpuAbi\"")
|
|
||||||
if (cpuAbi2 != null) put("CPU_ABI2", "const-string" to "\"$cpuAbi2\"")
|
|
||||||
if (device != null) put("DEVICE", "const-string" to "\"$device\"")
|
|
||||||
if (display != null) put("DISPLAY", "const-string" to "\"$display\"")
|
|
||||||
if (fingerprint != null) put("FINGERPRINT", "const-string" to "\"$fingerprint\"")
|
|
||||||
if (hardware != null) put("HARDWARE", "const-string" to "\"$hardware\"")
|
|
||||||
if (host != null) put("HOST", "const-string" to "\"$host\"")
|
|
||||||
if (id != null) put("ID", "const-string" to "\"$id\"")
|
|
||||||
if (manufacturer != null) put("MANUFACTURER", "const-string" to "\"$manufacturer\"")
|
|
||||||
if (model != null) put("MODEL", "const-string" to "\"$model\"")
|
|
||||||
if (odmSku != null) put("ODM_SKU", "const-string" to "\"$odmSku\"")
|
|
||||||
if (product != null) put("PRODUCT", "const-string" to "\"$product\"")
|
|
||||||
if (radio != null) put("RADIO", "const-string" to "\"$radio\"")
|
|
||||||
if (serial != null) put("SERIAL", "const-string" to "\"$serial\"")
|
|
||||||
if (sku != null) put("SKU", "const-string" to "\"$sku\"")
|
|
||||||
if (socManufacturer != null) put("SOC_MANUFACTURER", "const-string" to "\"$socManufacturer\"")
|
|
||||||
if (socModel != null) put("SOC_MODEL", "const-string" to "\"$socModel\"")
|
|
||||||
if (tags != null) put("TAGS", "const-string" to "\"$tags\"")
|
|
||||||
if (time != null) put("TIME", "const-wide" to "$time")
|
|
||||||
if (type != null) put("TYPE", "const-string" to "\"$type\"")
|
|
||||||
if (user != null) put("USER", "const-string" to "\"$user\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun filterMap(
|
|
||||||
classDef: ClassDef,
|
|
||||||
method: Method,
|
|
||||||
instruction: Instruction,
|
|
||||||
instructionIndex: Int
|
|
||||||
): Pair<Int, Pair<String, String>>? {
|
|
||||||
val reference = instruction.getReference<FieldReference>() ?: return null
|
|
||||||
if (reference.definingClass != BUILD_CLASS_DESCRIPTOR) return null
|
|
||||||
|
|
||||||
return replacements[reference.name]?.let { instructionIndex to it }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transform(mutableMethod: MutableMethod, entry: Pair<Int, Pair<String, String>>) {
|
|
||||||
val (index, replacement) = entry
|
|
||||||
val (opcode, operand) = replacement
|
|
||||||
val register = mutableMethod.getInstruction<OneRegisterInstruction>(index).registerA
|
|
||||||
|
|
||||||
mutableMethod.replaceInstruction(index, "$opcode v$register, $operand")
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private const val BUILD_CLASS_DESCRIPTOR = "Landroid/os/Build;"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
package app.revanced.patches.all.misc.build
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.longPatchOption
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Spoof build info",
|
|
||||||
description = "Spoof the information about the current build.",
|
|
||||||
use = false
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
class SpoofBuildInfoPatch : BaseSpoofBuildInfoPatch() {
|
|
||||||
override val board by stringPatchOption(
|
|
||||||
key = "board",
|
|
||||||
default = null,
|
|
||||||
title = "Board",
|
|
||||||
description = "The name of the underlying board, like \"goldfish\"."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val bootloader by stringPatchOption(
|
|
||||||
key = "bootloader",
|
|
||||||
default = null,
|
|
||||||
title = "Bootloader",
|
|
||||||
description = "The system bootloader version number."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val brand by stringPatchOption(
|
|
||||||
key = "brand",
|
|
||||||
default = null,
|
|
||||||
title = "Brand",
|
|
||||||
description = "The consumer-visible brand with which the product/hardware will be associated, if any."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val cpuAbi by stringPatchOption(
|
|
||||||
key = "cpu-abi",
|
|
||||||
default = null,
|
|
||||||
title = "CPU ABI",
|
|
||||||
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val cpuAbi2 by stringPatchOption(
|
|
||||||
key = "cpu-abi-2",
|
|
||||||
default = null,
|
|
||||||
title = "CPU ABI 2",
|
|
||||||
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val device by stringPatchOption(
|
|
||||||
key = "device",
|
|
||||||
default = null,
|
|
||||||
title = "Device",
|
|
||||||
description = "The name of the industrial design."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val display by stringPatchOption(
|
|
||||||
key = "display",
|
|
||||||
default = null,
|
|
||||||
title = "Display",
|
|
||||||
description = "A build ID string meant for displaying to the user."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val fingerprint by stringPatchOption(
|
|
||||||
key = "fingerprint",
|
|
||||||
default = null,
|
|
||||||
title = "Fingerprint",
|
|
||||||
description = "A string that uniquely identifies this build."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val hardware by stringPatchOption(
|
|
||||||
key = "hardware",
|
|
||||||
default = null,
|
|
||||||
title = "Hardware",
|
|
||||||
description = "The name of the hardware (from the kernel command line or /proc)."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val host by stringPatchOption(
|
|
||||||
key = "host",
|
|
||||||
default = null,
|
|
||||||
title = "Host",
|
|
||||||
description = "The host."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val id by stringPatchOption(
|
|
||||||
key = "id",
|
|
||||||
default = null,
|
|
||||||
title = "ID",
|
|
||||||
description = "Either a changelist number, or a label like \"M4-rc20\"."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val manufacturer by stringPatchOption(
|
|
||||||
key = "manufacturer",
|
|
||||||
default = null,
|
|
||||||
title = "Manufacturer",
|
|
||||||
description = "The manufacturer of the product/hardware."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val model by stringPatchOption(
|
|
||||||
key = "model",
|
|
||||||
default = null,
|
|
||||||
title = "Model",
|
|
||||||
description = "The end-user-visible name for the end product."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val odmSku by stringPatchOption(
|
|
||||||
key = "odm-sku",
|
|
||||||
default = null,
|
|
||||||
title = "ODM SKU",
|
|
||||||
description = "The SKU of the device as set by the original design manufacturer (ODM)."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val product by stringPatchOption(
|
|
||||||
key = "product",
|
|
||||||
default = null,
|
|
||||||
title = "Product",
|
|
||||||
description = "The name of the overall product."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val radio by stringPatchOption(
|
|
||||||
key = "radio",
|
|
||||||
default = null,
|
|
||||||
title = "Radio",
|
|
||||||
description = "This field was deprecated in API level 15. " +
|
|
||||||
"The radio firmware version is frequently not available when this class is initialized, " +
|
|
||||||
"leading to a blank or \"unknown\" value for this string. Use getRadioVersion() instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val serial by stringPatchOption(
|
|
||||||
key = "serial",
|
|
||||||
default = null,
|
|
||||||
title = "Serial",
|
|
||||||
description = "This field was deprecated in API level 26. Use getSerial() instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val sku by stringPatchOption(
|
|
||||||
key = "sku",
|
|
||||||
default = null,
|
|
||||||
title = "SKU",
|
|
||||||
description = "The SKU of the hardware (from the kernel command line)."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val socManufacturer by stringPatchOption(
|
|
||||||
key = "soc-manufacturer",
|
|
||||||
default = null,
|
|
||||||
title = "SOC Manufacturer",
|
|
||||||
description = "The manufacturer of the device's primary system-on-chip."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val socModel by stringPatchOption(
|
|
||||||
key = "soc-model",
|
|
||||||
default = null,
|
|
||||||
title = "SOC Model",
|
|
||||||
description = "The model name of the device's primary system-on-chip."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val tags by stringPatchOption(
|
|
||||||
key = "tags",
|
|
||||||
default = null,
|
|
||||||
title = "Tags",
|
|
||||||
description = "Comma-separated tags describing the build, like \"unsigned,debug\"."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val time by longPatchOption(
|
|
||||||
key = "time",
|
|
||||||
default = null,
|
|
||||||
title = "Time",
|
|
||||||
description = "The time at which the build was produced, given in milliseconds since the UNIX epoch."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val type by stringPatchOption(
|
|
||||||
key = "type",
|
|
||||||
default = null,
|
|
||||||
title = "Type",
|
|
||||||
description = "The type of build, like \"user\" or \"eng\"."
|
|
||||||
)
|
|
||||||
|
|
||||||
override val user by stringPatchOption(
|
|
||||||
key = "user",
|
|
||||||
default = null,
|
|
||||||
title = "User",
|
|
||||||
description = "The user."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -8,16 +8,14 @@ import org.w3c.dom.Element
|
|||||||
@Patch(
|
@Patch(
|
||||||
name = "Enable Android debugging",
|
name = "Enable Android debugging",
|
||||||
description = "Enables Android debugging capabilities. This can slow down the app.",
|
description = "Enables Android debugging capabilities. This can slow down the app.",
|
||||||
use = false,
|
use = false
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object EnableAndroidDebuggingPatch : ResourcePatch() {
|
object EnableAndroidDebuggingPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
context.xmlEditor["AndroidManifest.xml"].use { dom ->
|
||||||
val document = editor.file
|
val applicationNode = dom
|
||||||
|
.file
|
||||||
val applicationNode =
|
|
||||||
document
|
|
||||||
.getElementsByTagName("application")
|
.getElementsByTagName("application")
|
||||||
.item(0) as Element
|
.item(0) as Element
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package app.revanced.patches.all.misc.hex
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.PatchException
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.registerNewPatchOption
|
|
||||||
import app.revanced.patches.shared.misc.hex.BaseHexPatch
|
|
||||||
import app.revanced.util.Utils.trimIndentMultiline
|
|
||||||
import app.revanced.patcher.patch.Patch as PatchClass
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Hex",
|
|
||||||
description = "Replaces a hexadecimal patterns of bytes of files in an APK.",
|
|
||||||
use = false,
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
class HexPatch : BaseHexPatch() {
|
|
||||||
// TODO: Instead of stringArrayOption, use a custom option type to work around
|
|
||||||
// https://github.com/ReVanced/revanced-library/issues/48.
|
|
||||||
// Replace the custom option type with a stringArrayOption once the issue is resolved.
|
|
||||||
private val replacementsOption by registerNewPatchOption<PatchClass<*>, List<String>>(
|
|
||||||
key = "replacements",
|
|
||||||
title = "Replacements",
|
|
||||||
description = """
|
|
||||||
Hexadecimal patterns to search for and replace with another in a target file.
|
|
||||||
|
|
||||||
A pattern is a sequence of case insensitive strings, each representing hexadecimal bytes, separated by spaces.
|
|
||||||
An example pattern is 'aa 01 02 FF'.
|
|
||||||
|
|
||||||
Every pattern must be followed by a pipe ('|'), the replacement pattern,
|
|
||||||
another pipe ('|'), and the path to the file to make the changes in relative to the APK root.
|
|
||||||
The replacement pattern must have the same length as the original pattern.
|
|
||||||
|
|
||||||
Full example of a valid input:
|
|
||||||
'aa 01 02 FF|00 00 00 00|path/to/file'
|
|
||||||
""".trimIndentMultiline(),
|
|
||||||
required = true,
|
|
||||||
valueType = "StringArray",
|
|
||||||
)
|
|
||||||
|
|
||||||
override val replacements
|
|
||||||
get() = replacementsOption!!.map { from ->
|
|
||||||
val (pattern, replacementPattern, targetFilePath) = try {
|
|
||||||
from.split("|", limit = 3)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw PatchException(
|
|
||||||
"Invalid input: $from.\n" +
|
|
||||||
"Every pattern must be followed by a pipe ('|'), " +
|
|
||||||
"the replacement pattern, another pipe ('|'), " +
|
|
||||||
"and the path to the file to make the changes in relative to the APK root. ",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Replacement(pattern, replacementPattern, targetFilePath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import app.revanced.patcher.data.ResourceContext
|
|||||||
import app.revanced.patcher.patch.ResourcePatch
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.debugging.EnableAndroidDebuggingPatch
|
import app.revanced.patches.all.misc.debugging.EnableAndroidDebuggingPatch
|
||||||
import app.revanced.util.Utils.trimIndentMultiline
|
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -12,17 +11,16 @@ import java.io.File
|
|||||||
name = "Override certificate pinning",
|
name = "Override certificate pinning",
|
||||||
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
|
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
|
||||||
dependencies = [EnableAndroidDebuggingPatch::class],
|
dependencies = [EnableAndroidDebuggingPatch::class],
|
||||||
use = false,
|
use = false
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object OverrideCertificatePinningPatch : ResourcePatch() {
|
object OverrideCertificatePinningPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
val resXmlDirectory = context.get("res/xml")
|
val resXmlDirectory = context["res/xml"]
|
||||||
|
|
||||||
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
|
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val document = editor.file
|
val document = editor.file
|
||||||
|
|
||||||
val applicationNode = document.getElementsByTagName("application").item(0) as Element
|
val applicationNode = document.getElementsByTagName("application").item(0) as Element
|
||||||
|
|
||||||
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
|
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
|
||||||
@@ -33,6 +31,8 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
|
|||||||
|
|
||||||
// In case the file does not exist create the "network_security_config.xml" file.
|
// In case the file does not exist create the "network_security_config.xml" file.
|
||||||
File(resXmlDirectory, "network_security_config.xml").apply {
|
File(resXmlDirectory, "network_security_config.xml").apply {
|
||||||
|
if (!exists()) {
|
||||||
|
createNewFile()
|
||||||
writeText(
|
writeText(
|
||||||
"""
|
"""
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
@@ -54,8 +54,22 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
|
|||||||
</trust-anchors>
|
</trust-anchors>
|
||||||
</debug-overrides>
|
</debug-overrides>
|
||||||
</network-security-config>
|
</network-security-config>
|
||||||
""".trimIndentMultiline(),
|
"""
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// If the file already exists.
|
||||||
|
readText().let { text ->
|
||||||
|
if (!text.contains("<certificates src=\"user\" />")) {
|
||||||
|
writeText(
|
||||||
|
text.replace(
|
||||||
|
"<trust-anchors>",
|
||||||
|
"<trust-anchors>\n<certificates src=\"user\" overridePins=\"true\" />\n<certificates src=\"system\" />"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,18 @@ import java.io.Closeable
|
|||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Change package name",
|
name = "Change package name",
|
||||||
description = "Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.",
|
description = "Appends \".revanced\" to the package name by default.",
|
||||||
use = false,
|
use = false
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
||||||
private val packageNameOption =
|
private val packageNameOption = stringPatchOption(
|
||||||
stringPatchOption(
|
|
||||||
key = "packageName",
|
key = "packageName",
|
||||||
default = "Default",
|
default = "Default",
|
||||||
values = mapOf("Default" to "Default"),
|
values = mapOf("Default" to "Default"),
|
||||||
title = "Package name",
|
title = "Package name",
|
||||||
description = "The name of the package to rename the app to.",
|
description = "The name of the package to rename the app to.",
|
||||||
required = true,
|
required = true
|
||||||
) {
|
) {
|
||||||
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
|
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
|
||||||
}
|
}
|
||||||
@@ -42,29 +41,22 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
|||||||
* @throws PatchOptionException.ValueValidationException If the package name is invalid.
|
* @throws PatchOptionException.ValueValidationException If the package name is invalid.
|
||||||
*/
|
*/
|
||||||
fun setOrGetFallbackPackageName(fallbackPackageName: String): String {
|
fun setOrGetFallbackPackageName(fallbackPackageName: String): String {
|
||||||
val packageName = packageNameOption.value!!
|
val packageName = this.packageNameOption.value!!
|
||||||
|
|
||||||
return if (packageName == packageNameOption.default) {
|
return if (packageName == this.packageNameOption.default)
|
||||||
fallbackPackageName.also { packageNameOption.value = it }
|
fallbackPackageName.also { this.packageNameOption.value = it }
|
||||||
} else {
|
else
|
||||||
packageName
|
packageName
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() =
|
override fun close() = context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
|
||||||
val document = editor.file
|
val originalPackageName = manifest.getAttribute("package")
|
||||||
|
|
||||||
val replacementPackageName = packageNameOption.value
|
var replacementPackageName = this.packageNameOption.value
|
||||||
|
if (replacementPackageName == this.packageNameOption.default)
|
||||||
|
replacementPackageName = "$originalPackageName.revanced"
|
||||||
|
|
||||||
val manifest = document.getElementsByTagName("manifest").item(0) as Element
|
manifest.setAttribute("package", replacementPackageName)
|
||||||
manifest.setAttribute(
|
|
||||||
"package",
|
|
||||||
if (replacementPackageName != packageNameOption.default) {
|
|
||||||
replacementPackageName
|
|
||||||
} else {
|
|
||||||
"${manifest.getAttribute("package")}.revanced"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
package app.revanced.patches.all.misc.resources
|
|
||||||
|
|
||||||
import app.revanced.patcher.PatchClass
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.PatchException
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.util.DomFileEditor
|
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch.resources
|
|
||||||
import app.revanced.util.*
|
|
||||||
import app.revanced.util.resource.ArrayResource
|
|
||||||
import app.revanced.util.resource.BaseResource
|
|
||||||
import app.revanced.util.resource.StringResource
|
|
||||||
import org.w3c.dom.Node
|
|
||||||
import java.io.Closeable
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An identifier of an app. For example, `youtube`.
|
|
||||||
*/
|
|
||||||
private typealias AppId = String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An identifier of a patch. For example, `ad.general.HideAdsPatch`.
|
|
||||||
*/
|
|
||||||
private typealias PatchId = String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of resources of a patch.
|
|
||||||
*/
|
|
||||||
private typealias PatchResources = MutableSet<BaseResource>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of resources belonging to a patch.
|
|
||||||
*/
|
|
||||||
private typealias AppResources = MutableMap<PatchId, PatchResources>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of resources belonging to an app.
|
|
||||||
*/
|
|
||||||
private typealias Resources = MutableMap<AppId, AppResources>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The value of a resource.
|
|
||||||
* For example, `values` or `values-de`.
|
|
||||||
*/
|
|
||||||
private typealias Value = String
|
|
||||||
|
|
||||||
@Patch(description = "Add resources such as strings or arrays to the app.")
|
|
||||||
object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseResource>> by mutableMapOf(), Closeable {
|
|
||||||
private lateinit var context: ResourceContext
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of all resources associated by their value staged by [execute].
|
|
||||||
*/
|
|
||||||
private lateinit var resources: Map<Value, Resources>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of Crowdin locales to Android resource locale names.
|
|
||||||
*
|
|
||||||
* Fixme: Instead this patch should detect what locale regions are present in both patches and the target app,
|
|
||||||
* and automatically merge into the appropriate existing target file.
|
|
||||||
* So if a target app has only 'es', then the Crowdin file of 'es-rES' should merge into that.
|
|
||||||
* But if a target app has specific regions (such as 'pt-rBR'),
|
|
||||||
* then the Crowdin region specific file should merged into that.
|
|
||||||
*/
|
|
||||||
private val locales = mapOf(
|
|
||||||
"af-rZA" to "af",
|
|
||||||
"am-rET" to "am",
|
|
||||||
"ar-rSA" to "ar",
|
|
||||||
"as-rIN" to "as",
|
|
||||||
"az-rAZ" to "az",
|
|
||||||
"be-rBY" to "be",
|
|
||||||
"bg-rBG" to "bg",
|
|
||||||
"bn-rBD" to "bn",
|
|
||||||
"bs-rBA" to "bs",
|
|
||||||
"ca-rES" to "ca",
|
|
||||||
"cs-rCZ" to "cs",
|
|
||||||
"da-rDK" to "da",
|
|
||||||
"de-rDE" to "de",
|
|
||||||
"el-rGR" to "el",
|
|
||||||
"es-rES" to "es",
|
|
||||||
"et-rEE" to "et",
|
|
||||||
"eu-rES" to "eu",
|
|
||||||
"fa-rIR" to "fa",
|
|
||||||
"fi-rFI" to "fi",
|
|
||||||
"fil-rPH" to "tl",
|
|
||||||
"fr-rFR" to "fr",
|
|
||||||
"ga-rIE" to "ga",
|
|
||||||
"gl-rES" to "gl",
|
|
||||||
"gu-rIN" to "gu",
|
|
||||||
"hi-rIN" to "hi",
|
|
||||||
"hr-rHR" to "hr",
|
|
||||||
"hu-rHU" to "hu",
|
|
||||||
"hy-rAM" to "hy",
|
|
||||||
"in-rID" to "in",
|
|
||||||
"is-rIS" to "is",
|
|
||||||
"it-rIT" to "it",
|
|
||||||
"iw-rIL" to "iw",
|
|
||||||
"ja-rJP" to "ja",
|
|
||||||
"ka-rGE" to "ka",
|
|
||||||
"kk-rKZ" to "kk",
|
|
||||||
"km-rKH" to "km",
|
|
||||||
"kn-rIN" to "kn",
|
|
||||||
"ko-rKR" to "ko",
|
|
||||||
"ky-rKG" to "ky",
|
|
||||||
"lo-rLA" to "lo",
|
|
||||||
"lt-rLT" to "lt",
|
|
||||||
"lv-rLV" to "lv",
|
|
||||||
"mk-rMK" to "mk",
|
|
||||||
"ml-rIN" to "ml",
|
|
||||||
"mn-rMN" to "mn",
|
|
||||||
"mr-rIN" to "mr",
|
|
||||||
"ms-rMY" to "ms",
|
|
||||||
"my-rMM" to "my",
|
|
||||||
"nb-rNO" to "nb",
|
|
||||||
"ne-rIN" to "ne",
|
|
||||||
"nl-rNL" to "nl",
|
|
||||||
"or-rIN" to "or",
|
|
||||||
"pa-rIN" to "pa",
|
|
||||||
"pl-rPL" to "pl",
|
|
||||||
"pt-rBR" to "pt-rBR",
|
|
||||||
"pt-rPT" to "pt-rPT",
|
|
||||||
"ro-rRO" to "ro",
|
|
||||||
"ru-rRU" to "ru",
|
|
||||||
"si-rLK" to "si",
|
|
||||||
"sk-rSK" to "sk",
|
|
||||||
"sl-rSI" to "sl",
|
|
||||||
"sq-rAL" to "sq",
|
|
||||||
"sr-rCS" to "b+sr+Latn",
|
|
||||||
"sr-rSP" to "sr",
|
|
||||||
"sv-rSE" to "sv",
|
|
||||||
"sw-rKE" to "sw",
|
|
||||||
"ta-rIN" to "ta",
|
|
||||||
"te-rIN" to "te",
|
|
||||||
"th-rTH" to "th",
|
|
||||||
"tl-rPH" to "tl",
|
|
||||||
"tr-rTR" to "tr",
|
|
||||||
"uk-rUA" to "uk",
|
|
||||||
"ur-rIN" to "ur",
|
|
||||||
"uz-rUZ" to "uz",
|
|
||||||
"vi-rVN" to "vi",
|
|
||||||
"zh-rCN" to "zh-rCN",
|
|
||||||
"zh-rTW" to "zh-rTW",
|
|
||||||
"zu-rZA" to "zu",
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
The strategy of this patch is to stage resources present in `/resources/addresources`.
|
|
||||||
These resources are organized by their respective value and patch.
|
|
||||||
|
|
||||||
On AddResourcesPatch#execute, all resources are staged in a temporary map.
|
|
||||||
After that, other patches that depend on AddResourcesPatch can call
|
|
||||||
AddResourcesPatch#invoke(PatchClass) to stage resources belonging to that patch
|
|
||||||
from the temporary map to AddResourcesPatch.
|
|
||||||
|
|
||||||
After all patches that depend on AddResourcesPatch have been executed,
|
|
||||||
AddResourcesPatch#close is finally called to add all staged resources to the app.
|
|
||||||
*/
|
|
||||||
override fun execute(context: ResourceContext) {
|
|
||||||
this.context = context
|
|
||||||
|
|
||||||
resources =
|
|
||||||
buildMap {
|
|
||||||
/**
|
|
||||||
* Puts resources under `/resources/addresources/<value>/<resourceKind>.xml` into the map.
|
|
||||||
*
|
|
||||||
* @param sourceValue The source value of the resource. For example, `values` or `values-de-rDE`.
|
|
||||||
* @param destValue The destination value of the resource. For example, 'values' or 'values-de'.
|
|
||||||
* @param resourceKind The kind of the resource. For example, `strings` or `arrays`.
|
|
||||||
* @param transform A function that transforms the [Node]s from the XML files to a [BaseResource].
|
|
||||||
*/
|
|
||||||
fun addResources(
|
|
||||||
sourceValue: Value,
|
|
||||||
destValue: Value = sourceValue,
|
|
||||||
resourceKind: String,
|
|
||||||
transform: (Node) -> BaseResource,
|
|
||||||
) {
|
|
||||||
inputStreamFromBundledResource(
|
|
||||||
"addresources",
|
|
||||||
"$sourceValue/$resourceKind.xml",
|
|
||||||
)?.let { stream ->
|
|
||||||
// Add the resources associated with the given value to the map,
|
|
||||||
// instead of overwriting it.
|
|
||||||
// This covers the example case such as adding strings and arrays of the same value.
|
|
||||||
getOrPut(destValue, ::mutableMapOf).apply {
|
|
||||||
context.xmlEditor[stream].use { editor ->
|
|
||||||
val document = editor.file
|
|
||||||
|
|
||||||
document.getElementsByTagName("app").asSequence().forEach { app ->
|
|
||||||
val appId = app.attributes.getNamedItem("id").textContent
|
|
||||||
|
|
||||||
getOrPut(appId, ::mutableMapOf).apply {
|
|
||||||
app.forEachChildElement { patch ->
|
|
||||||
val patchId = patch.attributes.getNamedItem("id").textContent
|
|
||||||
|
|
||||||
getOrPut(patchId, ::mutableSetOf).apply {
|
|
||||||
patch.forEachChildElement { resourceNode ->
|
|
||||||
val resource = transform(resourceNode)
|
|
||||||
|
|
||||||
add(resource)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage all resources to a temporary map.
|
|
||||||
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
|
|
||||||
// are later used in AddResourcesPatch#close.
|
|
||||||
try {
|
|
||||||
val addStringResources = { source: Value, dest: Value ->
|
|
||||||
addResources(source, dest, "strings", StringResource::fromNode)
|
|
||||||
}
|
|
||||||
locales.forEach { (source, dest) -> addStringResources("values-$source", "values-$dest") }
|
|
||||||
addStringResources("values", "values")
|
|
||||||
|
|
||||||
addResources("values", "values", "arrays", ArrayResource::fromNode)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw PatchException("Failed to read resources", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a [BaseResource] to the map using [MutableMap.getOrPut].
|
|
||||||
*
|
|
||||||
* @param value The value of the resource. For example, `values` or `values-de`.
|
|
||||||
* @param resource The resource to add.
|
|
||||||
*
|
|
||||||
* @return True if the resource was added, false if it already existed.
|
|
||||||
*/
|
|
||||||
operator fun invoke(
|
|
||||||
value: Value,
|
|
||||||
resource: BaseResource,
|
|
||||||
) = getOrPut(value, ::mutableSetOf).add(resource)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of [BaseResource]s to the map using [MutableMap.getOrPut].
|
|
||||||
*
|
|
||||||
* @param value The value of the resource. For example, `values` or `values-de`.
|
|
||||||
* @param resources The resources to add.
|
|
||||||
*
|
|
||||||
* @return True if the resources were added, false if they already existed.
|
|
||||||
*/
|
|
||||||
operator fun invoke(
|
|
||||||
value: Value,
|
|
||||||
resources: Iterable<BaseResource>,
|
|
||||||
) = getOrPut(value, ::mutableSetOf).addAll(resources)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a [StringResource].
|
|
||||||
*
|
|
||||||
* @param name The name of the string resource.
|
|
||||||
* @param value The value of the string resource.
|
|
||||||
* @param formatted Whether the string resource is formatted. Defaults to `true`.
|
|
||||||
* @param resourceValue The value of the resource. For example, `values` or `values-de`.
|
|
||||||
*
|
|
||||||
* @return True if the resource was added, false if it already existed.
|
|
||||||
*/
|
|
||||||
operator fun invoke(
|
|
||||||
name: String,
|
|
||||||
value: String,
|
|
||||||
formatted: Boolean = true,
|
|
||||||
resourceValue: Value = "values",
|
|
||||||
) = invoke(resourceValue, StringResource(name, value, formatted))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an [ArrayResource].
|
|
||||||
*
|
|
||||||
* @param name The name of the array resource.
|
|
||||||
* @param items The items of the array resource.
|
|
||||||
*
|
|
||||||
* @return True if the resource was added, false if it already existed.
|
|
||||||
*/
|
|
||||||
operator fun invoke(
|
|
||||||
name: String,
|
|
||||||
items: List<String>,
|
|
||||||
) = invoke("values", ArrayResource(name, items))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts all resources of any [Value] staged in [resources] for the given [PatchClass] to [AddResourcesPatch].
|
|
||||||
*
|
|
||||||
* @param patch The class of the patch to add resources for.
|
|
||||||
* @param parseIds A function that parses the [AppId] and [PatchId] from the given [PatchClass].
|
|
||||||
* This is used to access the resources in [resources] to stage them in [AddResourcesPatch].
|
|
||||||
* The default implementation assumes that the [PatchClass] qualified name has the following format:
|
|
||||||
* `<any>.<any>.<any>.<app id>.<patch id>`.
|
|
||||||
*
|
|
||||||
* @return True if any resources were added, false if none were added.
|
|
||||||
*
|
|
||||||
* @see AddResourcesPatch.close
|
|
||||||
*/
|
|
||||||
operator fun invoke(
|
|
||||||
patch: PatchClass,
|
|
||||||
parseIds: PatchClass.() -> Pair<AppId, PatchId> = {
|
|
||||||
val qualifiedName = qualifiedName ?: throw PatchException("Patch qualified name is null")
|
|
||||||
|
|
||||||
// This requires qualifiedName to have the following format:
|
|
||||||
// `<any>.<any>.<any>.<app id>.<patch id>`
|
|
||||||
with(qualifiedName.split(".")) {
|
|
||||||
if (size < 5) throw PatchException("Patch qualified name has invalid format")
|
|
||||||
|
|
||||||
val appId = this[3]
|
|
||||||
val patchId = subList(4, size).joinToString(".")
|
|
||||||
|
|
||||||
appId to patchId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
): Boolean {
|
|
||||||
val (appId, patchId) = patch.parseIds()
|
|
||||||
|
|
||||||
var result = false
|
|
||||||
|
|
||||||
// Stage resources for the given patch to AddResourcesPatch associated with their value.
|
|
||||||
resources.forEach { (value, resources) ->
|
|
||||||
resources[appId]?.get(patchId)?.let { patchResources ->
|
|
||||||
if (invoke(value, patchResources)) result = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds all resources staged in [AddResourcesPatch] to the app.
|
|
||||||
* This is called after all patches that depend on [AddResourcesPatch] have been executed.
|
|
||||||
*/
|
|
||||||
override fun close() {
|
|
||||||
operator fun MutableMap<String, Pair<DomFileEditor, Node>>.invoke(
|
|
||||||
value: Value,
|
|
||||||
resource: BaseResource,
|
|
||||||
) {
|
|
||||||
// TODO: Fix open-closed principle violation by modifying BaseResource#serialize so that it accepts
|
|
||||||
// a Value and the map of documents. It will then get or put the document suitable for its resource type
|
|
||||||
// to serialize itself to it.
|
|
||||||
val resourceFileName =
|
|
||||||
when (resource) {
|
|
||||||
is StringResource -> "strings"
|
|
||||||
is ArrayResource -> "arrays"
|
|
||||||
else -> throw NotImplementedError("Unsupported resource type")
|
|
||||||
}
|
|
||||||
|
|
||||||
getOrPut(resourceFileName) {
|
|
||||||
val targetFile =
|
|
||||||
context.get("res/$value/$resourceFileName.xml").also {
|
|
||||||
it.parentFile?.mkdirs()
|
|
||||||
|
|
||||||
if(it.createNewFile()) {
|
|
||||||
it.writeText("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.xmlEditor[targetFile.path].let { editor ->
|
|
||||||
val document = editor.file
|
|
||||||
|
|
||||||
// Save the target node here as well
|
|
||||||
// in order to avoid having to call document.getNode("resources")
|
|
||||||
// but also save the document so that it can be closed later.
|
|
||||||
editor to document.getNode("resources")
|
|
||||||
}
|
|
||||||
}.let { (_, targetNode) ->
|
|
||||||
targetNode.addResource(resource) { invoke(value, it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
forEach { (value, resources) ->
|
|
||||||
// A map of document associated by their kind (e.g. strings, arrays).
|
|
||||||
// Each document is accompanied by the target node to which resources are added.
|
|
||||||
// A map is used because Map#getOrPut allows opening a new document for the duration of a resource value.
|
|
||||||
// This is done to prevent having to open the files for every resource that is added.
|
|
||||||
// Instead, it is cached once and reused for resources of the same value.
|
|
||||||
// This map is later accessed to close all documents for the current resource value.
|
|
||||||
val documents = mutableMapOf<String, Pair<DomFileEditor, Node>>()
|
|
||||||
|
|
||||||
resources.forEach { resource -> documents(value, resource) }
|
|
||||||
|
|
||||||
documents.values.forEach { (document, _) -> document.close() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package app.revanced.patches.all.misc.versioncode
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intPatchOption
|
|
||||||
import app.revanced.util.getNode
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Change version code",
|
|
||||||
description = "Changes the version code of the app. By default the highest version code is set. " +
|
|
||||||
"This allows older versions of an app to be installed " +
|
|
||||||
"if their version code is set to the same or a higher value and can stop app stores to update the app.",
|
|
||||||
use = false,
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object ChangeVersionCodePatch : ResourcePatch() {
|
|
||||||
private val versionCode by intPatchOption(
|
|
||||||
key = "versionCode",
|
|
||||||
default = Int.MAX_VALUE,
|
|
||||||
values = mapOf(
|
|
||||||
"Lowest" to 1,
|
|
||||||
"Highest" to Int.MAX_VALUE,
|
|
||||||
),
|
|
||||||
title = "Version code",
|
|
||||||
description = "The version code to use",
|
|
||||||
required = true,
|
|
||||||
) {
|
|
||||||
it!! >= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
|
||||||
context.document["AndroidManifest.xml"].use { document ->
|
|
||||||
val manifestElement = document.getNode("manifest") as Element
|
|
||||||
manifestElement.setAttribute("android:versionCode", "$versionCode")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,10 @@ package app.revanced.patches.all.screencapture.removerestriction
|
|||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
import app.revanced.util.patch.IMethodCall
|
||||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
import app.revanced.util.patch.Instruction35cInfo
|
||||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
import app.revanced.util.patch.filterMapInstruction35c
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
@@ -18,9 +18,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
|||||||
requiresIntegrations = true
|
requiresIntegrations = true
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object RemoveCaptureRestrictionPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
object RemoveCaptureRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
||||||
"Lapp/revanced/integrations/all/screencapture/removerestriction/RemoveScreencaptureRestrictionPatch"
|
"Lapp/revanced/all/screencapture/removerestriction/RemoveScreencaptureRestrictionPatch"
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
||||||
// Information about method calls we want to replace
|
// Information about method calls we want to replace
|
||||||
enum class MethodCall(
|
enum class MethodCall(
|
||||||
|
|||||||
@@ -8,12 +8,11 @@ import org.w3c.dom.Element
|
|||||||
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
|
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
|
||||||
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
|
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
// create an xml editor instance
|
||||||
val document = editor.file
|
context.xmlEditor["AndroidManifest.xml"].use { dom ->
|
||||||
|
|
||||||
// get the application node
|
// get the application node
|
||||||
val applicationNode =
|
val applicationNode = dom
|
||||||
document
|
.file
|
||||||
.getElementsByTagName("application")
|
.getElementsByTagName("application")
|
||||||
.item(0) as Element
|
.item(0) as Element
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import app.revanced.patcher.data.BytecodeContext
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
import app.revanced.util.patch.IMethodCall
|
||||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
import app.revanced.util.patch.Instruction35cInfo
|
||||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
import app.revanced.util.patch.filterMapInstruction35c
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
@@ -22,9 +22,9 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|||||||
requiresIntegrations = true,
|
requiresIntegrations = true,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object RemoveScreenshotRestrictionPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
object RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
||||||
"Lapp/revanced/integrations/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch"
|
"Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch"
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
@@ -71,7 +71,7 @@ object RemoveScreenshotRestrictionPatch : BaseTransformInstructionsPatch<Instruc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ModifyLayoutParamsFlags : BaseTransformInstructionsPatch<Pair<Instruction22c, Int>>() {
|
private class ModifyLayoutParamsFlags : AbstractTransformInstructionsPatch<Pair<Instruction22c, Int>>() {
|
||||||
override fun filterMap(
|
override fun filterMap(
|
||||||
classDef: ClassDef,
|
classDef: ClassDef,
|
||||||
method: Method,
|
method: Method,
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package app.revanced.patches.all.shortcut.sharetargets
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.util.asSequence
|
|
||||||
import app.revanced.util.getNode
|
|
||||||
import org.w3c.dom.Element
|
|
||||||
import java.io.FileNotFoundException
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Remove share targets",
|
|
||||||
description = "Removes share targets like directly sharing to a frequent contact.",
|
|
||||||
use = false,
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object RemoveShareTargetsPatch : ResourcePatch() {
|
|
||||||
override fun execute(context: ResourceContext) {
|
|
||||||
try {
|
|
||||||
context.document["res/xml/shortcuts.xml"]
|
|
||||||
} catch (_: FileNotFoundException) {
|
|
||||||
return Logger.getLogger(this::class.java.name).warning("The app has no shortcuts")
|
|
||||||
}.use { document ->
|
|
||||||
val rootNode = document.getNode("shortcuts") as? Element ?: return@use
|
|
||||||
|
|
||||||
document.getElementsByTagName("share-target").asSequence().forEach {
|
|
||||||
rootNode.removeChild(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,9 +3,10 @@ package app.revanced.patches.all.telephony.sim.spoof
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
@@ -23,30 +24,27 @@ import java.util.*
|
|||||||
use = false,
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object SpoofSimCountryPatch : BaseTransformInstructionsPatch<Pair<Int, String>>() {
|
object SpoofSimCountryPatch : AbstractTransformInstructionsPatch<Pair<Int, String>>() {
|
||||||
private val countries = Locale.getISOCountries().associateBy { Locale("", it).displayCountry }
|
private val isoValidator: PatchOption<String>.(String?) -> Boolean =
|
||||||
|
{ it: String? -> it?.uppercase() in Locale.getISOCountries() || it == null }
|
||||||
|
|
||||||
private val networkCountryIso by isoCountryPatchOption(
|
private val networkCountryIso by stringPatchOption(
|
||||||
"networkCountryIso",
|
"networkCountryIso",
|
||||||
"Network ISO Country Code",
|
|
||||||
)
|
|
||||||
|
|
||||||
private val simCountryIso by isoCountryPatchOption(
|
|
||||||
"simCountryIso",
|
|
||||||
"Sim ISO Country Code",
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun isoCountryPatchOption(
|
|
||||||
key: String,
|
|
||||||
title: String,
|
|
||||||
) = stringPatchOption(
|
|
||||||
key,
|
|
||||||
null,
|
null,
|
||||||
countries,
|
null,
|
||||||
title,
|
"Network ISO Country Code",
|
||||||
|
"ISO-3166-1 alpha-2 country code equivalent of the MCC (Mobile Country Code) " +
|
||||||
|
"of the current registered operator or the cell nearby.",
|
||||||
|
validator = isoValidator
|
||||||
|
)
|
||||||
|
|
||||||
|
private val simCountryIso by stringPatchOption(
|
||||||
|
"simCountryIso",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"Sim ISO Country Code",
|
||||||
"ISO-3166-1 alpha-2 country code equivalent for the SIM provider's country code.",
|
"ISO-3166-1 alpha-2 country code equivalent for the SIM provider's country code.",
|
||||||
false,
|
validator = isoValidator
|
||||||
validator = { it: String? -> it == null || it.uppercase() in countries.values }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun filterMap(
|
override fun filterMap(
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.amazon.deeplinking
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
internal object DeepLinkingFingerprint : MethodFingerprint(
|
|
||||||
"Z",
|
|
||||||
parameters = listOf("L"),
|
|
||||||
accessFlags = AccessFlags.PRIVATE.value,
|
|
||||||
strings = listOf("https://www.", "android.intent.action.VIEW")
|
|
||||||
)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package app.revanced.patches.amazon.deeplinking
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.util.exception
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Always allow deep-linking",
|
|
||||||
description = "Open Amazon links, even if the app is not set to handle Amazon links.",
|
|
||||||
compatiblePackages = [CompatiblePackage("com.amazon.mShop.android.shopping")]
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object DeepLinkingPatch : BytecodePatch(
|
|
||||||
setOf(DeepLinkingFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
DeepLinkingFingerprint.result?.mutableMethod?.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x1
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
) ?: throw DeepLinkingFingerprint.exception
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.backdrops.misc.pro
|
package app.revanced.patches.backdrops.misc.pro
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package app.revanced.patches.backdrops.misc.pro.fingerprints
|
|||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object ProUnlockFingerprint : MethodFingerprint(
|
object ProUnlockFingerprint : MethodFingerprint(
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patches.bandcamp.limitations
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.bandcamp.limitations.fingerprints.HandlePlaybackLimitsPatch
|
|
||||||
import app.revanced.util.exception
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Remove play limits",
|
|
||||||
description = "Disables purchase nagging and playback limits of not purchased tracks.",
|
|
||||||
compatiblePackages = [CompatiblePackage("com.bandcamp.android")],
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object RemovePlayLimitsPatch : BytecodePatch(
|
|
||||||
setOf(HandlePlaybackLimitsPatch),
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext) =
|
|
||||||
HandlePlaybackLimitsPatch.result?.mutableMethod?.addInstructions(0, "return-void")
|
|
||||||
?: throw HandlePlaybackLimitsPatch.exception
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.patches.bandcamp.limitations.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
|
|
||||||
internal object HandlePlaybackLimitsPatch : MethodFingerprint(
|
|
||||||
strings = listOf("play limits processing track", "found play_count"),
|
|
||||||
)
|
|
||||||
@@ -1,23 +1,20 @@
|
|||||||
package app.revanced.patches.candylinkvpn
|
package app.revanced.patches.candylinkvpn
|
||||||
|
|
||||||
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.candylinkvpn.fingerprints.IsPremiumPurchasedFingerprint
|
import app.revanced.patches.candylinkvpn.fingerprints.IsPremiumPurchasedFingerprint
|
||||||
import app.revanced.util.exception
|
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
compatiblePackages = [CompatiblePackage("com.candylink.openvpn")],
|
name = "Unlock pro",
|
||||||
)
|
compatiblePackages = [CompatiblePackage("com.candylink.openvpn")]
|
||||||
@Deprecated(
|
|
||||||
"This patch does not work anymore and will be removed in the future, " +
|
|
||||||
"because the servers now check the purchase status.",
|
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object UnlockProPatch : BytecodePatch(
|
object UnlockProPatch : BytecodePatch(
|
||||||
setOf(IsPremiumPurchasedFingerprint),
|
setOf(IsPremiumPurchasedFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
IsPremiumPurchasedFingerprint.result?.mutableMethod?.addInstructions(
|
IsPremiumPurchasedFingerprint.result?.mutableMethod?.addInstructions(
|
||||||
@@ -25,7 +22,7 @@ object UnlockProPatch : BytecodePatch(
|
|||||||
"""
|
"""
|
||||||
const/4 v0, 0x1
|
const/4 v0, 0x1
|
||||||
return v0
|
return v0
|
||||||
""",
|
"""
|
||||||
) ?: throw IsPremiumPurchasedFingerprint.exception
|
) ?: throw IsPremiumPurchasedFingerprint.exception
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.candylinkvpn.fingerprints
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
internal object IsPremiumPurchasedFingerprint : MethodFingerprint(
|
object IsPremiumPurchasedFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef, _ ->
|
customFingerprint = { methodDef, _ ->
|
||||||
methodDef.definingClass.endsWith("PreferenceProvider;") &&
|
methodDef.definingClass.endsWith("PreferenceProvider;") &&
|
||||||
methodDef.name == "isPremiumPurchased"
|
methodDef.name == "isPremiumPurchased"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.cieid.restrictions.root
|
package app.revanced.patches.cieid.restrictions.root
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.cieid.restrictions.root.fingerprints
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
internal object CheckRootFingerprint : MethodFingerprint(
|
object CheckRootFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef, _ ->
|
customFingerprint = { methodDef, _ ->
|
||||||
methodDef.definingClass == "Lit/ipzs/cieid/BaseActivity;" && methodDef.name == "onResume"
|
methodDef.definingClass == "Lit/ipzs/cieid/BaseActivity;" && methodDef.name == "onResume"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
package app.revanced.patches.duolingo.ad
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.duolingo.ad.fingerprints.InitializeMonetizationDebugSettingsFingerprint
|
|
||||||
import app.revanced.util.resultOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Disable ads",
|
|
||||||
compatiblePackages = [CompatiblePackage("com.duolingo")]
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object DisableAdsPatch : BytecodePatch(
|
|
||||||
setOf(InitializeMonetizationDebugSettingsFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
// Couple approaches to remove ads exist:
|
|
||||||
//
|
|
||||||
// MonetizationDebugSettings has a boolean value for "disableAds".
|
|
||||||
// OnboardingState has a getter to check if the user has any "adFreeSessions".
|
|
||||||
// SharedPreferences has a debug boolean value with key "disable_ads", which maps to "DebugCategory.DISABLE_ADS".
|
|
||||||
//
|
|
||||||
// MonetizationDebugSettings seems to be the most general setting to work fine.
|
|
||||||
InitializeMonetizationDebugSettingsFingerprint.resultOrThrow().let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
|
||||||
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex,
|
|
||||||
"const/4 v$register, 0x1"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.duolingo.ad.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
internal object InitializeMonetizationDebugSettingsFingerprint : MethodFingerprint(
|
|
||||||
returnType = "V",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
|
||||||
parameters = listOf(
|
|
||||||
"Z", // disableAds
|
|
||||||
"Z", // useDebugBilling
|
|
||||||
"Z", // showManageSubscriptions
|
|
||||||
"Z", // alwaysShowSuperAds
|
|
||||||
"Lcom/duolingo/debug/FamilyQuestOverride;",
|
|
||||||
),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.IPUT_BOOLEAN
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package app.revanced.patches.duolingo.debug
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.duolingo.debug.fingerprints.InitializeBuildConfigProviderFingerprint
|
|
||||||
import app.revanced.util.resultOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Enable debug menu",
|
|
||||||
compatiblePackages = [CompatiblePackage("com.duolingo", ["5.158.4"])],
|
|
||||||
use = false
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object EnableDebugMenuPatch : BytecodePatch(
|
|
||||||
setOf(InitializeBuildConfigProviderFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
InitializeBuildConfigProviderFingerprint.resultOrThrow().let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
|
||||||
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
insertIndex,
|
|
||||||
"const/4 v$register, 0x1"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package app.revanced.patches.duolingo.debug.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `BuildConfigProvider` class has two booleans:
|
|
||||||
*
|
|
||||||
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
|
|
||||||
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
|
|
||||||
*/
|
|
||||||
internal object InitializeBuildConfigProviderFingerprint : MethodFingerprint(
|
|
||||||
returnType = "V",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
|
||||||
strings = listOf(
|
|
||||||
"debug",
|
|
||||||
"release",
|
|
||||||
"china",
|
|
||||||
),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.IPUT_BOOLEAN
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.facebook.ads.story
|
package app.revanced.patches.facebook.ads.story
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package app.revanced.patches.facebook.ads.story.fingerprints
|
package app.revanced.patches.facebook.ads.story.fingerprints
|
||||||
|
|
||||||
internal object AdsInsertionFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptAdsInsertion\$1")
|
object AdsInsertionFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptAdsInsertion\$1")
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
package app.revanced.patches.facebook.ads.story.fingerprints
|
package app.revanced.patches.facebook.ads.story.fingerprints
|
||||||
|
|
||||||
internal object FetchMoreAdsFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptFetchMoreAds\$1")
|
object FetchMoreAdsFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptFetchMoreAds\$1")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package app.revanced.patches.facebook.ads.story.fingerprints
|
|||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
|
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
|
||||||
|
|
||||||
internal abstract class FieldMethodFingerprint(fieldValue: String) : MethodFingerprint(
|
abstract class FieldMethodFingerprint(fieldValue: String) : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
parameters = listOf(),
|
parameters = listOf(),
|
||||||
customFingerprint = { methodDef, classDef ->
|
customFingerprint = { methodDef, classDef ->
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.finanzonline.detection.bootloader
|
package app.revanced.patches.finanzonline.detection.bootloader
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#isBootStateOk (3.0.1)
|
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#isBootStateOk (3.0.1)
|
||||||
internal object BootStateFingerprint : MethodFingerprint(
|
object BootStateFingerprint : MethodFingerprint(
|
||||||
"Z",
|
"Z",
|
||||||
accessFlags = AccessFlags.PUBLIC.value,
|
accessFlags = AccessFlags.PUBLIC.value,
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
|||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#createKey (3.0.1)
|
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#createKey (3.0.1)
|
||||||
internal object CreateKeyFingerprint : MethodFingerprint(
|
object CreateKeyFingerprint : MethodFingerprint(
|
||||||
"Z",
|
"Z",
|
||||||
accessFlags = AccessFlags.PUBLIC.value,
|
accessFlags = AccessFlags.PUBLIC.value,
|
||||||
strings = listOf("attestation", "SHA-256", "random", "EC", "AndroidKeyStore")
|
strings = listOf("attestation", "SHA-256", "random", "EC", "AndroidKeyStore")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.finanzonline.detection.root
|
package app.revanced.patches.finanzonline.detection.root
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.RootDetection#isRooted (3.0.1)
|
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.RootDetection#isRooted (3.0.1)
|
||||||
internal object RootDetectionFingerprint : MethodFingerprint(
|
object RootDetectionFingerprint : MethodFingerprint(
|
||||||
"L",
|
"L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
parameters = listOf("L"),
|
parameters = listOf("L"),
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.customtabs
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.googlenews.customtabs.fingerprints.LaunchCustomTabFingerprint
|
|
||||||
import app.revanced.util.resultOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Enable CustomTabs",
|
|
||||||
description = "Enables CustomTabs to open articles in your default browser.",
|
|
||||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.magazines")],
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object EnableCustomTabs : BytecodePatch(
|
|
||||||
setOf(LaunchCustomTabFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
LaunchCustomTabFingerprint.resultOrThrow().let { result ->
|
|
||||||
result.mutableMethod.apply {
|
|
||||||
val checkIndex = result.scanResult.patternScanResult!!.endIndex + 1
|
|
||||||
val register = getInstruction<OneRegisterInstruction>(checkIndex).registerA
|
|
||||||
|
|
||||||
replaceInstruction(checkIndex, "const/4 v$register, 0x1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.customtabs.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
internal object LaunchCustomTabFingerprint : MethodFingerprint(
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IPUT,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IPUT_BOOLEAN,
|
|
||||||
),
|
|
||||||
customFingerprint = { _, classDef -> classDef.endsWith("CustomTabsArticleLauncher;") },
|
|
||||||
)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.gms
|
|
||||||
|
|
||||||
internal object Constants {
|
|
||||||
const val MAGAZINES_PACKAGE_NAME = "com.google.android.apps.magazines"
|
|
||||||
const val REVANCED_MAGAZINES_PACKAGE_NAME = "app.revanced.android.magazines"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.gms
|
|
||||||
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.fingerprints.MagazinesActivityOnCreateFingerprint
|
|
||||||
import app.revanced.patches.googlenews.misc.integrations.IntegrationsPatch
|
|
||||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
|
||||||
fromPackageName = MAGAZINES_PACKAGE_NAME,
|
|
||||||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
|
||||||
primeMethodFingerprint = null,
|
|
||||||
mainActivityOnCreateFingerprint = MagazinesActivityOnCreateFingerprint,
|
|
||||||
integrationsPatchDependency = IntegrationsPatch::class,
|
|
||||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
|
||||||
// Remove version constraint,
|
|
||||||
// once https://github.com/ReVanced/revanced-patches/pull/3111#issuecomment-2240877277 is resolved.
|
|
||||||
compatiblePackages = setOf(CompatiblePackage(MAGAZINES_PACKAGE_NAME, setOf("5.108.0.644447823"))),
|
|
||||||
) {
|
|
||||||
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.gms
|
|
||||||
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch
|
|
||||||
|
|
||||||
object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch(
|
|
||||||
fromPackageName = MAGAZINES_PACKAGE_NAME,
|
|
||||||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
|
||||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.gms.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
|
|
||||||
internal object MagazinesActivityOnCreateFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef, classDef ->
|
|
||||||
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.gms.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
|
|
||||||
internal object PrimeMethodFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("com.google.android.GoogleCamera", "com.android.vending"),
|
|
||||||
)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.integrations
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint
|
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
|
||||||
|
|
||||||
@Patch(requiresIntegrations = true)
|
|
||||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
|
||||||
setOf(StartActivityInitFingerprint),
|
|
||||||
)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package app.revanced.patches.googlenews.misc.integrations.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint.getApplicationContextIndex
|
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
|
|
||||||
internal object StartActivityInitFingerprint : IntegrationsFingerprint(
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IF_EQZ,
|
|
||||||
Opcode.CONST,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.IPUT_BOOLEAN,
|
|
||||||
Opcode.INVOKE_VIRTUAL, // Calls startActivity.getApplicationContext().
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
),
|
|
||||||
insertIndexResolver = { method ->
|
|
||||||
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
|
|
||||||
getReference<MethodReference>()?.name == "getApplicationContext"
|
|
||||||
}
|
|
||||||
|
|
||||||
getApplicationContextIndex + 2 // Below the move-result-object instruction.
|
|
||||||
},
|
|
||||||
contextRegisterResolver = { method ->
|
|
||||||
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
|
|
||||||
as OneRegisterInstruction
|
|
||||||
moveResultInstruction.registerA
|
|
||||||
},
|
|
||||||
customFingerprint = { methodDef, classDef ->
|
|
||||||
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
private var getApplicationContextIndex = -1
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.features
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.all.misc.build.BaseSpoofBuildInfoPatch
|
|
||||||
|
|
||||||
@Patch(description = "Spoof build info to Google Pixel XL.")
|
|
||||||
internal class SpoofBuildInfoPatch : BaseSpoofBuildInfoPatch() {
|
|
||||||
override val brand = "google"
|
|
||||||
override val manufacturer = "Google"
|
|
||||||
override val device = "marlin"
|
|
||||||
override val product = "marlin"
|
|
||||||
override val model = "Pixel XL"
|
|
||||||
override val fingerprint = "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys"
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.features
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringArrayPatchOption
|
|
||||||
import app.revanced.patches.googlephotos.features.fingerprints.InitializeFeaturesEnumFingerprint
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import app.revanced.util.resultOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
|
||||||
|
|
||||||
@Patch(
|
|
||||||
name = "Spoof features",
|
|
||||||
description = "Spoofs the device to enable Google Pixel exclusive features, including unlimited storage.",
|
|
||||||
dependencies = [SpoofBuildInfoPatch::class],
|
|
||||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.photos")],
|
|
||||||
)
|
|
||||||
@Suppress("unused")
|
|
||||||
object SpoofFeaturesPatch : BytecodePatch(setOf(InitializeFeaturesEnumFingerprint)) {
|
|
||||||
private val featuresToEnable by stringArrayPatchOption(
|
|
||||||
"featuresToEnable",
|
|
||||||
arrayOf(
|
|
||||||
"com.google.android.apps.photos.NEXUS_PRELOAD",
|
|
||||||
"com.google.android.apps.photos.nexus_preload",
|
|
||||||
),
|
|
||||||
title = "Features to enable",
|
|
||||||
description = "Google Pixel exclusive features to enable. Features up to Pixel XL enable the unlimited storage feature.",
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val featuresToDisable by stringArrayPatchOption(
|
|
||||||
"featuresToDisable",
|
|
||||||
arrayOf(
|
|
||||||
"com.google.android.apps.photos.PIXEL_2017_PRELOAD",
|
|
||||||
"com.google.android.apps.photos.PIXEL_2018_PRELOAD",
|
|
||||||
"com.google.android.apps.photos.PIXEL_2019_MIDYEAR_PRELOAD",
|
|
||||||
"com.google.android.apps.photos.PIXEL_2019_PRELOAD",
|
|
||||||
"com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2020_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2021_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2022_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2023_MIDYEAR_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2023_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
|
|
||||||
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
|
|
||||||
),
|
|
||||||
title = "Features to disable",
|
|
||||||
description = "Google Pixel exclusive features to disable." +
|
|
||||||
"Features after Pixel XL may have to be disabled for unlimited storage depending on the device.",
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
|
||||||
val featuresToEnable = featuresToEnable!!.toSet()
|
|
||||||
val featuresToDisable = featuresToDisable!!.toSet()
|
|
||||||
|
|
||||||
InitializeFeaturesEnumFingerprint.resultOrThrow().let { result ->
|
|
||||||
result.mutableMethod.apply {
|
|
||||||
getInstructions().filter { it.opcode == Opcode.CONST_STRING }.forEach {
|
|
||||||
val feature = it.getReference<StringReference>()!!.string
|
|
||||||
|
|
||||||
val spoofedFeature = when (feature) {
|
|
||||||
in featuresToEnable -> "android.hardware.wifi"
|
|
||||||
in featuresToDisable -> "dummy"
|
|
||||||
else -> return@forEach
|
|
||||||
}
|
|
||||||
|
|
||||||
val constStringIndex = it.location.index
|
|
||||||
val constStringRegister = (it as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
replaceInstruction(
|
|
||||||
constStringIndex,
|
|
||||||
"const-string v$constStringRegister, \"$spoofedFeature\"",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.features.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
|
|
||||||
object InitializeFeaturesEnumFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("com.google.android.apps.photos.NEXUS_PRELOAD"),
|
|
||||||
)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.gms
|
|
||||||
|
|
||||||
internal object Constants {
|
|
||||||
const val PHOTOS_PACKAGE_NAME = "com.google.android.apps.photos"
|
|
||||||
const val REVANCED_PHOTOS_PACKAGE_NAME = "app.revanced.android.photos"
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.gms
|
|
||||||
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.Constants.PHOTOS_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.Constants.REVANCED_PHOTOS_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.fingerprints.PhotosActivityOnCreateFingerprint
|
|
||||||
import app.revanced.patches.googlephotos.misc.integrations.IntegrationsPatch
|
|
||||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
|
||||||
|
|
||||||
@Suppress("unused")
|
|
||||||
object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
|
||||||
fromPackageName = PHOTOS_PACKAGE_NAME,
|
|
||||||
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
|
||||||
primeMethodFingerprint = null,
|
|
||||||
mainActivityOnCreateFingerprint = PhotosActivityOnCreateFingerprint,
|
|
||||||
integrationsPatchDependency = IntegrationsPatch::class,
|
|
||||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
|
||||||
compatiblePackages = setOf(CompatiblePackage(PHOTOS_PACKAGE_NAME)),
|
|
||||||
) {
|
|
||||||
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.gms
|
|
||||||
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.Constants.PHOTOS_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.googlephotos.misc.gms.Constants.REVANCED_PHOTOS_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch
|
|
||||||
|
|
||||||
object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch(
|
|
||||||
fromPackageName = PHOTOS_PACKAGE_NAME,
|
|
||||||
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
|
||||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
|
||||||
)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.gms.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
||||||
|
|
||||||
internal object PhotosActivityOnCreateFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef, classDef ->
|
|
||||||
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.integrations
|
|
||||||
|
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
|
||||||
import app.revanced.patches.googlephotos.misc.integrations.fingerprints.HomeActivityInitFingerprint
|
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
|
||||||
|
|
||||||
@Patch(requiresIntegrations = true)
|
|
||||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
|
||||||
setOf(HomeActivityInitFingerprint),
|
|
||||||
)
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package app.revanced.patches.googlephotos.misc.integrations.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patches.googlephotos.misc.integrations.fingerprints.HomeActivityInitFingerprint.getApplicationContextIndex
|
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
|
|
||||||
internal object HomeActivityInitFingerprint : IntegrationsFingerprint(
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.CONST_STRING,
|
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.IF_NEZ,
|
|
||||||
Opcode.INVOKE_VIRTUAL, // Calls getApplicationContext().
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
),
|
|
||||||
insertIndexResolver = { method ->
|
|
||||||
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
|
|
||||||
getReference<MethodReference>()?.name == "getApplicationContext"
|
|
||||||
}
|
|
||||||
|
|
||||||
getApplicationContextIndex + 2 // Below the move-result-object instruction.
|
|
||||||
},
|
|
||||||
contextRegisterResolver = { method ->
|
|
||||||
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
|
|
||||||
as OneRegisterInstruction
|
|
||||||
moveResultInstruction.registerA
|
|
||||||
},
|
|
||||||
customFingerprint = { methodDef, classDef ->
|
|
||||||
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
private var getApplicationContextIndex = -1
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.googlerecorder.restrictions
|
package app.revanced.patches.googlerecorder.restrictions
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.googlerecorder.restrictions.fingerprints
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
internal object OnApplicationCreateFingerprint : MethodFingerprint(
|
object OnApplicationCreateFingerprint : MethodFingerprint(
|
||||||
strings = listOf("com.google.android.feature.PIXEL_2017_EXPERIENCE"),
|
strings = listOf("com.google.android.feature.PIXEL_2017_EXPERIENCE"),
|
||||||
customFingerprint = custom@{ methodDef, classDef ->
|
customFingerprint = custom@{ methodDef, classDef ->
|
||||||
if (methodDef.name != "onCreate") return@custom false
|
if (methodDef.name != "onCreate") return@custom false
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.hexeditor.ad
|
package app.revanced.patches.hexeditor.ad
|
||||||
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.extensions.exception
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.hexeditor.ad.fingerprints
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
internal object PrimaryAdsFingerprint : MethodFingerprint(
|
object PrimaryAdsFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef, _ ->
|
customFingerprint = { methodDef, _ ->
|
||||||
methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled"
|
methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import app.revanced.patches.iconpackstudio.misc.pro.fingerprints.CheckProFingerp
|
|||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Unlock pro",
|
name = "Unlock pro",
|
||||||
compatiblePackages = [CompatiblePackage("ginlemon.iconpackstudio", ["2.2 build 016"])]
|
compatiblePackages = [CompatiblePackage("ginlemon.iconpackstudio")]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object UnlockProPatch : BytecodePatch(
|
object UnlockProPatch : BytecodePatch(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.iconpackstudio.misc.pro.fingerprints
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
internal object CheckProFingerprint : MethodFingerprint(
|
object CheckProFingerprint : MethodFingerprint(
|
||||||
"Z",
|
"Z",
|
||||||
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("IPSPurchaseRepository;")}
|
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("IPSPurchaseRepository;")}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,20 +7,20 @@ import app.revanced.patcher.patch.annotation.Patch
|
|||||||
import app.revanced.patches.idaustria.detection.root.fingerprints.AttestationSupportedCheckFingerprint
|
import app.revanced.patches.idaustria.detection.root.fingerprints.AttestationSupportedCheckFingerprint
|
||||||
import app.revanced.patches.idaustria.detection.root.fingerprints.BootloaderCheckFingerprint
|
import app.revanced.patches.idaustria.detection.root.fingerprints.BootloaderCheckFingerprint
|
||||||
import app.revanced.patches.idaustria.detection.root.fingerprints.RootCheckFingerprint
|
import app.revanced.patches.idaustria.detection.root.fingerprints.RootCheckFingerprint
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.Utils.returnEarly
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Remove root detection",
|
name = "Remove root detection",
|
||||||
description = "Removes the check for root permissions and unlocked bootloader.",
|
description = "Removes the check for root permissions and unlocked bootloader.",
|
||||||
compatiblePackages = [CompatiblePackage("at.gv.oe.app")],
|
compatiblePackages = [CompatiblePackage("at.gv.oe.app", ["3.0.2"])]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object RootDetectionPatch : BytecodePatch(
|
object RootDetectionPatch : BytecodePatch(
|
||||||
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint),
|
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext) = setOf(
|
override fun execute(context: BytecodeContext) = listOf(
|
||||||
AttestationSupportedCheckFingerprint,
|
AttestationSupportedCheckFingerprint,
|
||||||
BootloaderCheckFingerprint,
|
BootloaderCheckFingerprint,
|
||||||
RootCheckFingerprint,
|
RootCheckFingerprint
|
||||||
).returnEarly(true)
|
).returnEarly(true)
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user