mirror of
https://github.com/revanced/revanced-patcher.git
synced 2025-04-29 21:04:26 +02:00
chore: Merge branch dev
to main
(#304)
This commit is contained in:
commit
b2aecb726d
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@ -10,6 +10,9 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@ -46,5 +49,5 @@ jobs:
|
||||
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npm exec semantic-release
|
||||
|
@ -23,7 +23,8 @@
|
||||
"assets": [
|
||||
"CHANGELOG.md",
|
||||
"gradle.properties"
|
||||
]
|
||||
],
|
||||
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
],
|
||||
[
|
||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -1,3 +1,33 @@
|
||||
## [20.0.1-dev.5](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.4...v20.0.1-dev.5) (2024-10-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use non-nullable type for options ([ea6fc70](https://github.com/ReVanced/revanced-patcher/commit/ea6fc70caab055251ad4d0d3f1b5cf53865abb85))
|
||||
|
||||
## [20.0.1-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.3...v20.0.1-dev.4) (2024-10-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make it work on Android by not using APIs from JVM unavailable to Android. ([2be6e97](https://github.com/ReVanced/revanced-patcher/commit/2be6e97817437f40e17893dfff3bea2cd4c3ff9e))
|
||||
|
||||
## [20.0.1-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.2...v20.0.1-dev.3) (2024-10-03)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Free memory earlier and remove negligible lookup maps ([d53aacd](https://github.com/ReVanced/revanced-patcher/commit/d53aacdad4ed3750ddae526fb307577ea36e6171))
|
||||
|
||||
## [20.0.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v20.0.1-dev.1...v20.0.1-dev.2) (2024-10-01)
|
||||
|
||||
## [20.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v20.0.0...v20.0.1-dev.1) (2024-09-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Check for class type exactly instead of with contains ([#310](https://github.com/ReVanced/revanced-patcher/issues/310)) ([69f2f20](https://github.com/ReVanced/revanced-patcher/commit/69f2f20fd99162f91cd9c531dfe47d00d3152ead))
|
||||
|
||||
# [20.0.0](https://github.com/ReVanced/revanced-patcher/compare/v19.3.1...v20.0.0) (2024-08-06)
|
||||
|
||||
|
||||
|
@ -108,7 +108,7 @@ val rawResourcePatch = rawResourcePatch {
|
||||
}
|
||||
|
||||
@Surpress("unused")
|
||||
val resourcePatch = rawResourcePatch {
|
||||
val resourcePatch = resourcePatch {
|
||||
execute {
|
||||
// TODO
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
version = 20.0.0
|
||||
version = 20.0.1-dev.5
|
||||
|
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,6 +1,8 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dist
|
||||
zipStorePath=wrapper/dists
|
||||
|
22
gradlew
vendored
22
gradlew
vendored
@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@ -83,7 +85,9 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@ -144,7 +148,7 @@ 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
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@ -201,11 +205,11 @@ 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
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
2972
package-lock.json
generated
2972
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.9.1",
|
||||
"semantic-release": "^23.0.2"
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"semantic-release": "^24.1.2"
|
||||
}
|
||||
}
|
||||
|
@ -66,36 +66,15 @@ class Fingerprint internal constructor(
|
||||
}
|
||||
|
||||
// TODO: If only one string is necessary, why not use a single string for every fingerprint?
|
||||
fun Fingerprint.lookupByStrings() = strings?.firstNotNullOfOrNull { lookupMaps.methodsByStrings[it] }
|
||||
if (lookupByStrings()?.let(::match) == true) {
|
||||
if (strings?.firstNotNullOfOrNull { lookupMaps.methodsByStrings[it] }?.let(::match) == true) {
|
||||
return true
|
||||
}
|
||||
|
||||
// No strings declared or none matched (partial matches are allowed).
|
||||
// Use signature matching.
|
||||
fun Fingerprint.lookupBySignature(): MethodClassPairs {
|
||||
if (accessFlags == null) return lookupMaps.allMethods
|
||||
|
||||
var returnTypeValue = returnType
|
||||
if (returnTypeValue == null) {
|
||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
// Constructors always have void return type.
|
||||
returnTypeValue = "V"
|
||||
} else {
|
||||
return lookupMaps.allMethods
|
||||
}
|
||||
}
|
||||
|
||||
val signature =
|
||||
buildString {
|
||||
append(accessFlags)
|
||||
append(returnTypeValue.first())
|
||||
appendParameters(parameters ?: return@buildString)
|
||||
}
|
||||
|
||||
return lookupMaps.methodsBySignature[signature] ?: return MethodClassPairs()
|
||||
context.classes.forEach { classDef ->
|
||||
if (match(context, classDef)) return true
|
||||
}
|
||||
return match(lookupBySignature())
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +107,7 @@ class Fingerprint internal constructor(
|
||||
fun match(
|
||||
context: BytecodePatchContext,
|
||||
method: Method,
|
||||
) = match(context, method, context.classByType(method.definingClass)!!.immutableClass)
|
||||
) = match(context, method, context.classBy { method.definingClass == it.type }!!.immutableClass)
|
||||
|
||||
/**
|
||||
* Match using a [Method].
|
||||
|
@ -98,14 +98,12 @@ class Patcher(private val config: PatcherConfig) : Closeable {
|
||||
|
||||
logger.info("Merging extensions")
|
||||
|
||||
context.executablePatches.forEachRecursively { patch ->
|
||||
if (patch is BytecodePatch && patch.extension != null) {
|
||||
context.bytecodeContext.merge(patch.extension)
|
||||
}
|
||||
}
|
||||
with(context.bytecodeContext) {
|
||||
context.executablePatches.mergeExtensions()
|
||||
|
||||
// Initialize lookup maps.
|
||||
context.bytecodeContext.lookupMaps
|
||||
// Initialize lookup maps.
|
||||
lookupMaps
|
||||
}
|
||||
|
||||
logger.info("Executing patches")
|
||||
|
||||
|
@ -20,6 +20,7 @@ class PatcherConfig(
|
||||
private val temporaryFilesPath: File = File("revanced-temporary-files"),
|
||||
aaptBinaryPath: String? = null,
|
||||
frameworkFileDirectory: String? = null,
|
||||
@Deprecated("This is going to be removed in the future because it is not needed anymore.")
|
||||
internal val multithreadingDexFileWriter: Boolean = false,
|
||||
) {
|
||||
private val logger = Logger.getLogger(PatcherConfig::class.java.name)
|
||||
|
@ -21,7 +21,6 @@ import lanchon.multidexlib2.MultiDexIO
|
||||
import lanchon.multidexlib2.RawDexIO
|
||||
import java.io.Closeable
|
||||
import java.io.FileFilter
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import java.util.logging.Logger
|
||||
|
||||
@ -60,40 +59,41 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
internal val lookupMaps by lazy { LookupMaps(classes) }
|
||||
|
||||
/**
|
||||
* A map for lookup by [merge].
|
||||
* Merge the extensions for this set of patches.
|
||||
*/
|
||||
internal val classesByType = mutableMapOf<String, ClassDef>().apply {
|
||||
classes.forEach { classDef -> put(classDef.type, classDef) }
|
||||
}
|
||||
internal fun Set<Patch<*>>.mergeExtensions() {
|
||||
// Lookup map for fast checking if a class exists by its type.
|
||||
val classesByType = mutableMapOf<String, ClassDef>().apply {
|
||||
classes.forEach { classDef -> put(classDef.type, classDef) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge an extension to [classes].
|
||||
*
|
||||
* @param extensionInputStream The input stream of the extension to merge.
|
||||
*/
|
||||
internal fun merge(extensionInputStream: InputStream) {
|
||||
val extension = extensionInputStream.readAllBytes()
|
||||
forEachRecursively { patch ->
|
||||
if (patch is BytecodePatch && patch.extension != null) {
|
||||
|
||||
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
||||
val existingClass = classesByType[classDef.type] ?: run {
|
||||
logger.fine("Adding class \"$classDef\"")
|
||||
val extension = patch.extension.readAllBytes()
|
||||
|
||||
classes += classDef
|
||||
classesByType[classDef.type] = classDef
|
||||
RawDexIO.readRawDexFile(extension, 0, null).classes.forEach { classDef ->
|
||||
val existingClass = classesByType[classDef.type] ?: run {
|
||||
logger.fine("Adding class \"$classDef\"")
|
||||
|
||||
return@forEach
|
||||
}
|
||||
classes += classDef
|
||||
classesByType[classDef.type] = classDef
|
||||
|
||||
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")
|
||||
return@forEach
|
||||
}
|
||||
|
||||
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
|
||||
// If the class was merged, replace the original class with the merged class.
|
||||
if (mergedClass === existingClass) {
|
||||
return@let
|
||||
logger.fine("Class \"$classDef\" exists already. Adding missing methods and fields.")
|
||||
|
||||
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
|
||||
// If the class was merged, replace the original class with the merged class.
|
||||
if (mergedClass === existingClass) {
|
||||
return@let
|
||||
}
|
||||
|
||||
classes -= existingClass
|
||||
classes += mergedClass
|
||||
}
|
||||
}
|
||||
|
||||
classes -= existingClass
|
||||
classes += mergedClass
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,6 +104,7 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
* @param type The type of the class.
|
||||
* @return A proxy for the first class that matches the type.
|
||||
*/
|
||||
@Deprecated("Use classBy { type in it.type } instead.", ReplaceWith("classBy { type in it.type }"))
|
||||
fun classByType(type: String) = classBy { type in it.type }
|
||||
|
||||
/**
|
||||
@ -144,6 +145,9 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
override fun get(): Set<PatcherResult.PatchedDexFile> {
|
||||
logger.info("Compiling patched dex files")
|
||||
|
||||
// Free up memory before compiling the dex files.
|
||||
lookupMaps.close()
|
||||
|
||||
val patchedDexFileResults =
|
||||
config.patchedFiles.resolve("dex").also {
|
||||
it.deleteRecursively() // Make sure the directory is empty.
|
||||
@ -177,21 +181,6 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
* @param classes The list of classes to create the lookup maps from.
|
||||
*/
|
||||
internal class LookupMaps internal constructor(classes: List<ClassDef>) : Closeable {
|
||||
/**
|
||||
* Classes associated by their type.
|
||||
*/
|
||||
internal val classesByType = classes.associateBy { it.type }.toMutableMap()
|
||||
|
||||
/**
|
||||
* All methods and the class they are a member of.
|
||||
*/
|
||||
internal val allMethods = MethodClassPairs()
|
||||
|
||||
/**
|
||||
* Methods associated by its access flags, return type and parameter.
|
||||
*/
|
||||
internal val methodsBySignature = MethodClassPairsLookupMap()
|
||||
|
||||
/**
|
||||
* Methods associated by strings referenced in it.
|
||||
*/
|
||||
@ -202,22 +191,6 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
classDef.methods.forEach { method ->
|
||||
val methodClassPair: MethodClassPair = method to classDef
|
||||
|
||||
// For fingerprints with no access or return type specified.
|
||||
allMethods += methodClassPair
|
||||
|
||||
val accessFlagsReturnKey = method.accessFlags.toString() + method.returnType.first()
|
||||
|
||||
// Add <access><returnType> as the key.
|
||||
methodsBySignature[accessFlagsReturnKey] = methodClassPair
|
||||
|
||||
// Add <access><returnType>[parameters] as the key.
|
||||
methodsBySignature[
|
||||
buildString {
|
||||
append(accessFlagsReturnKey)
|
||||
appendParameters(method.parameterTypes)
|
||||
},
|
||||
] = methodClassPair
|
||||
|
||||
// Add strings contained in the method as the key.
|
||||
method.instructionsOrNull?.forEach instructions@{ instruction ->
|
||||
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO) {
|
||||
@ -258,15 +231,12 @@ class BytecodePatchContext internal constructor(private val config: PatcherConfi
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
allMethods.clear()
|
||||
methodsBySignature.clear()
|
||||
methodsByStrings.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
lookupMaps.close()
|
||||
classesByType.clear()
|
||||
classes.clear()
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ fun intOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Int?>.(Int?) -> Boolean = { true },
|
||||
validator: Option<Int>.(Int?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -264,7 +264,7 @@ fun PatchBuilder<*>.intOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Int?>.(Int?) -> Boolean = { true },
|
||||
validator: Option<Int>.(Int?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -297,7 +297,7 @@ fun booleanOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Boolean?>.(Boolean?) -> Boolean = { true },
|
||||
validator: Option<Boolean>.(Boolean?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -330,7 +330,7 @@ fun PatchBuilder<*>.booleanOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Boolean?>.(Boolean?) -> Boolean = { true },
|
||||
validator: Option<Boolean>.(Boolean?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -363,7 +363,7 @@ fun floatOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Float?>.(Float?) -> Boolean = { true },
|
||||
validator: Option<Float>.(Float?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -396,7 +396,7 @@ fun PatchBuilder<*>.floatOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Float?>.(Float?) -> Boolean = { true },
|
||||
validator: Option<Float>.(Float?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -429,7 +429,7 @@ fun longOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Long?>.(Long?) -> Boolean = { true },
|
||||
validator: Option<Long>.(Long?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
@ -462,7 +462,7 @@ fun PatchBuilder<*>.longOption(
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: Option<Long?>.(Long?) -> Boolean = { true },
|
||||
validator: Option<Long>.(Long?) -> Boolean = { true },
|
||||
) = option(
|
||||
key,
|
||||
default,
|
||||
|
@ -10,6 +10,9 @@ import lanchon.multidexlib2.BasicDexFileNamer
|
||||
import lanchon.multidexlib2.MultiDexIO
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import java.net.URLClassLoader
|
||||
import java.util.jar.JarFile
|
||||
import kotlin.reflect.KProperty
|
||||
@ -636,7 +639,7 @@ sealed class PatchLoader private constructor(
|
||||
*/
|
||||
private val Class<*>.patchFields
|
||||
get() = fields.filter { field ->
|
||||
field.type.isPatch && field.canAccess(null)
|
||||
field.type.isPatch && field.canAccess()
|
||||
}.map { field ->
|
||||
field.get(null) as Patch<*>
|
||||
}
|
||||
@ -646,7 +649,7 @@ sealed class PatchLoader private constructor(
|
||||
*/
|
||||
private val Class<*>.patchMethods
|
||||
get() = methods.filter { method ->
|
||||
method.returnType.isPatch && method.parameterCount == 0 && method.canAccess(null)
|
||||
method.returnType.isPatch && method.parameterCount == 0 && method.canAccess()
|
||||
}.map { method ->
|
||||
method.invoke(null) as Patch<*>
|
||||
}
|
||||
@ -670,6 +673,12 @@ sealed class PatchLoader private constructor(
|
||||
it.name != null
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
private fun Member.canAccess(): Boolean {
|
||||
if (this is Method && parameterCount != 0) return false
|
||||
|
||||
return Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,9 @@ internal object ClassMerger {
|
||||
callback: MutableClass.() -> Unit,
|
||||
) {
|
||||
callback(targetClass)
|
||||
this.classByType(targetClass.superclass ?: return)?.mutableClass?.let {
|
||||
|
||||
targetClass.superclass ?: return
|
||||
this.classBy { targetClass.superclass == it.type }?.mutableClass?.let {
|
||||
traverseClassHierarchy(it, callback)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ import app.revanced.patcher.util.ProxyClassList
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableClassDef
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
@ -193,6 +195,7 @@ internal object PatcherTest {
|
||||
private operator fun Set<Patch<*>>.invoke(): List<PatchResult> {
|
||||
every { patcher.context.executablePatches } returns toMutableSet()
|
||||
every { patcher.context.bytecodeContext.lookupMaps } returns LookupMaps(patcher.context.bytecodeContext.classes)
|
||||
every { with(patcher.context.bytecodeContext) { any<Set<Patch<*>>>().mergeExtensions() } } just runs
|
||||
|
||||
return runBlocking { patcher().toList() }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user