Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Merge branch dev to main #326

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# [21.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v21.0.0...v21.1.0-dev.1) (2024-12-07)


### Features

* Add identity hash code to unnamed patches ([88a3252](https://github.com/ReVanced/revanced-patcher/commit/88a325257494939a79fb30dd51d60c5c52546755))

# [21.0.0](https://github.com/ReVanced/revanced-patcher/compare/v20.0.2...v21.0.0) (2024-11-05)


Expand Down
2 changes: 2 additions & 0 deletions api/revanced-patcher.api
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public final class app/revanced/patcher/Patcher : java/io/Closeable {
}

public final class app/revanced/patcher/PatcherConfig {
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/io/File;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}
Expand Down
36 changes: 18 additions & 18 deletions docs/2_2_patch_anatomy.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ package app.revanced.patches.ads
val disableAdsPatch = bytecodePatch(
name = "Disable ads",
description = "Disable ads in the app.",
) {
) {
compatibleWith("com.some.app"("1.0.0"))

// Patches can depend on other patches, executing them first.
dependsOn(disableAdsResourcePatch)

// Merge precompiled DEX files into the patched app, before the patch is executed.
extendWith("disable-ads.rve")

// Business logic of the patch to disable ads in the app.
execute {
// Fingerprint to find the method to patch.
val showAdsMatch by showAdsFingerprint {
// More about fingerprints on the next page of the documentation.
// More about fingerprints on the next page of the documentation.
}

// In the method that shows ads,
// call DisableAdsPatch.shouldDisableAds() from the extension (precompiled DEX file)
// to enable or disable ads.
Expand Down Expand Up @@ -122,11 +122,11 @@ To define an option, use the available `option` functions:
```kt
val patch = bytecodePatch(name = "Patch") {
// Add an inbuilt option and delegate it to a property.
val value by stringOption(key = "option")
val value by stringOption(name = "Inbuilt option")

// Add an option with a custom type and delegate it to a property.
val string by option<String>(key = "string")
val string by option<String>(name = "String option")

execute {
println(value)
println(string)
Expand All @@ -139,7 +139,7 @@ Options of a patch can be set after loading the patches with `PatchLoader` by ob
```kt
loadPatchesJar(patches).apply {
// Type is checked at runtime.
first { it.name == "Patch" }.options["option"] = "Value"
first { it.name == "Patch" }.options["Option"] = "Value"
}
```

Expand All @@ -152,7 +152,7 @@ option.type // The KType of the option. Captures the full type information of th
Options can be declared outside a patch and added to a patch manually:

```kt
val option = stringOption(key = "option")
val option = stringOption(name = "Option")

bytecodePatch(name = "Patch") {
val value by option()
Expand Down Expand Up @@ -183,18 +183,18 @@ and use it in a patch:
```kt
val patch = bytecodePatch(name = "Complex patch") {
extendWith("complex-patch.rve")
execute {

execute {
fingerprint.match!!.mutableMethod.addInstructions(0, "invoke-static { }, LComplexPatch;->doSomething()V")
}
}
```

ReVanced Patcher merges the classes from the extension into `context.classes` before executing the patch.
ReVanced Patcher merges the classes from the extension into `context.classes` before executing the patch.
When the patch is executed, it can reference the classes and methods from the extension.

> [!NOTE]
>
>
> The [ReVanced Patches template](https://github.com/ReVanced/revanced-patches-template) repository
> is a template project to create patches and extensions.

Expand All @@ -211,9 +211,9 @@ A simple real-world example would be a patch that opens a resource file of the a
Other patches that depend on this patch can write to the file, and the finalization block can close the file.

```kt
val patch = bytecodePatch(name = "Patch") {
val patch = bytecodePatch(name = "Patch") {
dependsOn(
bytecodePatch(name = "Dependency") {
bytecodePatch(name = "Dependency") {
execute {
print("1")
}
Expand Down Expand Up @@ -249,10 +249,10 @@ The same order is followed for multiple patches depending on the patch.
- A patch can declare compatibility with specific packages and versions,
but patches can still be executed on any package or version.
It is recommended that compatibility is specified to present known compatible packages and versions.
- If `compatibleWith` is not used, the patch is treated as compatible with any package
- If `compatibleWith` is not used, the patch is treated as compatible with any package
- If a package is specified with no versions, the patch is compatible with any version of the package
- If an empty array of versions is specified, the patch is not compatible with any version of the package.
This is useful for declaring incompatibility with a specific package.
This is useful for declaring incompatibility with a specific package.
- A patch can raise a `PatchException` at any time of execution to indicate that the patch failed to execute.

## ⏭️ What's next
Expand Down
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
org.gradle.parallel = true
org.gradle.caching = true
version = 21.0.0
org.gradle.parallel=true
org.gradle.caching=true
version=21.1.0-dev.1
6 changes: 3 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[versions]
android = "4.1.1.4"
apktool-lib = "2.9.3"
apktool-lib = "2.10.1.1"
binary-compatibility-validator = "0.15.1"
kotlin = "2.0.0"
kotlin = "2.0.20"
kotlinx-coroutines-core = "1.8.1"
mockk = "1.13.10"
multidexlib2 = "3.0.3.r3"
# Tracking https://github.com/google/smali/issues/64.
#noinspection GradleDependency
smali = "3.0.5"
smali = "3.0.8"
xpp3 = "1.1.4c"

[libraries]
Expand Down
24 changes: 21 additions & 3 deletions src/main/kotlin/app/revanced/patcher/PatcherConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,28 @@ import java.util.logging.Logger
class PatcherConfig(
internal val apkFile: File,
private val temporaryFilesPath: File = File("revanced-temporary-files"),
aaptBinaryPath: String? = null,
aaptBinaryPath: File? = null,
frameworkFileDirectory: String? = null,
) {
/**
* The configuration for the patcher.
*
* @param apkFile The apk file to patch.
* @param temporaryFilesPath A path to a folder to store temporary files in.
* @param aaptBinaryPath A path to a custom aapt binary.
* @param frameworkFileDirectory A path to the directory to cache the framework file in.
*/
@Deprecated(
"Use the constructor with a File for aaptBinaryPath instead.",
ReplaceWith("PatcherConfig(apkFile, temporaryFilesPath, aaptBinaryPath?.let { File(it) }, frameworkFileDirectory)"),
)
constructor(
apkFile: File,
temporaryFilesPath: File = File("revanced-temporary-files"),
aaptBinaryPath: String? = null,
frameworkFileDirectory: String? = null,
) : this(apkFile, temporaryFilesPath, aaptBinaryPath?.let { File(it) }, frameworkFileDirectory)

private val logger = Logger.getLogger(PatcherConfig::class.java.name)

/**
Expand All @@ -33,8 +52,7 @@ class PatcherConfig(
*/
internal val resourceConfig =
Config.getDefaultConfig().apply {
useAapt2 = true
aaptPath = aaptBinaryPath ?: ""
aaptBinary = aaptBinaryPath
frameworkDirectory = frameworkFileDirectory
}

Expand Down
43 changes: 39 additions & 4 deletions src/main/kotlin/app/revanced/patcher/patch/Option.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,51 @@ import kotlin.reflect.typeOf
* @constructor Create a new [Option].
*/
@Suppress("MemberVisibilityCanBePrivate", "unused")
class Option<T> @PublishedApi internal constructor(
class Option<T>
@PublishedApi
@Deprecated("Use the constructor with the name instead of a key instead.")
internal constructor(
@Deprecated("Use the name property instead.")
val key: String,
val default: T? = null,
val values: Map<String, T?>? = null,
@Deprecated("Use the name property instead.")
val title: String? = null,
val description: String? = null,
val required: Boolean = false,
val type: KType,
val validator: Option<T>.(T?) -> Boolean = { true },
) {
/**
* The name.
*/
val name = key

/**
* An option.
*
* @param T The value type of the option.
* @param name The name.
* @param default The default value.
* @param values Eligible option values mapped to a human-readable name.
* @param description A description.
* @param required Whether the option is required.
* @param type The type of the option value (to handle type erasure).
* @param validator The function to validate the option value.
*
* @constructor Create a new [Option].
*/
@PublishedApi
internal constructor(
name: String,
default: T? = null,
values: Map<String, T?>? = null,
description: String? = null,
required: Boolean = false,
type: KType,
validator: Option<T>.(T?) -> Boolean = { true },
) : this(name, default, values, name, description, required, type, validator)

/**
* The value of the [Option].
*/
Expand Down Expand Up @@ -109,7 +144,7 @@ class Option<T> @PublishedApi internal constructor(
class Options internal constructor(
private val options: Map<String, Option<*>>,
) : Map<String, Option<*>> by options {
internal constructor(options: Set<Option<*>>) : this(options.associateBy { it.key })
internal constructor(options: Set<Option<*>>) : this(options.associateBy { it.name })

/**
* Set an option's value.
Expand Down Expand Up @@ -856,14 +891,14 @@ sealed class OptionException(errorMessage: String) : Exception(errorMessage, nul
*
* @param value The value that failed validation.
*/
class ValueValidationException(value: Any?, option: Option<*>) : OptionException("The option value \"$value\" failed validation for ${option.key}")
class ValueValidationException(value: Any?, option: Option<*>) : OptionException("The option value \"$value\" failed validation for ${option.name}")

/**
* An exception thrown when a value is required but null was passed.
*
* @param option The [Option] that requires a value.
*/
class ValueRequiredException(option: Option<*>) : OptionException("The option ${option.key} requires a value, but the value was null")
class ValueRequiredException(option: Option<*>) : OptionException("The option ${option.name} requires a value, but the value was null")

/**
* An exception thrown when a [Option] is not found.
Expand Down
9 changes: 5 additions & 4 deletions src/main/kotlin/app/revanced/patcher/patch/Patch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ sealed class Patch<C : PatchContext<*>>(
finalizeBlock?.invoke(context)
}

override fun toString() = name ?: "Patch"
override fun toString() = name ?:
"Patch@${System.identityHashCode(this)}"
}

internal fun Patch<*>.anyRecursively(
Expand Down Expand Up @@ -161,7 +162,7 @@ class BytecodePatch internal constructor(

override fun finalize(context: PatcherContext) = finalize(context.bytecodeContext)

override fun toString() = name ?: "BytecodePatch"
override fun toString() = name ?: "Bytecode${super.toString()}"
}

/**
Expand Down Expand Up @@ -204,7 +205,7 @@ class RawResourcePatch internal constructor(

override fun finalize(context: PatcherContext) = finalize(context.resourceContext)

override fun toString() = name ?: "RawResourcePatch"
override fun toString() = name ?: "RawResource${super.toString()}"
}

/**
Expand Down Expand Up @@ -247,7 +248,7 @@ class ResourcePatch internal constructor(

override fun finalize(context: PatcherContext) = finalize(context.resourceContext)

override fun toString() = name ?: "ResourcePatch"
override fun toString() = name ?: "Resource${super.toString()}"
}

/**
Expand Down
Loading
Loading