You've already forked revanced-patcher
mirror of
https://github.com/revanced/revanced-patcher
synced 2025-09-06 16:38:50 +02:00
Compare commits
170 Commits
v5.1.1
...
arsclib-re
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c6fdf97794 | ||
![]() |
c52f0b80f2 | ||
![]() |
4b5e25b29c | ||
![]() |
c752a3c596 | ||
![]() |
740911a2a3 | ||
![]() |
242d805c6c | ||
![]() |
c543fdc18b | ||
![]() |
d48a8e697f | ||
![]() |
8749a61d39 | ||
![]() |
a4a030f2b2 | ||
![]() |
dcc4ecd237 | ||
![]() |
57f3036a96 | ||
![]() |
753e55dfc3 | ||
![]() |
9d81baf4b4 | ||
![]() |
7cb4d4c596 | ||
![]() |
2c8565508e | ||
![]() |
c7f156e4c9 | ||
![]() |
fcef4342e8 | ||
![]() |
72783a5e74 | ||
![]() |
a379b69eeb | ||
![]() |
0a8ccba33e | ||
![]() |
519359a9eb | ||
![]() |
b615ed6aab | ||
![]() |
d718134ab2 | ||
![]() |
5e681ed381 | ||
![]() |
6e1b6479b6 | ||
![]() |
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 | ||
![]() |
fd742eba63 | ||
![]() |
ba9d998681 | ||
![]() |
75df245ec3 | ||
![]() |
4164cb0dea | ||
![]() |
18fe35ae73 | ||
![]() |
f9bc95f220 | ||
![]() |
d2f91a8545 | ||
![]() |
4016bdc37f | ||
![]() |
538b2a8599 | ||
![]() |
4aa14bbb85 | ||
![]() |
d37452997b | ||
![]() |
db21d5e953 | ||
![]() |
4d581811db | ||
![]() |
8c502448be | ||
![]() |
fec16d9442 | ||
![]() |
5583904994 | ||
![]() |
797286b758 | ||
![]() |
4ae9ad09d6 | ||
![]() |
447e1ad30e | ||
![]() |
843e62ad29 | ||
![]() |
9c07ffcc7a |
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# Linux start script should use lf
|
||||
/gradlew text eol=lf
|
||||
|
||||
# These are Windows script files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
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
|
33
.github/workflows/release.yml
vendored
33
.github/workflows/release.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
@@ -9,32 +10,36 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
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
|
||||
- name: Setup JDK
|
||||
uses: actions/setup-java@v2
|
||||
- name: Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
path: |
|
||||
${{ runner.home }}/.gradle/caches
|
||||
${{ runner.home }}/.gradle/wrapper
|
||||
.gradle
|
||||
build
|
||||
node_modules
|
||||
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew build
|
||||
run: ./gradlew clean --no-daemon
|
||||
- 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
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx semantic-release
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
run: npm exec semantic-release
|
||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@@ -74,6 +74,7 @@ cmake-build-*/
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
.idea/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
@@ -115,3 +116,9 @@ gradle-app.setting
|
||||
|
||||
# Avoid ignoring 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": [
|
||||
["@semantic-release/commit-analyzer", {
|
||||
"releaseRules": [
|
||||
{"type": "build", "release": "patch"}
|
||||
]
|
||||
}],
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog",
|
||||
"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
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
431
CHANGELOG.md
431
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,3 @@
|
||||
# Patcher
|
||||
Patcher framework used in the ReVanced project.
|
||||
# 💉 ReVanced Patcher
|
||||
|
||||
ReVanced Patcher used to patch Android applications.
|
||||
|
42
arsclib-utils/.gitignore
vendored
Normal file
42
arsclib-utils/.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
18
arsclib-utils/build.gradle.kts
Normal file
18
arsclib-utils/build.gradle.kts
Normal file
@@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "app.revanced"
|
||||
|
||||
dependencies {
|
||||
implementation("io.github.reandroid:ARSCLib:1.1.7")
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(11)
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package app.revanced.arsc
|
||||
|
||||
/**
|
||||
* An exception thrown when there is an error with APK resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
sealed class ApkResourceException(message: String, throwable: Throwable? = null) : Exception(message, throwable) {
|
||||
/**
|
||||
* An exception when locking resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class Locked(message: String, throwable: Throwable? = null) : ApkResourceException(message, throwable)
|
||||
|
||||
/**
|
||||
* An exception when writing resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class Write(message: String, throwable: Throwable? = null) : ApkResourceException(message, throwable)
|
||||
|
||||
/**
|
||||
* An exception when reading resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class Read(message: String, throwable: Throwable? = null) : ApkResourceException(message, throwable)
|
||||
/**
|
||||
* An exception when decoding resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class Decode(message: String, throwable: Throwable? = null) : ApkResourceException(message, throwable)
|
||||
|
||||
/**
|
||||
* An exception when encoding resources.
|
||||
*
|
||||
* @param message The exception message.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class Encode(message: String, throwable: Throwable? = null) : ApkResourceException(message, throwable)
|
||||
|
||||
/**
|
||||
* An exception thrown when a reference could not be resolved.
|
||||
*
|
||||
* @param reference The invalid reference.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
class InvalidReference(reference: String, throwable: Throwable? = null) :
|
||||
ApkResourceException("Failed to resolve: $reference", throwable) {
|
||||
|
||||
/**
|
||||
* An exception thrown when a reference could not be resolved.
|
||||
*
|
||||
* @param type The type of the reference.
|
||||
* @param name The name of the reference.
|
||||
* @param throwable The corresponding [Throwable].
|
||||
*/
|
||||
constructor(type: String, name: String, throwable: Throwable? = null) : this("@$type/$name", throwable)
|
||||
}
|
||||
|
||||
/**
|
||||
* An exception thrown when the Apk file not have a resource table, but was expected to have one.
|
||||
*/
|
||||
class MissingResourceTable : ApkResourceException("Apk does not have a resource table.")
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package app.revanced.arsc.archive
|
||||
|
||||
import app.revanced.arsc.resource.ResourceContainer
|
||||
import com.reandroid.apk.ApkModule
|
||||
import com.reandroid.apk.DexFileInputSource
|
||||
import com.reandroid.archive.InputSource
|
||||
import java.io.File
|
||||
import java.io.Flushable
|
||||
|
||||
/**
|
||||
* A class for reading/writing files in an [ApkModule].
|
||||
*
|
||||
* @param module The [ApkModule] to operate on.
|
||||
*/
|
||||
class Archive(internal val module: ApkModule) : Flushable {
|
||||
val mainPackageResources = ResourceContainer(this, module.tableBlock)
|
||||
|
||||
fun save(output: File) {
|
||||
flush()
|
||||
module.writeApk(output)
|
||||
}
|
||||
fun readDexFiles(): MutableList<DexFileInputSource> = module.listDexFiles()
|
||||
fun write(inputSource: InputSource) = module.apkArchive.add(inputSource) // Overwrites existing files.
|
||||
fun read(name: String): InputSource? = module.apkArchive.getInputSource(name)
|
||||
override fun flush() = mainPackageResources.flush()
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package app.revanced.arsc.logging
|
||||
interface Logger {
|
||||
fun error(msg: String)
|
||||
fun warn(msg: String)
|
||||
fun info(msg: String)
|
||||
fun trace(msg: String)
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
package app.revanced.arsc.resource
|
||||
|
||||
import app.revanced.arsc.ApkResourceException
|
||||
import com.reandroid.arsc.coder.EncodeResult
|
||||
import com.reandroid.arsc.coder.ValueDecoder
|
||||
import com.reandroid.arsc.value.Entry
|
||||
import com.reandroid.arsc.value.ValueType
|
||||
import com.reandroid.arsc.value.array.ArrayBag
|
||||
import com.reandroid.arsc.value.array.ArrayBagItem
|
||||
import com.reandroid.arsc.value.plurals.PluralsBag
|
||||
import com.reandroid.arsc.value.plurals.PluralsBagItem
|
||||
import com.reandroid.arsc.value.plurals.PluralsQuantity
|
||||
import com.reandroid.arsc.value.style.StyleBag
|
||||
import com.reandroid.arsc.value.style.StyleBagItem
|
||||
|
||||
/**
|
||||
* A resource value.
|
||||
*/
|
||||
sealed class Resource {
|
||||
internal abstract fun write(entry: Entry, resources: ResourceContainer)
|
||||
}
|
||||
|
||||
internal val Resource.isComplex get() = when (this) {
|
||||
is Scalar -> false
|
||||
is Complex -> true
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple resource.
|
||||
*/
|
||||
open class Scalar internal constructor(private val valueType: ValueType, private val value: Int) : Resource() {
|
||||
protected open fun data(resources: ResourceContainer) = value
|
||||
|
||||
override fun write(entry: Entry, resources: ResourceContainer) {
|
||||
entry.setValueAsRaw(valueType, data(resources))
|
||||
}
|
||||
|
||||
internal open fun toArrayItem(resources: ResourceContainer) = ArrayBagItem.create(valueType, data(resources))
|
||||
internal open fun toStyleItem(resources: ResourceContainer) = StyleBagItem.create(valueType, data(resources))
|
||||
}
|
||||
|
||||
/**
|
||||
* A marker class for complex resources.
|
||||
*/
|
||||
sealed class Complex : Resource()
|
||||
|
||||
private fun encoded(encodeResult: EncodeResult?) = encodeResult?.let { Scalar(it.valueType, it.value) }
|
||||
?: throw ApkResourceException.Encode("Failed to encode value")
|
||||
|
||||
/**
|
||||
* Encode a color.
|
||||
*
|
||||
* @param hex The hex value of the color.
|
||||
* @return The encoded [Resource].
|
||||
*/
|
||||
fun color(hex: String) = encoded(ValueDecoder.encodeColor(hex))
|
||||
|
||||
/**
|
||||
* Encode a dimension or fraction.
|
||||
*
|
||||
* @param value The dimension value such as 24dp.
|
||||
* @return The encoded [Resource].
|
||||
*/
|
||||
fun dimension(value: String) = encoded(ValueDecoder.encodeDimensionOrFraction(value))
|
||||
|
||||
/**
|
||||
* Encode a boolean resource.
|
||||
*
|
||||
* @param value The boolean.
|
||||
* @return The encoded [Resource].
|
||||
*/
|
||||
fun boolean(value: Boolean) = Scalar(ValueType.INT_BOOLEAN, if (value) -Int.MAX_VALUE else 0)
|
||||
|
||||
/**
|
||||
* Encode a float.
|
||||
*
|
||||
* @param n The number to encode.
|
||||
* @return The encoded [Resource].
|
||||
*/
|
||||
fun float(n: Float) = Scalar(ValueType.FLOAT, n.toBits())
|
||||
|
||||
/**
|
||||
* Create an integer [Resource].
|
||||
*
|
||||
* @param n The number to encode.
|
||||
* @return The integer [Resource].
|
||||
*/
|
||||
fun integer(n: Int) = Scalar(ValueType.INT_DEC, n)
|
||||
|
||||
/**
|
||||
* Create a reference [Resource].
|
||||
*
|
||||
* @param resourceId The target resource.
|
||||
* @return The reference resource.
|
||||
*/
|
||||
fun reference(resourceId: Int) = Scalar(ValueType.REFERENCE, resourceId)
|
||||
|
||||
/**
|
||||
* Resolve and create a reference [Resource].
|
||||
*
|
||||
* @see reference
|
||||
* @param ref The reference string to resolve.
|
||||
* @param resourceTable The resource table to resolve the reference with.
|
||||
* @return The reference resource.
|
||||
*/
|
||||
fun reference(resourceTable: ResourceTable, ref: String) = reference(resourceTable.resolve(ref))
|
||||
|
||||
/**
|
||||
* An array [Resource].
|
||||
*
|
||||
* @param elements The elements of the array.
|
||||
*/
|
||||
class Array(private val elements: Collection<Scalar>) : Complex() {
|
||||
override fun write(entry: Entry, resources: ResourceContainer) {
|
||||
ArrayBag.create(entry).addAll(elements.map { it.toArrayItem(resources) })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A style resource.
|
||||
*
|
||||
* @param elements The attributes to override.
|
||||
* @param parent A reference to the parent style.
|
||||
*/
|
||||
class Style(private val elements: Map<String, Scalar>, private val parent: String? = null) : Complex() {
|
||||
override fun write(entry: Entry, resources: ResourceContainer) {
|
||||
val resTable = resources.resourceTable
|
||||
val style = StyleBag.create(entry)
|
||||
parent?.let {
|
||||
style.parentId = resTable.resolve(parent)
|
||||
}
|
||||
|
||||
style.putAll(
|
||||
elements.asIterable().associate {
|
||||
StyleBag.resolve(resTable.encodeMaterials, it.key) to it.value.toStyleItem(resources)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A quantity string [Resource].
|
||||
*
|
||||
* @param elements A map of the quantity to the corresponding string.
|
||||
*/
|
||||
class Plurals(private val elements: Map<String, String>) : Complex() {
|
||||
override fun write(entry: Entry, resources: ResourceContainer) {
|
||||
val plurals = PluralsBag.create(entry)
|
||||
|
||||
plurals.putAll(elements.asIterable().associate { (k, v) ->
|
||||
PluralsQuantity.value(k) to PluralsBagItem.string(resources.getOrCreateString(v))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A string [Resource].
|
||||
*
|
||||
* @param value The string value.
|
||||
*/
|
||||
class StringResource(val value: String) : Scalar(ValueType.STRING, 0) {
|
||||
private fun tableString(resources: ResourceContainer) = resources.getOrCreateString(value)
|
||||
|
||||
override fun data(resources: ResourceContainer) = tableString(resources).index
|
||||
override fun toArrayItem(resources: ResourceContainer) = ArrayBagItem.string(tableString(resources))
|
||||
override fun toStyleItem(resources: ResourceContainer) = StyleBagItem.string(tableString(resources))
|
||||
}
|
@@ -0,0 +1,167 @@
|
||||
package app.revanced.arsc.resource
|
||||
|
||||
import app.revanced.arsc.ApkResourceException
|
||||
import app.revanced.arsc.archive.Archive
|
||||
import com.reandroid.apk.xmlencoder.EncodeUtil
|
||||
import com.reandroid.arsc.chunk.TableBlock
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlDocument
|
||||
import com.reandroid.arsc.value.Entry
|
||||
import com.reandroid.arsc.value.ResConfig
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.Flushable
|
||||
|
||||
class ResourceContainer(private val archive: Archive, internal val tableBlock: TableBlock) : Flushable {
|
||||
private val packageBlock = tableBlock.pickOne() // Pick the main package block.
|
||||
internal lateinit var resourceTable: ResourceTable // TODO: Set this.
|
||||
|
||||
private val lockedResourceFileNames = mutableSetOf<String>()
|
||||
|
||||
private fun lock(resourceFile: ResourceFile) {
|
||||
if (resourceFile.name in lockedResourceFileNames) {
|
||||
throw ApkResourceException.Locked("Resource file ${resourceFile.name} is already locked.")
|
||||
}
|
||||
|
||||
lockedResourceFileNames.add(resourceFile.name)
|
||||
}
|
||||
|
||||
private fun unlock(resourceFile: ResourceFile) {
|
||||
lockedResourceFileNames.remove(resourceFile.name)
|
||||
}
|
||||
|
||||
|
||||
fun <T : ResourceFile> openResource(name: String): ResourceFileEditor<T> {
|
||||
val inputSource = archive.read(name)
|
||||
?: throw ApkResourceException.Read("Resource file $name not found.")
|
||||
|
||||
val resourceFile = when {
|
||||
ResXmlDocument.isResXmlBlock(inputSource.openStream()) -> {
|
||||
val xmlDocument = archive.module
|
||||
.loadResXmlDocument(inputSource)
|
||||
.decodeToXml(resourceTable.entryStore, packageBlock.id)
|
||||
|
||||
ResourceFile.XmlResourceFile(name, xmlDocument)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val bytes = inputSource.openStream().use { it.readAllBytes() }
|
||||
|
||||
ResourceFile.BinaryResourceFile(name, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ResourceFileEditor(resourceFile as T).also {
|
||||
lockedResourceFileNames.add(name)
|
||||
}
|
||||
} catch (e: ClassCastException) {
|
||||
throw ApkResourceException.Decode("Resource file $name is not ${resourceFile::class}.", e)
|
||||
}
|
||||
}
|
||||
|
||||
inner class ResourceFileEditor<T : ResourceFile> internal constructor(
|
||||
private val resourceFile: T,
|
||||
) : Closeable {
|
||||
fun use(block: (T) -> Unit) = block(resourceFile)
|
||||
override fun close() {
|
||||
lockedResourceFileNames.remove(resourceFile.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun flush() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a resource file, creating it if the file does not exist.
|
||||
*
|
||||
* @param path The resource file path.
|
||||
* @return The corresponding [ResourceFiles],
|
||||
*/
|
||||
fun openFile(path: String) = ResourceFiles(createHandle(path), archive)
|
||||
|
||||
private fun getPackageBlock() = packageBlock ?: throw ApkResourceException.MissingResourceTable
|
||||
|
||||
internal fun getOrCreateString(value: String) =
|
||||
tableBlock?.stringPool?.getOrCreate(value) ?: throw ApkResourceException.MissingResourceTable
|
||||
|
||||
private fun Entry.set(resource: Resource) {
|
||||
val existingEntryNameReference = specReference
|
||||
|
||||
// Sets this.specReference if the entry is not yet initialized.
|
||||
// Sets this.specReference to 0 if the resource type of the existing entry changes.
|
||||
ensureComplex(resource.isComplex)
|
||||
|
||||
if (existingEntryNameReference != 0) {
|
||||
// Preserve the entry name by restoring the previous spec block reference (if present).
|
||||
specReference = existingEntryNameReference
|
||||
}
|
||||
|
||||
resource.write(this, this@ResourceContainer)
|
||||
resourceTable.registerChanged(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an [Entry] from the resource table.
|
||||
*
|
||||
* @param type The resource type.
|
||||
* @param name The resource name.
|
||||
* @param qualifiers The variant to use.
|
||||
*/
|
||||
private fun getEntry(type: String, name: String, qualifiers: String?): Entry? {
|
||||
val resourceId = try {
|
||||
resourceTable.resolve("@$type/$name")
|
||||
} catch (_: ApkResourceException.InvalidReference) {
|
||||
return null
|
||||
}
|
||||
|
||||
val config = ResConfig.parse(qualifiers)
|
||||
return tableBlock?.resolveReference(resourceId)?.singleOrNull { it.resConfig == config }
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a [ResourceFiles.Handle] that can be used to open a [ResourceFiles].
|
||||
* This may involve looking it up in the resource table to find the actual location in the archive.
|
||||
*
|
||||
* @param path The path of the resource.
|
||||
*/
|
||||
private fun createHandle(path: String): ResourceFiles.Handle {
|
||||
if (path.startsWith("res/values")) throw ApkResourceException.Decode("Decoding the resource table as a file is not supported")
|
||||
|
||||
var onClose = {}
|
||||
var archivePath = path
|
||||
|
||||
if (tableBlock != null && path.startsWith("res/") && path.count { it == '/' } == 2) {
|
||||
val file = File(path)
|
||||
|
||||
val qualifiers = EncodeUtil.getQualifiersFromResFile(file)
|
||||
val type = EncodeUtil.getTypeNameFromResFile(file)
|
||||
val name = file.nameWithoutExtension
|
||||
|
||||
// The resource file names that the app developers used may have been minified, so we have to resolve it with the resource table.
|
||||
// Example: res/drawable-hdpi/icon.png -> res/4a.png
|
||||
getEntry(type, name, qualifiers)?.resValue?.valueAsString?.let {
|
||||
archivePath = it
|
||||
} ?: run {
|
||||
// An entry for this specific resource file was not found in the resource table, so we have to register it after we save.
|
||||
onClose = { setResource(type, name, StringResource(archivePath), qualifiers) }
|
||||
}
|
||||
}
|
||||
|
||||
return ResourceFiles.Handle(path, archivePath, onClose)
|
||||
}
|
||||
|
||||
fun setResource(type: String, entryName: String, resource: Resource, qualifiers: String? = null) =
|
||||
getPackageBlock().getOrCreate(qualifiers, type, entryName).also { it.set(resource) }.resourceId
|
||||
|
||||
fun setResources(type: String, resources: Map<String, Resource>, configuration: String? = null) {
|
||||
getPackageBlock().getOrCreateSpecTypePair(type).getOrCreateTypeBlock(configuration).apply {
|
||||
resources.forEach { (entryName, resource) -> getOrCreateEntry(entryName).set(resource) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun flush() {
|
||||
packageBlock?.name = archive
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
package app.revanced.arsc.resource
|
||||
|
||||
import app.revanced.arsc.ApkResourceException
|
||||
import app.revanced.arsc.archive.Archive
|
||||
import com.reandroid.archive.InputSource
|
||||
import com.reandroid.xml.XMLDocument
|
||||
import com.reandroid.xml.XMLException
|
||||
import java.io.*
|
||||
|
||||
|
||||
abstract class ResourceFile(val name: String) {
|
||||
internal var realName: String? = null
|
||||
|
||||
class XmlResourceFile(name: String, val document: XMLDocument) : ResourceFile(name)
|
||||
class BinaryResourceFile(name: String, var bytes: ByteArray) : ResourceFile(name)
|
||||
}
|
||||
|
||||
|
||||
class ResourceFiles private constructor(
|
||||
) : Closeable {
|
||||
|
||||
/**
|
||||
* Instantiate a [ResourceFiles].
|
||||
*
|
||||
* @param handle The [Handle] associated with this file.
|
||||
* @param archive The [Archive] that the file resides in.
|
||||
*/
|
||||
internal constructor(handle: Handle, archive: Archive) : this(
|
||||
handle,
|
||||
archive,
|
||||
try {
|
||||
archive.read(handle.archivePath)
|
||||
} catch (e: XMLException) {
|
||||
throw ApkResourceException.Decode("Failed to decode XML while reading ${handle.virtualPath}", e)
|
||||
} catch (e: IOException) {
|
||||
throw ApkResourceException.Decode("Could not read ${handle.virtualPath}", e)
|
||||
}
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_BUFFER_SIZE = 1024
|
||||
}
|
||||
|
||||
var contents = readResult?.data ?: ByteArray(0)
|
||||
set(value) {
|
||||
pendingWrite = true
|
||||
field = value
|
||||
}
|
||||
|
||||
val exists = readResult != null
|
||||
|
||||
override fun toString() = handle.virtualPath
|
||||
|
||||
override fun close() {
|
||||
if (pendingWrite) {
|
||||
val path = handle.archivePath
|
||||
|
||||
if (isXmlResource) archive.writeXml(
|
||||
path,
|
||||
try {
|
||||
XMLDocument.load(inputStream())
|
||||
} catch (e: XMLException) {
|
||||
throw ApkResourceException.Encode("Failed to parse XML while writing ${handle.virtualPath}", e)
|
||||
}
|
||||
|
||||
) else archive.writeRaw(path, contents)
|
||||
}
|
||||
|
||||
handle.onClose()
|
||||
|
||||
|
||||
archive.unlock(this)
|
||||
}
|
||||
|
||||
fun inputStream(): InputStream = ByteArrayInputStream(contents)
|
||||
|
||||
fun outputStream(bufferSize: Int = DEFAULT_BUFFER_SIZE): OutputStream =
|
||||
object : ByteArrayOutputStream(bufferSize) {
|
||||
override fun close() {
|
||||
this@ResourceFiles.contents = if (buf.size > count) buf.copyOf(count) else buf
|
||||
super.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param virtualPath The resource file path. Example: /res/drawable-hdpi/icon.png.
|
||||
* @param archivePath The actual file path in the archive. Example: res/4a.png.
|
||||
* @param onClose An action to perform when the file associated with this handle is closed
|
||||
*/
|
||||
internal data class Handle(val virtualPath: String, val archivePath: String, val onClose: () -> Unit)
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
package app.revanced.arsc.resource
|
||||
|
||||
import app.revanced.arsc.ApkResourceException
|
||||
import com.reandroid.apk.xmlencoder.EncodeException
|
||||
import com.reandroid.apk.xmlencoder.EncodeMaterials
|
||||
import com.reandroid.arsc.util.FrameworkTable
|
||||
import com.reandroid.arsc.value.Entry
|
||||
import com.reandroid.common.TableEntryStore
|
||||
|
||||
/**
|
||||
* A high-level API for resolving resources in the resource table, which spans the entire ApkBundle.
|
||||
*/
|
||||
class ResourceTable(base: ResourceContainer, all: Sequence<ResourceContainer>) {
|
||||
private val packageName = base.tableBlock!!.name
|
||||
|
||||
/**
|
||||
* A [TableEntryStore] used to decode XML.
|
||||
*/
|
||||
internal val entryStore = TableEntryStore()
|
||||
|
||||
/**
|
||||
* The [EncodeMaterials] to use for resolving resources and encoding XML.
|
||||
*/
|
||||
internal val encodeMaterials: EncodeMaterials = object : EncodeMaterials() {
|
||||
/*
|
||||
Our implementation is more efficient because it does not have to loop through every single entry group
|
||||
when the resource id cannot be found in the TableIdentifier, which does not update when you create a new resource.
|
||||
It also looks at the entire table instead of just the current package.
|
||||
*/
|
||||
override fun resolveLocalResourceId(type: String, name: String) = resolveLocal(type, name)
|
||||
}
|
||||
|
||||
/**
|
||||
* The resource mappings which are generated when the ApkBundle is created.
|
||||
*/
|
||||
private val tableIdentifier = encodeMaterials.tableIdentifier
|
||||
|
||||
/**
|
||||
* A table of all the resources that have been changed or added.
|
||||
*/
|
||||
private val modifiedResources = HashMap<String, HashMap<String, Int>>()
|
||||
|
||||
|
||||
/**
|
||||
* Resolve a resource id for the specified resource.
|
||||
* Cannot resolve resources from the android framework.
|
||||
*
|
||||
* @param type The type of the resource.
|
||||
* @param name The name of the resource.
|
||||
* @return The id of the resource.
|
||||
*/
|
||||
fun resolveLocal(type: String, name: String) =
|
||||
modifiedResources[type]?.get(name)
|
||||
?: tableIdentifier.get(packageName, type, name)?.resourceId
|
||||
?: throw ApkResourceException.InvalidReference(
|
||||
type,
|
||||
name
|
||||
)
|
||||
|
||||
/**
|
||||
* Resolve a resource id for the specified resource.
|
||||
*
|
||||
* @param reference The resource reference string.
|
||||
* @return The id of the resource.
|
||||
*/
|
||||
fun resolve(reference: String) = try {
|
||||
encodeMaterials.resolveReference(reference)
|
||||
} catch (e: EncodeException) {
|
||||
throw ApkResourceException.InvalidReference(reference, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the [ResourceTable] that an [Entry] has been created or modified.
|
||||
*/
|
||||
internal fun registerChanged(entry: Entry) {
|
||||
modifiedResources.getOrPut(entry.typeName, ::HashMap)[entry.name] = entry.resourceId
|
||||
}
|
||||
|
||||
init {
|
||||
all.forEach {
|
||||
it.tableBlock?.let { table ->
|
||||
entryStore.add(table)
|
||||
tableIdentifier.load(table)
|
||||
}
|
||||
|
||||
it.resourceTable = this
|
||||
}
|
||||
|
||||
base.also {
|
||||
encodeMaterials.currentPackage = it.tableBlock
|
||||
|
||||
it.tableBlock!!.frameWorks.forEach { fw ->
|
||||
if (fw is FrameworkTable) {
|
||||
entryStore.add(fw)
|
||||
encodeMaterials.addFramework(fw)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package app.revanced.arsc.xml
|
||||
|
||||
import app.revanced.arsc.resource.ResourceContainer
|
||||
import app.revanced.arsc.resource.boolean
|
||||
import com.reandroid.apk.xmlencoder.EncodeException
|
||||
import com.reandroid.apk.xmlencoder.XMLEncodeSource
|
||||
import com.reandroid.arsc.chunk.xml.ResXmlDocument
|
||||
import com.reandroid.xml.XMLDocument
|
||||
import com.reandroid.xml.XMLElement
|
||||
import com.reandroid.xml.source.XMLDocumentSource
|
||||
|
||||
/**
|
||||
* Archive input source to lazily encode an [XMLDocument] after it has been modified.
|
||||
*
|
||||
* @param name The file name of this input source.
|
||||
* @param document The [XMLDocument] to encode.
|
||||
* @param resources The [ResourceContainer] to use for encoding.
|
||||
*/
|
||||
internal class LazyXMLEncodeSource(
|
||||
name: String,
|
||||
val document: XMLDocument,
|
||||
private val resources: ResourceContainer
|
||||
) : XMLEncodeSource(resources.resourceTable.encodeMaterials, XMLDocumentSource(name, document)) {
|
||||
private var encoded = false
|
||||
|
||||
override fun getResXmlBlock(): ResXmlDocument {
|
||||
if (encoded) return super.getResXmlBlock()
|
||||
|
||||
XMLEncodeSource(resources.resourceTable.encodeMaterials, XMLDocumentSource(name, document))
|
||||
|
||||
fun XMLElement.registerIds() {
|
||||
listAttributes().forEach { attr ->
|
||||
if (!attr.value.startsWith("@+id/")) return@forEach
|
||||
|
||||
val name = attr.value.split('/').last()
|
||||
resources.setResource("id", name, boolean(false))
|
||||
attr.value = "@id/$name"
|
||||
}
|
||||
|
||||
listChildElements().forEach { it.registerIds() }
|
||||
}
|
||||
|
||||
// Handle all @+id/id_name references in the document.
|
||||
document.documentElement.registerIds()
|
||||
|
||||
encoded = true
|
||||
|
||||
// This will call XMLEncodeSource.getResXmlBlock(),
|
||||
// which will encode the document if it has not already been encoded.
|
||||
try {
|
||||
return super.getResXmlBlock()
|
||||
} catch (e: EncodeException) {
|
||||
throw EncodeException("Failed to encode $name", e)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,68 +1,3 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "1.7.0"
|
||||
java
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "app.revanced"
|
||||
|
||||
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
|
||||
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri("https://maven.pkg.github.com/revanced/multidexlib2")
|
||||
credentials {
|
||||
username = githubUsername
|
||||
password = githubPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("xpp3:xpp3:1.1.4c")
|
||||
implementation("org.smali:smali:2.5.2")
|
||||
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
||||
implementation("org.apktool:apktool-lib:2.8.1-SNAPSHOT")
|
||||
|
||||
implementation(kotlin("reflect"))
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("PASSED", "SKIPPED", "FAILED")
|
||||
}
|
||||
}
|
||||
processResources {
|
||||
expand("projectVersion" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
if (System.getenv("GITHUB_ACTOR") != null)
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
else
|
||||
mavenLocal()
|
||||
}
|
||||
publications {
|
||||
register<MavenPublication>("gpr") {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
kotlin("jvm") version "1.8.20" apply false
|
||||
}
|
||||
|
@@ -1,2 +1,4 @@
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
kotlin.code.style = official
|
||||
version = 5.1.1
|
||||
version = 11.0.4
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
40
gradlew
vendored
40
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -32,10 +32,10 @@
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -80,13 +80,10 @@ do
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# 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"'
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -133,22 +130,29 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
@@ -205,6 +213,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
15
gradlew.bat
vendored
15
gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,8 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user