You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-10 05:30:49 +02:00
Compare commits
123 Commits
v6.1.0
...
v11.0.2-de
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f3c9e28a62 | ||
![]() |
d5d6f85084 | ||
![]() |
b8151ebccb | ||
![]() |
5650e34432 | ||
![]() |
c893d16d52 | ||
![]() |
34f08bf206 | ||
![]() |
f02a42610b | ||
![]() |
c95e6fa92f | ||
![]() |
fd738e723b | ||
![]() |
b1d1956323 | ||
![]() |
725a8012ac | ||
![]() |
bb9a73e53b | ||
![]() |
ef2de35a74 | ||
![]() |
2a453d51a8 | ||
![]() |
43d6868d1f | ||
![]() |
cea9379b32 | ||
![]() |
a12fe7dd9e | ||
![]() |
efdd01a988 | ||
![]() |
eafe1c631f | ||
![]() |
aacf900764 | ||
![]() |
f82494e9bb | ||
![]() |
1e0ffa176e | ||
![]() |
b7eb2d2249 | ||
![]() |
b6d6a7591b | ||
![]() |
8f1c835299 | ||
![]() |
a188c16a99 | ||
![]() |
3e6804f06c | ||
![]() |
526a3d7c35 | ||
![]() |
28fc6a2ddd | ||
![]() |
d4f08d7bff | ||
![]() |
ca9fe322eb | ||
![]() |
239ea0bcaa | ||
![]() |
7f02b8df48 | ||
![]() |
a2052202b2 | ||
![]() |
223cea7021 | ||
![]() |
ac9337f694 | ||
![]() |
549651d04a | ||
![]() |
966bbd902e | ||
![]() |
81e6f8784e | ||
![]() |
9c53877888 | ||
![]() |
98f8eedecd | ||
![]() |
4ed429d25c | ||
![]() |
119d05f469 | ||
![]() |
2432fde6bf | ||
![]() |
49c173dc14 | ||
![]() |
d83e9372bb | ||
![]() |
7e8cd3bede | ||
![]() |
d67436271d | ||
![]() |
aa07f35f06 | ||
![]() |
77e0536838 | ||
![]() |
a49e78234b | ||
![]() |
a3ae825e48 | ||
![]() |
146c8504ed | ||
![]() |
2eb125ad69 | ||
![]() |
6e24a85eab | ||
![]() |
e4c3e9ffc5 | ||
![]() |
4c1778a62f | ||
![]() |
d99261cdbb | ||
![]() |
ac1c0f2773 | ||
![]() |
eddd4ec7ac | ||
![]() |
07a2829c65 | ||
![]() |
3d77e299d9 | ||
![]() |
f1336f89e4 | ||
![]() |
0502f84c20 | ||
![]() |
058d292ad5 | ||
![]() |
1029d56a52 | ||
![]() |
709b5a0fec | ||
![]() |
e1accc5041 | ||
![]() |
6dbbf2e03e | ||
![]() |
16557eeab0 | ||
![]() |
6bca3e2bb5 | ||
![]() |
a263fdfd41 | ||
![]() |
e4b4bacae8 | ||
![]() |
cbc97af155 | ||
![]() |
d5533788e2 | ||
![]() |
5a4ea5cd7d | ||
![]() |
70f3c8b38c | ||
![]() |
6b410a0eea | ||
![]() |
73a013d75b | ||
![]() |
7159f3db4c | ||
![]() |
7d5ecf095c | ||
![]() |
fa015a424d | ||
![]() |
dd7dd38357 | ||
![]() |
22356f2d26 | ||
![]() |
66701f6076 | ||
![]() |
6a6ded084e | ||
![]() |
5887c69bde | ||
![]() |
4102f43b8a | ||
![]() |
5c09ef7837 | ||
![]() |
3e0bf8c863 | ||
![]() |
8f3ecc318c | ||
![]() |
365da96e2b | ||
![]() |
cd68ec4803 | ||
![]() |
35265e029c | ||
![]() |
9f0a09a756 | ||
![]() |
e802141df5 | ||
![]() |
abebc0862c | ||
![]() |
96ef150e89 | ||
![]() |
c5de9e2988 | ||
![]() |
c391ca648b | ||
![]() |
7cf79e68e0 | ||
![]() |
f07db3c214 | ||
![]() |
88bb3a8845 | ||
![]() |
b9e6bd6775 | ||
![]() |
cd1b72e078 | ||
![]() |
6b889557ab | ||
![]() |
4b1be8c647 | ||
![]() |
73c893c6e7 | ||
![]() |
75b36823b8 | ||
![]() |
d2d93cd075 | ||
![]() |
26b8621ac8 | ||
![]() |
f365a41741 | ||
![]() |
9ec720e983 | ||
![]() |
0f432b3fdd | ||
![]() |
96cd5618dd | ||
![]() |
c2a5a55e67 | ||
![]() |
6c5de8b414 | ||
![]() |
ea773cfa56 | ||
![]() |
a306561b55 | ||
![]() |
b6dcd88495 | ||
![]() |
a925650044 | ||
![]() |
77bbf6be1f | ||
![]() |
bd053b7e99 |
2
.github/config.yml
vendored
Normal file
2
.github/config.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
firstPRMergeComment: >
|
||||||
|
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.
|
25
.github/workflows/pull_request.yml
vendored
Normal file
25
.github/workflows/pull_request.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: PR to main
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
MESSAGE: merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pull-request:
|
||||||
|
name: Open pull request
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Open pull request
|
||||||
|
uses: repo-sync/pull-request@v2
|
||||||
|
with:
|
||||||
|
destination_branch: 'main'
|
||||||
|
pr_title: 'chore: ${{ env.MESSAGE }}'
|
||||||
|
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
|
||||||
|
pr_draft: true
|
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@@ -1,4 +1,5 @@
|
|||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -9,6 +10,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
@@ -17,24 +19,27 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
# Make sure the release step uses its own credentials:
|
||||||
|
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
||||||
|
persist-credentials: false
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup JDK
|
- name: Cache
|
||||||
uses: actions/setup-java@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
path: |
|
||||||
distribution: 'temurin'
|
${{ runner.home }}/.gradle/caches
|
||||||
cache: gradle
|
${{ runner.home }}/.gradle/wrapper
|
||||||
- name: Setup Node.js
|
.gradle
|
||||||
uses: actions/setup-node@v3
|
build
|
||||||
with:
|
node_modules
|
||||||
node-version: "lts/*"
|
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew build
|
run: ./gradlew clean --no-daemon
|
||||||
- name: Setup semantic-release
|
- name: Setup semantic-release
|
||||||
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
run: npm install
|
||||||
- name: Release
|
- name: Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||||
run: npx semantic-release
|
run: npm exec semantic-release
|
||||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@@ -74,6 +74,7 @@ cmake-build-*/
|
|||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
out/
|
||||||
|
.idea/
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
# mpeltonen/sbt-idea plugin
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
@@ -115,3 +116,9 @@ gradle-app.setting
|
|||||||
|
|
||||||
# Avoid ignoring test resources
|
# Avoid ignoring test resources
|
||||||
!src/test/resources/*
|
!src/test/resources/*
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Gradle props, to avoid sharing the gpr key
|
||||||
|
gradle.properties
|
||||||
|
9
.idea/.gitignore
generated
vendored
9
.idea/.gitignore
generated
vendored
@@ -1,9 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
/kotlinc.xml
|
|
10
.idea/codeStyles/Project.xml
generated
10
.idea/codeStyles/Project.xml
generated
@@ -1,10 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<JetCodeStyleSettings>
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</JetCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="kotlin">
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
7
.idea/discord.xml
generated
7
.idea/discord.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="PROJECT_FILES" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
15
.idea/git_toolbox_prj.xml
generated
15
.idea/git_toolbox_prj.xml
generated
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GitToolBoxProjectSettings">
|
|
||||||
<option name="commitMessageIssueKeyValidationOverride">
|
|
||||||
<BoolValueOverride>
|
|
||||||
<option name="enabled" value="true" />
|
|
||||||
</BoolValueOverride>
|
|
||||||
</option>
|
|
||||||
<option name="commitMessageValidationEnabledOverride">
|
|
||||||
<BoolValueOverride>
|
|
||||||
<option name="enabled" value="true" />
|
|
||||||
</BoolValueOverride>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
6
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
10
.idea/misc.xml
generated
10
.idea/misc.xml
generated
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
12
.idea/vcs.xml
generated
12
.idea/vcs.xml
generated
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CommitMessageInspectionProfile">
|
|
||||||
<profile version="1.0">
|
|
||||||
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
20
.releaserc
20
.releaserc
@@ -7,11 +7,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
["@semantic-release/commit-analyzer", {
|
"@semantic-release/commit-analyzer",
|
||||||
"releaseRules": [
|
|
||||||
{"type": "build", "release": "patch"}
|
|
||||||
]
|
|
||||||
}],
|
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
"@semantic-release/changelog",
|
"@semantic-release/changelog",
|
||||||
"gradle-semantic-release-plugin",
|
"gradle-semantic-release-plugin",
|
||||||
@@ -24,6 +20,18 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@semantic-release/github"
|
[
|
||||||
|
"@saithodev/semantic-release-backmerge",
|
||||||
|
{
|
||||||
|
backmergeBranches: [{"from": "main", "to": "dev"}],
|
||||||
|
clearWorkspace: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@semantic-release/github",
|
||||||
|
{
|
||||||
|
successComment: false
|
||||||
|
}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
315
CHANGELOG.md
315
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,3 @@
|
|||||||
# Patcher
|
# 💉 ReVanced Patcher
|
||||||
Patcher framework used in the ReVanced project.
|
|
||||||
|
ReVanced Patcher used to patch Android applications.
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.7.0"
|
kotlin("jvm") version "1.8.10"
|
||||||
java
|
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,12 +21,12 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("xpp3:xpp3:1.1.4c")
|
implementation("xpp3:xpp3:1.1.4c")
|
||||||
implementation("org.smali:smali:2.5.2")
|
implementation("app.revanced:smali:2.5.3-a3836654")
|
||||||
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
implementation("app.revanced:multidexlib2:2.5.3-a3836654")
|
||||||
implementation("org.apktool:apktool-lib:2.8.1-SNAPSHOT")
|
implementation("app.revanced:apktool-lib:2.7.0")
|
||||||
|
|
||||||
implementation(kotlin("reflect"))
|
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.20-RC")
|
||||||
testImplementation(kotlin("test"))
|
testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20-RC")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
@@ -46,6 +45,10 @@ java {
|
|||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(11)
|
||||||
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
if (System.getenv("GITHUB_ACTOR") != null)
|
if (System.getenv("GITHUB_ACTOR") != null)
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 6.1.0
|
version = 11.0.2-dev.1
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
6580
package-lock.json
generated
Normal file
6580
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
package.json
Normal file
9
package.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"@saithodev/semantic-release-backmerge": "^3.1.0",
|
||||||
|
"@semantic-release/changelog": "^6.0.2",
|
||||||
|
"@semantic-release/git": "^10.0.1",
|
||||||
|
"gradle-semantic-release-plugin": "^1.7.6",
|
||||||
|
"semantic-release": "^20.1.0"
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,9 @@
|
|||||||
package app.revanced.patcher
|
package app.revanced.patcher
|
||||||
|
|
||||||
import app.revanced.patcher.data.Context
|
import app.revanced.patcher.data.Context
|
||||||
import app.revanced.patcher.data.findIndexed
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.dependencies
|
import app.revanced.patcher.extensions.PatchExtensions.dependencies
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
||||||
import app.revanced.patcher.extensions.nullOutputStream
|
import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.*
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.util.VersionReader
|
import app.revanced.patcher.util.VersionReader
|
||||||
@@ -24,10 +23,12 @@ import lanchon.multidexlib2.MultiDexIO
|
|||||||
import org.jf.dexlib2.Opcodes
|
import org.jf.dexlib2.Opcodes
|
||||||
import org.jf.dexlib2.iface.DexFile
|
import org.jf.dexlib2.iface.DexFile
|
||||||
import org.jf.dexlib2.writer.io.MemoryDataStore
|
import org.jf.dexlib2.writer.io.MemoryDataStore
|
||||||
|
import java.io.Closeable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.OutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
|
||||||
private val NAMER = BasicDexFileNamer()
|
internal val NAMER = BasicDexFileNamer()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ReVanced Patcher.
|
* The ReVanced Patcher.
|
||||||
@@ -37,6 +38,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
private val logger = options.logger
|
private val logger = options.logger
|
||||||
private val opcodes: Opcodes
|
private val opcodes: Opcodes
|
||||||
private var resourceDecodingMode = ResourceDecodingMode.MANIFEST_ONLY
|
private var resourceDecodingMode = ResourceDecodingMode.MANIFEST_ONLY
|
||||||
|
private var mergeIntegrations = false
|
||||||
val context: PatcherContext
|
val context: PatcherContext
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -63,42 +65,19 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add additional dex file container to the patcher.
|
* Add integrations to be merged by the patcher.
|
||||||
* @param files The dex file containers to add to the patcher.
|
* The integrations will only be merged, if necessary.
|
||||||
* @param allowedOverwrites A list of class types that are allowed to be overwritten.
|
*
|
||||||
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
|
* @param integrations The integrations, must be dex files or dex file container such as ZIP, APK or DEX files.
|
||||||
|
* @param callback The callback for [integrations] which are being added.
|
||||||
*/
|
*/
|
||||||
fun addFiles(
|
fun addIntegrations(
|
||||||
files: List<File>,
|
integrations: List<File>,
|
||||||
allowedOverwrites: Iterable<String> = emptyList(),
|
|
||||||
throwOnDuplicates: Boolean = false,
|
|
||||||
callback: (File) -> Unit
|
callback: (File) -> Unit
|
||||||
) {
|
) {
|
||||||
for (file in files) {
|
context.integrations.apply integrations@{
|
||||||
var modified = false
|
add(integrations)
|
||||||
for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
|
this@integrations.callback = callback
|
||||||
val type = classDef.type
|
|
||||||
|
|
||||||
val existingClass = context.bytecodeContext.classes.classes.findIndexed { it.type == type }
|
|
||||||
if (existingClass == null) {
|
|
||||||
if (throwOnDuplicates) throw Exception("Class $type has already been added to the patcher")
|
|
||||||
|
|
||||||
logger.trace("Merging $type")
|
|
||||||
context.bytecodeContext.classes.classes.add(classDef)
|
|
||||||
modified = true
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowedOverwrites.contains(type)) continue
|
|
||||||
|
|
||||||
logger.trace("Overwriting $type")
|
|
||||||
|
|
||||||
val index = existingClass.second
|
|
||||||
context.bytecodeContext.classes.classes[index] = classDef
|
|
||||||
modified = true
|
|
||||||
}
|
|
||||||
if (modified) callback(file)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +133,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
cacheDirectory.close()
|
cacheDirectory.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> logger.info("Not compiling resources because resource patching is not required")
|
else -> logger.info("Not compiling resources because resource patching is not required")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,18 +166,29 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
*/
|
*/
|
||||||
fun addPatches(patches: Iterable<Class<out Patch<Context>>>) {
|
fun addPatches(patches: Iterable<Class<out Patch<Context>>>) {
|
||||||
/**
|
/**
|
||||||
* Fill the cache with the instances of the [Patch]es for later use.
|
* Returns true if at least one patches or its dependencies matches the given predicate.
|
||||||
* Note: Dependencies of the [Patch] will be cached as well.
|
|
||||||
*/
|
*/
|
||||||
fun Class<out Patch<Context>>.isResource() {
|
fun Class<out Patch<Context>>.anyRecursively(predicate: (Class<out Patch<Context>>) -> Boolean): Boolean =
|
||||||
this.also {
|
predicate(this) || dependencies?.any { it.java.anyRecursively(predicate) } == true
|
||||||
if (!ResourcePatch::class.java.isAssignableFrom(it)) return@also
|
|
||||||
// set the mode to decode all resources before running the patches
|
|
||||||
|
// Determine if resource patching is required.
|
||||||
|
for (patch in patches) {
|
||||||
|
if (patch.anyRecursively { ResourcePatch::class.java.isAssignableFrom(it) }) {
|
||||||
resourceDecodingMode = ResourceDecodingMode.FULL
|
resourceDecodingMode = ResourceDecodingMode.FULL
|
||||||
}.dependencies?.forEach { it.java.isResource() }
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.patches.addAll(patches.onEach(Class<out Patch<Context>>::isResource))
|
// Determine if merging integrations is required.
|
||||||
|
for (patch in patches) {
|
||||||
|
if (patch.anyRecursively { it.requiresIntegrations }) {
|
||||||
|
mergeIntegrations = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.patches.addAll(patches)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,6 +231,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceDecodingMode.MANIFEST_ONLY -> {
|
ResourceDecodingMode.MANIFEST_ONLY -> {
|
||||||
logger.info("Decoding AndroidManifest.xml only, because resources are not needed")
|
logger.info("Decoding AndroidManifest.xml only, because resources are not needed")
|
||||||
|
|
||||||
@@ -256,7 +248,12 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
XmlPullStreamDecoder(
|
XmlPullStreamDecoder(
|
||||||
axmlParser, AndrolibResources().resXmlSerializer
|
axmlParser, AndrolibResources().resXmlSerializer
|
||||||
).decodeManifest(
|
).decodeManifest(
|
||||||
extInputFile.directory.getFileInput("AndroidManifest.xml"), nullOutputStream
|
extInputFile.directory.getFileInput("AndroidManifest.xml"),
|
||||||
|
object : OutputStream() {
|
||||||
|
override fun write(b: Int) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,9 +307,10 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
val result = executePatch(dependency, executedPatches)
|
val result = executePatch(dependency, executedPatches)
|
||||||
if (result.isSuccess()) return@forEach
|
if (result.isSuccess()) return@forEach
|
||||||
|
|
||||||
val error = result.error()!!
|
return PatchResultError(
|
||||||
val errorMessage = error.cause ?: error.message
|
"'$patchName' depends on '${dependency.patchName}' but the following error was raised: " +
|
||||||
return PatchResultError("'$patchName' depends on '${dependency.patchName}' but the following error was raised: $errorMessage")
|
result.error()!!.let { it.cause?.stackTraceToString() ?: it.message }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isResourcePatch = ResourcePatch::class.java.isAssignableFrom(patchClass)
|
val isResourcePatch = ResourcePatch::class.java.isAssignableFrom(patchClass)
|
||||||
@@ -344,6 +342,8 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sequence {
|
return sequence {
|
||||||
|
if (mergeIntegrations) context.integrations.merge(logger)
|
||||||
|
|
||||||
// prevent from decoding the manifest twice if it is not needed
|
// prevent from decoding the manifest twice if it is not needed
|
||||||
if (resourceDecodingMode == ResourceDecodingMode.FULL) decodeResources(ResourceDecodingMode.FULL)
|
if (resourceDecodingMode == ResourceDecodingMode.FULL) decodeResources(ResourceDecodingMode.FULL)
|
||||||
|
|
||||||
@@ -351,24 +351,42 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
|
|
||||||
val executedPatches = LinkedHashMap<String, ExecutedPatch>() // first is name
|
val executedPatches = LinkedHashMap<String, ExecutedPatch>() // first is name
|
||||||
|
|
||||||
try {
|
|
||||||
context.patches.forEach { patch ->
|
|
||||||
val patchResult = executePatch(patch, executedPatches)
|
|
||||||
|
|
||||||
val result = if (patchResult.isSuccess()) {
|
context.patches.forEach { patch ->
|
||||||
Result.success(patchResult.success()!!)
|
val patchResult = executePatch(patch, executedPatches)
|
||||||
} else {
|
|
||||||
Result.failure(patchResult.error()!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
yield(patch.patchName to result)
|
val result = if (patchResult.isSuccess()) {
|
||||||
if (stopOnError && patchResult.isError()) return@sequence
|
Result.success(patchResult.success()!!)
|
||||||
}
|
} else {
|
||||||
} finally {
|
Result.failure(patchResult.error()!!)
|
||||||
executedPatches.values.reversed().forEach { (patch, _) ->
|
|
||||||
patch.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This prints before the patch really finishes in case it is a Closeable
|
||||||
|
// because the Closeable is closed after all patches are executed.
|
||||||
|
yield(patch.patchName to result)
|
||||||
|
|
||||||
|
if (stopOnError && patchResult.isError()) return@sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
executedPatches.values
|
||||||
|
.filter(ExecutedPatch::success)
|
||||||
|
.map(ExecutedPatch::patchInstance)
|
||||||
|
.filterIsInstance(Closeable::class.java)
|
||||||
|
.asReversed().forEach {
|
||||||
|
try {
|
||||||
|
it.close()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
val patchName = (it as Patch<Context>).javaClass.patchName
|
||||||
|
|
||||||
|
logger.error("Failed to close '$patchName': ${exception.stackTraceToString()}")
|
||||||
|
|
||||||
|
yield(patchName to Result.failure(exception))
|
||||||
|
|
||||||
|
// This is not failsafe. If a patch throws an exception while closing,
|
||||||
|
// the other patches that depend on it may fail.
|
||||||
|
if (stopOnError) return@sequence
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
package app.revanced.patcher
|
package app.revanced.patcher
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.*
|
||||||
import app.revanced.patcher.data.Context
|
import app.revanced.patcher.logging.Logger
|
||||||
import app.revanced.patcher.data.PackageMetadata
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.Patch
|
import app.revanced.patcher.patch.Patch
|
||||||
|
import app.revanced.patcher.util.ClassMerger.merge
|
||||||
import org.jf.dexlib2.iface.ClassDef
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -14,6 +13,52 @@ data class PatcherContext(
|
|||||||
) {
|
) {
|
||||||
val packageMetadata = PackageMetadata()
|
val packageMetadata = PackageMetadata()
|
||||||
internal val patches = mutableListOf<Class<out Patch<Context>>>()
|
internal val patches = mutableListOf<Class<out Patch<Context>>>()
|
||||||
|
internal val integrations = Integrations(this)
|
||||||
internal val bytecodeContext = BytecodeContext(classes)
|
internal val bytecodeContext = BytecodeContext(classes)
|
||||||
internal val resourceContext = ResourceContext(resourceCacheDirectory)
|
internal val resourceContext = ResourceContext(resourceCacheDirectory)
|
||||||
|
|
||||||
|
internal class Integrations(val context: PatcherContext) {
|
||||||
|
var callback: ((File) -> Unit)? = null
|
||||||
|
private val integrations: MutableList<File> = mutableListOf()
|
||||||
|
|
||||||
|
fun add(integrations: List<File>) = this@Integrations.integrations.addAll(integrations)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge integrations.
|
||||||
|
* @param logger A logger.
|
||||||
|
*/
|
||||||
|
fun merge(logger: Logger) {
|
||||||
|
with(context.bytecodeContext.classes) {
|
||||||
|
for (integrations in integrations) {
|
||||||
|
callback?.let { it(integrations) }
|
||||||
|
|
||||||
|
for (classDef in lanchon.multidexlib2.MultiDexIO.readDexFile(
|
||||||
|
true,
|
||||||
|
integrations,
|
||||||
|
NAMER,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
).classes) {
|
||||||
|
val type = classDef.type
|
||||||
|
|
||||||
|
val result = classes.findIndexed { it.type == type }
|
||||||
|
if (result == null) {
|
||||||
|
logger.trace("Merging type $type")
|
||||||
|
classes.add(classDef)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val (existingClass, existingClassIndex) = result
|
||||||
|
|
||||||
|
logger.trace("Type $type exists. Adding missing methods and fields.")
|
||||||
|
|
||||||
|
existingClass.merge(classDef, context, logger).let { mergedClass ->
|
||||||
|
if (mergedClass !== existingClass) // referential equality check
|
||||||
|
classes[existingClassIndex] = mergedClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -15,7 +15,7 @@ import java.io.File
|
|||||||
data class PatcherOptions(
|
data class PatcherOptions(
|
||||||
internal val inputFile: File,
|
internal val inputFile: File,
|
||||||
internal val resourceCacheDirectory: String,
|
internal val resourceCacheDirectory: String,
|
||||||
internal val aaptPath: String = "",
|
internal val aaptPath: String? = null,
|
||||||
internal val frameworkFolderLocation: String? = null,
|
internal val frameworkFolderLocation: String? = null,
|
||||||
internal val logger: Logger = NopLogger
|
internal val logger: Logger = NopLogger
|
||||||
)
|
)
|
||||||
|
@@ -7,8 +7,6 @@ import app.revanced.patcher.patch.Patch
|
|||||||
* @param compatiblePackages A list of packages a [Patch] is compatible with.
|
* @param compatiblePackages A list of packages a [Patch] is compatible with.
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
@MustBeDocumented
|
|
||||||
annotation class Compatibility(
|
annotation class Compatibility(
|
||||||
val compatiblePackages: Array<Package>,
|
val compatiblePackages: Array<Package>,
|
||||||
)
|
)
|
||||||
@@ -19,8 +17,6 @@ annotation class Compatibility(
|
|||||||
* @param versions The versions of the package the [Patch] is compatible with.
|
* @param versions The versions of the package the [Patch] is compatible with.
|
||||||
*/
|
*/
|
||||||
@Target()
|
@Target()
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
@MustBeDocumented
|
|
||||||
annotation class Package(
|
annotation class Package(
|
||||||
val name: String,
|
val name: String,
|
||||||
val versions: Array<String> = [],
|
val versions: Array<String> = [],
|
||||||
|
@@ -7,8 +7,6 @@ import app.revanced.patcher.patch.Patch
|
|||||||
* @param name A suggestive name for the [Patch].
|
* @param name A suggestive name for the [Patch].
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
@MustBeDocumented
|
|
||||||
annotation class Name(
|
annotation class Name(
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
@@ -18,8 +16,6 @@ annotation class Name(
|
|||||||
* @param description A description for the [Patch].
|
* @param description A description for the [Patch].
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
@MustBeDocumented
|
|
||||||
annotation class Description(
|
annotation class Description(
|
||||||
val description: String,
|
val description: String,
|
||||||
)
|
)
|
||||||
@@ -30,8 +26,6 @@ annotation class Description(
|
|||||||
* @param version The version of a [Patch].
|
* @param version The version of a [Patch].
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
@MustBeDocumented
|
|
||||||
annotation class Version(
|
annotation class Version(
|
||||||
val version: String,
|
val version: String,
|
||||||
)
|
)
|
||||||
|
@@ -54,17 +54,6 @@ class BytecodeContext internal constructor(classes: MutableList<ClassDef>) : Con
|
|||||||
}
|
}
|
||||||
return proxy
|
return proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
|
||||||
inline fun <reified T> Iterable<T>.find(predicate: (T) -> Boolean): T? {
|
|
||||||
for (element in this) {
|
|
||||||
if (predicate(element)) {
|
|
||||||
return element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,79 +1,33 @@
|
|||||||
package app.revanced.patcher.extensions
|
package app.revanced.patcher.extensions
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.*
|
|
||||||
import app.revanced.patcher.data.Context
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.patch.OptionsContainer
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.PatchOptions
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KVisibility
|
|
||||||
import kotlin.reflect.full.companionObject
|
|
||||||
import kotlin.reflect.full.companionObjectInstance
|
|
||||||
|
|
||||||
/**
|
internal object AnnotationExtensions {
|
||||||
* Recursively find a given annotation on a class.
|
/**
|
||||||
* @param targetAnnotation The annotation to find.
|
* Recursively find a given annotation on a class.
|
||||||
* @return The annotation.
|
*
|
||||||
*/
|
* @param targetAnnotation The annotation to find.
|
||||||
private fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: KClass<T>) =
|
* @return The annotation.
|
||||||
this.findAnnotationRecursively(targetAnnotation.java, mutableSetOf())
|
*/
|
||||||
|
fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: KClass<T>): T? {
|
||||||
|
fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
||||||
|
targetAnnotation: Class<T>, traversed: MutableSet<Annotation>
|
||||||
|
): T? {
|
||||||
|
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST") if (found != null) return found as T
|
||||||
|
|
||||||
private fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
for (annotation in this.annotations) {
|
||||||
targetAnnotation: Class<T>, traversed: MutableSet<Annotation>
|
if (traversed.contains(annotation)) continue
|
||||||
): T? {
|
traversed.add(annotation)
|
||||||
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST") if (found != null) return found as T
|
return (annotation.annotationClass.java.findAnnotationRecursively(targetAnnotation, traversed))
|
||||||
|
?: continue
|
||||||
for (annotation in this.annotations) {
|
|
||||||
if (traversed.contains(annotation)) continue
|
|
||||||
traversed.add(annotation)
|
|
||||||
|
|
||||||
return (annotation.annotationClass.java.findAnnotationRecursively(targetAnnotation, traversed)) ?: continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
object PatchExtensions {
|
|
||||||
val Class<out Patch<Context>>.patchName: String
|
|
||||||
get() = findAnnotationRecursively(Name::class)?.name ?: this.simpleName
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.version
|
|
||||||
get() = findAnnotationRecursively(Version::class)?.version
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.include
|
|
||||||
get() = findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)!!.include
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.description
|
|
||||||
get() = findAnnotationRecursively(Description::class)?.description
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.dependencies
|
|
||||||
get() = findAnnotationRecursively(DependsOn::class)?.dependencies
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.compatiblePackages
|
|
||||||
get() = findAnnotationRecursively(Compatibility::class)?.compatiblePackages
|
|
||||||
|
|
||||||
val Class<out Patch<Context>>.options: PatchOptions?
|
|
||||||
get() = kotlin.companionObject?.let { cl ->
|
|
||||||
if (cl.visibility != KVisibility.PUBLIC) return null
|
|
||||||
kotlin.companionObjectInstance?.let {
|
|
||||||
(it as? OptionsContainer)?.options
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return this.findAnnotationRecursively(targetAnnotation.java, mutableSetOf())
|
||||||
object MethodFingerprintExtensions {
|
}
|
||||||
val MethodFingerprint.name: String
|
|
||||||
get() = this.javaClass.simpleName
|
|
||||||
|
|
||||||
val MethodFingerprint.fuzzyPatternScanMethod
|
|
||||||
get() = javaClass.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
|
||||||
|
|
||||||
val MethodFingerprint.fuzzyScanThreshold
|
|
||||||
get() = fuzzyPatternScanMethod?.threshold ?: 0
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
|||||||
|
package app.revanced.patcher.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object MethodFingerprintExtensions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of a [MethodFingerprint].
|
||||||
|
*/
|
||||||
|
val MethodFingerprint.name: String
|
||||||
|
get() = this.javaClass.simpleName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [FuzzyPatternScanMethod] annotation of a [MethodFingerprint].
|
||||||
|
*/
|
||||||
|
val MethodFingerprint.fuzzyPatternScanMethod
|
||||||
|
get() = javaClass.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
||||||
|
}
|
@@ -0,0 +1,71 @@
|
|||||||
|
package app.revanced.patcher.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.Context
|
||||||
|
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||||
|
import app.revanced.patcher.patch.OptionsContainer
|
||||||
|
import app.revanced.patcher.patch.Patch
|
||||||
|
import app.revanced.patcher.patch.PatchOptions
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
||||||
|
import kotlin.reflect.KVisibility
|
||||||
|
import kotlin.reflect.full.companionObject
|
||||||
|
import kotlin.reflect.full.companionObjectInstance
|
||||||
|
|
||||||
|
object PatchExtensions {
|
||||||
|
/**
|
||||||
|
* The name of a [Patch].
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.patchName: String
|
||||||
|
get() = findAnnotationRecursively(Name::class)?.name ?: this.simpleName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of a [Patch].
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.version
|
||||||
|
get() = findAnnotationRecursively(Version::class)?.version
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weather or not a [Patch] should be included.
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.include
|
||||||
|
get() = findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)!!.include
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of a [Patch].
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.description
|
||||||
|
get() = findAnnotationRecursively(Description::class)?.description
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dependencies of a [Patch].
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.dependencies
|
||||||
|
get() = findAnnotationRecursively(DependsOn::class)?.dependencies
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The packages a [Patch] is compatible with.
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.compatiblePackages
|
||||||
|
get() = findAnnotationRecursively(Compatibility::class)?.compatiblePackages
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weather or not a [Patch] requires integrations.
|
||||||
|
*/
|
||||||
|
internal val Class<out Patch<Context>>.requiresIntegrations
|
||||||
|
get() = findAnnotationRecursively(RequiresIntegrations::class) != null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options of a [Patch].
|
||||||
|
*/
|
||||||
|
val Class<out Patch<Context>>.options: PatchOptions?
|
||||||
|
get() = kotlin.companionObject?.let { cl ->
|
||||||
|
if (cl.visibility != KVisibility.PUBLIC) return null
|
||||||
|
kotlin.companionObjectInstance?.let {
|
||||||
|
(it as? OptionsContainer)?.options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,7 +7,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
* @param threshold if [threshold] or more of the opcodes do not match, skip.
|
* @param threshold if [threshold] or more of the opcodes do not match, skip.
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
annotation class FuzzyPatternScanMethod(
|
annotation class FuzzyPatternScanMethod(
|
||||||
val threshold: Int = 1
|
val threshold: Int = 1
|
||||||
)
|
)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user