### Example Patch File Structure Source: https://github.com/revanced/revanced-patcher/blob/main/docs/4_structure_and_conventions.md Illustrates the organization of patch files within a project package. Matching logic can be separated into its own file for better organization. ```text 📦your.org.patches.app.package ├ 🔍SomePatchMatching.kt └ 🧩SomePatch.kt ``` -------------------------------- ### Creating Bytecode Patch Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_patches_intro.md Example of how to define a BytecodePatch. This patch type focuses on modifying Dalvik VM bytecode. ```kotlin @Surpress("unused") val bytecodePatch = bytecodePatch(name = "Bytecode patch") { apply { // More about this on the next page of the documentation. } } ``` -------------------------------- ### Example Patch to Disable Ads Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Demonstrates how to create a patch to disable ads in an application. It shows how to define patch metadata, specify compatibility, declare dependencies on other patches or extensions, and apply bytecode modifications to a specific method. ```kotlin package app.revanced.patches.com.some.app 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, applying them first. dependsOn(disableAdsResourcePatch) // Merge precompiled DEX files into the patched app, before the patch is applied. extendWith("disable-ads.rve") // Business logic of the patch to disable ads in the app. apply { // Find the method to patch. val showAdsMethod = firstMethod { // More about this on the next page of the documentation. } // DisableAdsPatch.shouldDisableAds() is available from the `disable-ads.rve` extension (precompiled DEX file). showAdsMethod.addInstructions( 0, """ invoke-static {}, LDisableAdsPatch;->shouldDisableAds()Z move-result v0 return v0 """ ) } } ``` -------------------------------- ### Creating Resource Patch Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_patches_intro.md Example of how to define a ResourcePatch. This patch type modifies decoded resources within an APK. ```kotlin @Surpress("unused") val resourcePatch = resourcePatch(name = "Resource patch") { apply { // More about this on the next page of the documentation. } } ``` -------------------------------- ### Define Bytecode Matching Criteria Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Use `composingFirstMethod` to specify attributes for matching a specific method in bytecode. This example defines criteria for a method in `com.some.app.ads.Loader`. ```kotlin package app.revanced.patches.ads.com.some.app val BytecodePatchContext.loadAdsMethod by composingFirstMethod { definingClass("Lcom/some/app/ads/Loader;") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) returnType("Z") parameterTypes("Z") opcodes(Opcode.RETURN) strings("pro") } ``` -------------------------------- ### get(String, Boolean) and delete(String) Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md Provides access to resource files for reading and writing, and allows marking files for deletion. ```APIDOC ## `get(String, Boolean)` and `delete(String)` ### Description The `get` function returns a `File` object for reading and writing resource files. The `delete` function marks files for deletion upon APK rebuild. ### Method `get(resourcePath: String, isDirectory: Boolean)` `delete(resourcePath: String)` ### Parameters - **resourcePath** (String) - The path to the resource file. - **isDirectory** (Boolean) - Indicates if the path refers to a directory (used by `get`). ### Request Example ```kt apply { val file = get("res/values/strings.xml") val content = file.readText() file.writeText(content) delete("res/values/strings.xml") } ``` ### Response - **file** (File) - A `File` object representing the resource file. ``` -------------------------------- ### Read and Write Resource Files Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md The `get` function returns a `File` object for reading and writing resource files. Use `writeText` to update content and `readText` to retrieve it. The `delete` function marks files for removal during APK rebuild. ```kotlin apply { val file = get("res/values/strings.xml") val content = file.readText() file.writeText(content) } ``` ```kotlin apply { delete("res/values/strings.xml") } ``` -------------------------------- ### Reconstruct Original Java Code from Bytecode Attributes Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md This example demonstrates how the extracted bytecode attributes (access flags, return type, parameter types, opcodes, strings, and class name) can be used to reconstruct the original Java method. ```java package com.some.app.ads; class AdsLoader { public final boolean (boolean ) { // ... var userStatus = "pro"; // ... return ; } } ``` -------------------------------- ### IndexedMatcher extension function Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Provides an example of using the `matchIndexed` extension function on a list of instructions to apply an IndexedMatcher. ```kotlin val matched = listOf().matchIndexed("string"(), method()) ``` -------------------------------- ### Creating Raw Resource Patch Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_patches_intro.md Example of how to define a RawResourcePatch. This patch type is used for modifying arbitrary files within an APK without decoding resources. ```kotlin @Surpress("unused") val rawResourcePatch = rawResourcePatch(name = "Raw resource patch") { apply { // More about this on the next page of the documentation. } } ``` -------------------------------- ### Extension Functions for Expressive Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Provides examples of extension functions that allow matching based on specific attributes of methods and classes, such as implementation details, parameter types, and field properties. These extensions make the matching criteria more readable and concise. ```kotlin firstMethod { implementation { anyInstruction { opcode == Opcode.RETURN } } && anyParameter { type == "I" } } firstClassDef { anyField { accessFlags.all { it == AccessFlags.PRIVATE } && type == "Ljava/lang/String;" } && anyMethod { name == "toString" } } ``` -------------------------------- ### Navigate Method Calls by Index Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md The `navigate` API allows recursive navigation through method calls by index. Use `original()` to retrieve the immutable method or `stop()` to get the mutable copy. Chaining `to()` calls enables deeper navigation. ```kotlin apply { // Sequentially navigate to the instructions at index 1 within 'someMethod'. val method = navigate(someMethod).to(1).original() // original() returns the original immutable method. // Further navigate to the second occurrence where the instruction's opcode is 'INVOKEVIRTUAL'. // stop() returns the mutable copy of the method. val method = navigate(someMethod).to(2) { instruction -> instruction.opcode == Opcode.INVOKEVIRTUAL }.stop() // Alternatively, to stop(), you can delegate the method to a variable. val method by navigate(someMethod).to(1) // You can chain multiple calls to at() to navigate deeper into the method. val method by navigate(someMethod).to(1).to(2, 3, 4).to(5) } ``` -------------------------------- ### Delegate Properties for API Usage Outside Apply Block Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates how to use delegate properties (prefixed with 'getting') to access matched methods or classes outside the main 'apply' block of a patch. This is useful for accessing matched elements in other parts of your code. ```kotlin val BytecodePatchContext.someMethod by gettingFirstMethod { name == "someMethodName" && definingClass == "Lcom/some/Class;" } bytecodePatch { apply { // Use the delegated property to access the matched method: someMethod.name } } ``` -------------------------------- ### Defining and Using Patch Options Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Demonstrates how to define string and custom type options within a patch and how to set their values. ```kotlin val patch = bytecodePatch(name = "Patch") { // Add an inbuilt option and delegate its value to a property. val value by stringOption(name = "String option") // Add an option with a custom type and delegate its value to a property. val someValue by option(name = "Some type option") apply { println(value) println(someValue) } } ``` ```kotlin loadPatches(patches).apply { // Type is checked at runtime. first { it.name == "Patch" }.options["String option"] = "Value" } ``` -------------------------------- ### Composite API for method matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates using the `firstMethodComposite` function to declaratively match a method based on its name, instructions, strings, and opcodes. Shows how to access matched properties. ```kotlin val match = firstMethodComposite { name("someMethodName") instructions( at(0) { opcode == Opcode.CONST_STRING }, after(2..3, method("name")) ) strings("someString", "anotherString") opcodes(Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_INTERFACE) } match.method match.methodOrNull match.immutableMethod match.immutableMethodOrNull match.classDef match.classDefOrNull match.immutableClassDef match.immutableClassDefOrNull ``` -------------------------------- ### IndexedMatcher for Instructions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows how to use `indexedMatcher` to match `Instruction` objects based on their properties like opcode, type, method, field, string, reference, and registers. ```APIDOC ## IndexedMatcher for Instructions ### Description Shows how to use `indexedMatcher` to match `Instruction` objects based on their properties like opcode, type, method, field, string, reference, and registers. ### Method `indexedMatcher(instructionPredicate1, instructionPredicate2, ...)` ### Parameters - `opcode(Opcode)`: Matches an instruction with the specified opcode. - `type(typeString)`: Matches an instruction referencing the specified type. - `method(methodName)`: Matches an instruction referencing the specified method. - `field(fieldName)`: Matches an instruction referencing the specified field. - `string(stringValue)`: Matches an instruction referencing the specified string. - `reference(referenceString)`: Matches an instruction referencing the specified reference. - `literal(longValue)`: Matches an instruction with the specified literal long value. - `registers(vararg Int)`: Matches an instruction using the specified registers. - `instruction { condition }`: Matches an instruction based on a custom condition. - `allOf(predicate1, ...)`: Matches if all provided predicates are true. - `noneOf(predicate1, ...)`: Matches if none of the provided predicates are true. - `anyOf(predicate1, ...)`: Matches if any of the provided predicates are true. ### Request Example ```kt indexedMatcher( opcode(Opcode.CONST_STRING), type("Lcom/some/Class;"), method("someMethodName"), field("someFieldName"), string("someString"), reference("Lcom/some/Class;->someMethod()V"), literal(1L), registers(1, 2, 3), instruction { opcode == Opcode.INVOKE_VIRTUAL }, allOf(noneOf(opcode(Opcode.CONST_STRING), opcode(Opcode.CONST)), anyOf(string("A"), string("B"))) ) ``` ``` -------------------------------- ### IndexedMatcher with Instruction helper functions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates using specialized helper functions like `opcode`, `type`, `method`, `string`, `reference`, `literal`, `registers`, `instruction`, `allOf`, `noneOf`, and `anyOf` for matching `Instruction` properties. ```kotlin indexedMatcher( opcode(Opcode.CONST_STRING), type("Lcom/some/Class;"), method("someMethodName"), field("someFieldName"), string("someString"), reference("Lcom/some/Class;->someMethod()V"), literal(1L), registers(1, 2, 3), instruction { opcode == Opcode.INVOKE_VIRTUAL }, allOf(noneOf(opcode(Opcode.CONST_STRING), opcode(Opcode.CONST)), anyOf(string("A"), string("B"))) ) ``` -------------------------------- ### Create Patcher Instance and Apply Patches Source: https://github.com/revanced/revanced-patcher/blob/main/docs/2_patcher_intro.md Creates a patcher for a given APK file and applies selected patches. The lambda receives APK details to filter patches. Patch results are logged, and the final result contains modified APK components. ```kotlin val patch = patcher(apkFile = File("app.apk")) { packageName, versionName -> patches // Optionally filter this set - for example based on packageName and versionName. } val patchesResult = patch { patchResult -> val exception = patchResult.exception ?: return@patch logger.info("\"${patchResult.patch}\" succeeded") StringWriter().use { exception.printStackTrace(PrintWriter(it)) logger.severe("\"${patchResult.patch}\" failed:\n$it") } } val dexFiles = patchesResult.dexFiles val resources = patchesResult.resources ``` -------------------------------- ### IndexedMatcher with unorderedAllOf Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows how to create an IndexedMatcher using `unorderedAllOf` with predicates for unordered matching of strings. ```kotlin indexedMatcher(predicates = unorderedAllOf("string"(), "string2"(String::contains))) ``` -------------------------------- ### Method Matching with String Lookup Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows how to use string arguments for faster method matching. This variant is supported across all method matching API variants and is useful when the exact method signature strings are known. ```kotlin firstMethod("someString", "someOtherString") ``` -------------------------------- ### Clone ReVanced Patcher Repository Source: https://github.com/revanced/revanced-patcher/blob/main/docs/1_setup.md Clone the ReVanced Patcher repository to your local machine and navigate into the project directory. This is the first step to setting up your development environment. ```bash git clone https://github.com/revanced/revanced-patches && cd revanced-patches ``` -------------------------------- ### IndexedMatcher with Unordered Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates how to create unordered matching predicates using `unorderedAllOf` for use with `indexedMatcher`. ```APIDOC ## IndexedMatcher with Unordered Matching ### Description Demonstrates how to create unordered matching predicates using `unorderedAllOf` for use with `indexedMatcher`. ### Method `indexedMatcher(predicates = unorderedAllOf(predicate1, predicate2, ...))` ### Parameters - `predicates`: A collection of predicates to be matched in any order. - `unorderedAllOf(predicate1, ...)`: Helper function to create unordered matching predicates. ### Request Example ```kt indexedMatcher(predicates = unorderedAllOf("string"(), "string2"(String::contains))) ``` ``` -------------------------------- ### navigate(Method).at(index) Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md Allows recursive navigation through method calls by index or instruction criteria. Can return the original immutable method or a mutable copy. ```APIDOC ## `navigate(Method).at(index)` ### Description Navigates method calls recursively by index or instruction criteria. `original()` returns the immutable method, while `stop()` or delegating to a variable returns the mutable copy. ### Method `navigate(Method).to(index)` ### Parameters - **Method** (Method) - The method to navigate within. - **index** (Int) - The index of the instruction or occurrence. - **(instruction -> Boolean)** (Function) - Optional predicate to find specific instructions. ### Request Example ```kt apply { // Sequentially navigate to the instructions at index 1 within 'someMethod'. val method = navigate(someMethod).to(1).original() // original() returns the original immutable method. // Further navigate to the second occurrence where the instruction's opcode is 'INVOKEVIRTUAL'. // stop() returns the mutable copy of the method. val method = navigate(someMethod).to(2) { instruction -> instruction.opcode == Opcode.INVOKEVIRTUAL }.stop() // Alternatively, to stop(), you can delegate the method to a variable. val method by navigate(someMethod).to(1) // You can chain multiple calls to at() to navigate deeper into the method. val method by navigate(someMethod).to(1).to(2, 3, 4).to(5) } ``` ### Response - **method** (Method) - The navigated method (original immutable or mutable copy). ``` -------------------------------- ### Basic API Variants for Class and Method Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates the use of first, orNull, and declarative variants for finding classes and methods. Use the 'first' variants when a match is expected, and 'OrNull' variants when a match is optional. Declarative variants allow for more structured predicate definitions. ```kotlin bytecodePatch { apply { // Find the first class matching the predicate, or raises an exception if no match is found: firstClassDef { type == "Lcom/some/Class;" } // Returns null if no match is found: assertIsNull(firstClassDefOrNull { type == "No class has such a type" }) // Declarative variant: firstClassDefDeclaratively { predicate { type == "Lcom/some/Class;" } } // Declarative variant, returns null if no match is found: assertIsNull(firstClassDefDeclarativelyOrNull { predicate { type == "No class has such a type" } }) // Find the first method matching the predicate, or raises an exception if no match is found: firstMethod { name == "someMethodName" && definingClass == "Lcom/some/Class;" } // Returns null if no match is found: assertIsNull(firstMethodOrNull { name == "No method has such a name" }) // Declarative variant: firstMethodDeclaratively { predicate { name == "someMethodName" } predicate { definingClass == "Lcom/some/Class;" } } // Declarative variant, returns null if no match is found: assertIsNull(firstMethodDeclarativelyOrNull { predicate { name == "No method has such a name" } }) } } ``` -------------------------------- ### IndexedMatcher with basic conditions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates creating an IndexedMatcher with lambda conditions to match specific integer values at certain positions in a list. Asserts the matching result and the collected indices. ```kotlin val match = indexedMatcher( { lastMatchedIndex, currentIndex, setNextIndex -> currentIndex == 0 && this == 1 }, { _,_,_ -> this == 2 }, { _,_,_ -> this == 3 }, ) assertFalse(match(listOf(0, 1, 0, 0, 2, 0, 3))) assertEmpty(match.indices) true(match(listOf(1, 0, 0, 2, 0, 3))) assertEquals(match.indices, listOf(0, 3, 5)) ``` -------------------------------- ### Load Patches from File Source: https://github.com/revanced/revanced-patcher/blob/main/docs/2_patcher_intro.md Loads a set of patches from a specified file. Ensure the 'revanced-patches.rvp' file is accessible. ```kotlin val patches = loadPatches(File("revanced-patches.rvp")) ``` -------------------------------- ### Build ReVanced Patcher Project Source: https://github.com/revanced/revanced-patcher/blob/main/docs/1_setup.md Build the ReVanced Patcher project using the Gradle wrapper. This command compiles the project and runs all necessary build tasks. ```bash ./gradlew build ``` -------------------------------- ### Adding Extensions to a Patch Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Demonstrates how to include precompiled DEX files as extensions to a patch for runtime modifications. ```java public class ComplexPatch { public static void doSomething() { // ... } } ``` ```kotlin val patch = bytecodePatch(name = "Complex patch") { extendWith("complex-patch.rve") apply { someMethod.addInstructions(0, "invoke-static { }, LComplexPatch;->doSomething()V") } } ``` ```kotlin extendWith { File("complex-patch.rve").inputStream() } ``` -------------------------------- ### Configure GitHub Packages Authentication Source: https://github.com/revanced/revanced-patcher/blob/main/docs/1_setup.md If the build fails due to authentication issues with GitHub Packages, you need to create a Personal Access Token (PAT) with the 'read:packages' scope. Add this token to your ~/.gradle/gradle.properties file. ```properties gpr.user = user gpr.key = key ``` -------------------------------- ### IndexedMatcher with helper functions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows the usage of helper functions like `at`, `after`, `afterAtMin`, and `afterAtMost` to define conditions for an IndexedMatcher based on index positions. ```kotlin indexedMatcher( at(0) { this == 1 }, at(3) { this == 2 }, after(1..2) { this == 3 }, after { this == 2 }, afterAtMin(2) { this == 3 }, afterAtMost(2) { this == 3 }, ) ``` -------------------------------- ### IndexedMatcher for Instruction matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates creating an IndexedMatcher to match specific `Instruction` objects within a method based on their opcode and reference string. ```kotlin val match = indexedMatcher( { _, _, _ -> opcode == Opcode.CONST_STRING }, { _, _, _ -> (this as? ReferenceInstruction)?.reference?.toString()?.contains("myMethod") == true } ) ``` -------------------------------- ### IndexedMatcher Usage Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates the basic usage of `indexedMatcher` to match items in a list by their index and value, and verifies the matched indices. ```APIDOC ## IndexedMatcher Usage ### Description Demonstrates the basic usage of `indexedMatcher` to match items in a list by their index and value, and verifies the matched indices. ### Method `indexedMatcher(predicate1, predicate2, ...)` ### Parameters - `T`: The type of elements in the list. - `predicate`: A lambda function that takes `lastMatchedIndex`, `currentIndex`, and `setNextIndex` as parameters and returns a boolean indicating if the current item matches. ### Request Example ```kt val match = indexedMatcher( { lastMatchedIndex, currentIndex, setNextIndex -> currentIndex == 0 && this == 1 }, { _,_,_ -> this == 2 }, { _,_,_ -> this == 3 }, ) assertFalse(match(listOf(0, 1, 0, 0, 2, 0, 3))) assertEmpty(match.indices) assertTrue(match(listOf(1, 0, 0, 2, 0, 3))) assertEquals(match.indices, listOf(0, 3, 5)) ``` ### Response - `match`: A function that takes a list and returns a boolean indicating if the list matches the defined criteria. - `match.indices`: A list of indices where matches were found. ``` -------------------------------- ### Composite API for Method Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Introduces the Composite API, which combines matching and matcher APIs to target the common use-case of matching methods and finding instruction indices. ```APIDOC ## Composite API for Method Matching ### Description Introduces the Composite API, which combines matching and matcher APIs to target the common use-case of matching methods and finding instruction indices. ### Method `firstMethodComposite { ... }` ### Parameters - `name(methodName)`: Specifies the name of the method to match. - `instructions(indexedMatcherPredicate1, ...)`: Matches instructions using indexed matchers. - `strings(string1, ...)`: Matches strings. - `opcodes(opcode1, ...)`: Matches opcodes. ### Request Example ```kt val match = firstMethodComposite { name("someMethodName") instructions( at(0) { opcode == Opcode.CONST_STRING }, after(2..3, method("name")) ) strings("someString", "anotherString") opcodes(Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_INTERFACE) } // Accessing matched method and class information: match.method match.methodOrNull match.immutableMethod match.immutableMethodOrNull match.classDef match.classDefOrNull match.immutableClassDef match.immutableClassDefOrNull // Get the indices of the matchers: val instructionIndices = match.indices[0] val stringIndices = match.indices[1] val opcodeIndices = match.indices[2] ``` ``` -------------------------------- ### Predicate-Based Matching with String Predicates Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates using predicate-based matching for methods, allowing for flexible criteria like string prefixes or specific return types. This variant offers fine-grained control over matching conditions. ```kotlin firstMethodDeclaratively { name { startsWith("some") } definingClass("Lcom/some/") returnType { it == "V" || it == "Z" } } ``` -------------------------------- ### IndexedMatcher with Lambda and Invoke Variants Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates convenience variants of the matching APIs, including lambda and invoke overloads for common matching criteria like strings, methods, and references. ```APIDOC ## IndexedMatcher with Lambda and Invoke Variants ### Description Demonstrates convenience variants of the matching APIs, including lambda and invoke overloads for common matching criteria like strings, methods, and references. ### Method `indexedMatcher(variantPredicate1, variantPredicate2, ...)` ### Parameters - `T`: The type of elements in the list. - `Opcode.CONST_STRING()`: Invoke variant for matching a specific opcode. - `"string" { contains(it) }`: Lambda variant for matching strings with a custom condition. - `"string"(String::contains)`: Invoke variant for matching strings using a method reference. - `1L()`: Invoke variant for matching a literal long value. - `method { definingClass == "Lcom/some/Class;" && name == "someMethodName" }`: Lambda variant for matching methods with specific class and name. - `reference { it is StringReference }`: Lambda variant for matching references of a specific type. ### Request Example ```kt indexedMatcher( Opcode.CONST_STRING(), "string" { contains(it) }, "string"(String::contains), 1L(), method { definingClass == "Lcom/some/Class;" && name == "someMethodName" }, reference { it is StringReference }, ) ``` ``` -------------------------------- ### Declaring Options Outside Patches Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Illustrates how to declare an option independently and then use it within multiple patches. ```kotlin val option = stringOption(name = "Option") bytecodePatch(name = "Patch") { val value by option() } bytecodePatch(name = "Another patch") { val value by option() } ``` -------------------------------- ### Declarative Indexed Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows how to use indexed matchers in a declarative way with functions like `firstMethodDeclaratively`, `instructions`, `opcodes`, and `strings`. ```APIDOC ## Declarative Indexed Matching ### Description Shows how to use indexed matchers in a declarative way with functions like `firstMethodDeclaratively`, `instructions`, `opcodes`, and `strings`. ### Method `firstMethodDeclaratively { ... }` ### Parameters - `instructions(predicate1, ...)`: Matches instructions sequentially. - `opcodes(opcode1, ...)`: Matches opcodes sequentially using `after()`. - `strings(string1, ...)`: Matches full strings using `unorderedAllOf()`. ### Request Example ```kt firstMethodDeclaratively { instructions( string(), method()) opcodes(Opcode.CONST_STRING, Opcode.INVOKE_VIRTUAL) // Matches sequentially using after(). strings("A", "B", "C") // Matches full strings using unorderedAllOf(); Also uses them for fast lookup. } ``` ``` -------------------------------- ### Declarative Predicate Logic with anyOf, allOf, noneOf Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows how to combine multiple predicates using 'anyOf', 'allOf', and 'noneOf' blocks within the declarative API for complex matching logic. ```kotlin firstMethodDeclaratively { anyOf { predicate { name == "someMethodName" } predicate { name == "anotherMethodName" } } noneOf { allOf { predicate { definingClass == "Lcom/some/Class;" } predicate { accessFlags.contains(AccessFlags.PUBLIC) } } predicate { returnType == "V" } } } ``` -------------------------------- ### Creating Bytecode Patch with Inferring Name Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_patches_intro.md Demonstrates creating a BytecodePatch where the name is inferred from the variable name using the 'creating' variant. ```kotlin val `Some patch` by creatingBytecodePatch { apply { // More about this on the next page of the documentation. } } ``` -------------------------------- ### IndexedMatcher with Wildcards Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Explains the use of wildcards in `indexedMatcher` to match any instruction, string, method, field, or reference, including the use of `noneOf()` for matching any instruction when empty. ```APIDOC ## IndexedMatcher with Wildcards ### Description Explains the use of wildcards in `indexedMatcher` to match any instruction, string, method, field, or reference, including the use of `noneOf()` for matching any instruction when empty. ### Method `indexedMatcher(wildcardPredicate1, wildcardPredicate2, ...)` ### Parameters - `T`: The type of elements in the list. - `string()`: Matches any string. - `method()`: Matches any method. - `field()`: Matches any field. - `reference()`: Matches any reference. - `noneOf()`: Matches any instruction when the `noneOf` block is empty. ### Request Example ```kt indexedMatcher( string(), // Matches any string. method(), // Matches any method. field(), // Matches any field. reference(), // Matches any reference. noneOf(), // Matches any instruction, because the noneOf block is empty. ) ``` ``` -------------------------------- ### IndexedMatcher with mixed APIs Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates combining different matching APIs, including `at` and `afterAtMost`, within a single `indexedMatcher` call. ```kotlin indexedMatcher( at(2, afterAtMost(3, allOf(Opcode.CONST_STRING(), "str"(String::startsWith)))) ) ``` -------------------------------- ### IndexedMatcher with Special Functions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates the use of special helper functions like `at`, `after`, `afterAtMin`, and `afterAtMost` to define more complex matching conditions within `indexedMatcher`. ```APIDOC ## IndexedMatcher with Special Functions ### Description Illustrates the use of special helper functions like `at`, `after`, `afterAtMin`, and `afterAtMost` to define more complex matching conditions within `indexedMatcher`. ### Method `indexedMatcher(specialPredicate1, specialPredicate2, ...)` ### Parameters - `T`: The type of elements in the list. - `at(index)`: Matches an item at a specific index. - `after(range)`: Matches an item after a range of indices. - `afterAtMin(index)`: Matches an item after a minimum index. - `afterAtMost(index)`: Matches an item after a maximum index. - `predicate`: A lambda function for the matching condition. ### Request Example ```kt indexedMatcher( at(0) { this == 1 }, after(1..2) { this == 3 }, after { this == 2 }, afterAtMin(2) { this == 3 }, afterAtMost(2) { this == 3 }, ) ``` ``` -------------------------------- ### Using afterDependents Block for Post-processing Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Shows how the afterDependents block executes after all dependent patches are applied, ensuring post-processing occurs in the correct order. ```kotlin val patch = bytecodePatch(name = "Patch") { dependsOn( bytecodePatch(name = "Dependency") { apply { print("1") } afterDependents { print("4") } } ) apply { print("2") } afterDependents { print("3") } } ``` -------------------------------- ### IndexedMatcher with wildcards Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates using wildcard matchers for `string`, `method`, `field`, `reference`, and `noneOf` to match any instance of these types. ```kotlin indexedMatcher( string(), // Matches any string. method(), // Matches any method. field(), // Matches any field. reference(), // Matches any reference. noneOf(), // Matches any instruction, because the noneOf block is empty. ) ``` -------------------------------- ### Declarative matching with IndexedMatchers Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates using IndexedMatchers within a declarative API for matching instructions, opcodes, and strings sequentially or unordered. ```kotlin firstMethodDeclaratively { instructions( string(), method()) opcodes(Opcode.CONST_STRING, Opcode.INVOKE_VIRTUAL) // Matches sequentially using after(). strings("A", "B", "C") // Matches full strings using unorderedAllOf(); Also uses them for fast lookup. } ``` -------------------------------- ### Read and Write DOM Files Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md The `document` function allows reading and writing DOM files. It can accept a file path or an `InputStream`. Modifications are made within the `use` block, ensuring proper resource management. ```kotlin apply { document("res/values/strings.xml").use { document -> val element = doc.createElement("string").apply { textContent = "Hello, World!" } document.documentElement.appendChild(element) } } ``` ```kotlin apply { val inputStream = classLoader.getResourceAsStream("some.xml") document(inputStream).use { document -> // ... } } ``` -------------------------------- ### document(String) and document(InputStream) Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md Enables reading and writing DOM files, supporting both string paths and input streams. ```APIDOC ## `document(String)` and `document(InputStream)` ### Description Reads and writes DOM files. Can accept a file path string or an `InputStream`. ### Method `document(filePath: String)` `document(inputStream: InputStream)` ### Parameters - **filePath** (String) - The path to the DOM file. - **inputStream** (InputStream) - An input stream to read the DOM file from. ### Request Example ```kt apply { document("res/values/strings.xml").use { document -> val element = doc.createElement("string").apply { textContent = "Hello, World!" } document.documentElement.appendChild(element) } val inputStream = classLoader.getResourceAsStream("some.xml") document(inputStream).use { document -> // ... process document ... } } ``` ### Response - **document** (Document) - A DOM `Document` object for manipulation. ``` -------------------------------- ### Accessing Composite API match indices Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates how to retrieve the indices of matched instructions, strings, and opcodes from a Composite API match result. ```kotlin // Get the indices of the matchers: val instructionIndices = match.indices[0] val stringIndices = match.indices[1] val opcodeIndices = match.indices[2] ``` -------------------------------- ### Accessing Option Type Information Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_1_patch_anatomy.md Shows how to retrieve the KType of a patch option, which includes generic type information. ```kotlin option.type // The KType of the option. Captures the full type information of the option, including generics. ``` -------------------------------- ### IndexedMatcher with lambda and invoke variants Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows convenient lambda and invoke variants for common matching APIs like `Opcode`, `string`, `method`, and `reference`. ```kotlin indexedMatcher( Opcode.CONST_STRING(), "string" { contains(it) }, "string"(String::contains), 1L(), method { definingClass == "Lcom/some/Class;" && name == "someMethodName" }, reference { it is StringReference }, ) ``` -------------------------------- ### Composite API Operator Overloads Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Explains the convenience operator overloads provided by the `Match` class in the Composite API for accessing matched indices. ```APIDOC ## Composite API Operator Overloads ### Description Explains the convenience operator overloads provided by the `Match` class in the Composite API for accessing matched indices. ### Method Operator overloads for `Match` class. ### Parameters - `match[index]`: Shorthand for `match.indices[index]`. - `match[index1, index2]`: Shorthand for `match.indices[index1][index2]`. - `match[-1, -1]`: Supports negative indices for accessing the last elements. - `val (method, indices, immutableClassDef) = match`: Destructuring declaration to access matched components. ### Request Example ```kt val match = firstMethodComposite { // ... matchers defined here } match[0] // Shorthand for match.indices[0]. match[0, 0] // Shorthand for match.indices[0][0]. match[-1, -1] // Also supports negative indices, shorthand for match.indices[match.indices.size - 1][match.indices[0].size - 1]. val (method, indices, immutableClassDef) = match // "indices" is match.indices[0]. ``` ``` -------------------------------- ### Extension Function for Indexed Matching Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Presents an extension function `matchIndexed` that simplifies the usage of `indexedMatcher` on a list of instructions. ```APIDOC ## Extension Function for Indexed Matching ### Description Presents an extension function `matchIndexed` that simplifies the usage of `indexedMatcher` on a list of instructions. ### Method `List.matchIndexed(predicate1, predicate2, ...)` ### Parameters - `List`: The list of instructions to match against. - `predicate`: Predicates to be used for matching. ### Request Example ```kt val matched = listOf().matchIndexed("string"(), method()) ``` ``` -------------------------------- ### Immutable API Variant for Read-Only Access Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Demonstrates the 'immutable' variant of the API, which returns read-only copies of matched classes or methods. Use this when you only need to inspect the matched elements and not modify them. ```kotlin firstImmutableClassDef { type == "Lcom/some/Class;" } ``` -------------------------------- ### Composite API operator overloading Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Shows the convenience of using operator overloading (`[]`) on the `Match` object to access indices, including support for negative indices. ```kotlin match[0] // Shorthand for match.indices[0]. match[0, 0] // Shorthand for match.indices[0][0]. match[-1, -1] // Also supports negative indices, shorthand for match.indices[match.indices.size - 1][match.indices[0].size - 1]. ``` -------------------------------- ### Composite API destructuring declaration Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Illustrates using a destructuring declaration to easily extract the method, its indices, and class definition from a Composite API match result. ```kotlin val (method, indices, immutableClassDef) = match // "indices" is match.indices[0]. ``` -------------------------------- ### Add ReVanced Patcher Dependency Source: https://github.com/revanced/revanced-patcher/blob/main/README.md Include this dependency in your project's build.gradle file to use the ReVanced Patcher library. Ensure you replace '{$version}' with the actual version number. ```kotlin dependencies { implementation("app.revanced:revanced-patcher:{$version}") } ``` -------------------------------- ### Create Mutable Class Definitions Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md Use `getOrReplaceMutable` to create a mutable copy of a class definition, allowing modifications to its methods. Accessing the property triggers the creation of the mutable copy. ```kotlin apply { val mutableClass = classDefs.getOrReplaceMutable(classDef) mutableClass.methods.add(Method()) } ``` -------------------------------- ### Declarative Extensions for Common Attributes Source: https://github.com/revanced/revanced-patcher/blob/main/docs/3_2_matching.md Highlights notable extension functions available for declarative variants, enabling matching by common method attributes like name, access flags, and return types. These can be used in conjunction with 'anyOf', 'allOf', and 'noneOf' blocks. ```kotlin firstMethodDeclaratively { anyOf { name("someMethodName") accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) } noneOf { definingClass("Lcom/some/Class;") allOf { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returnType("V") } } parameterTypes("I", "Ljava/lang/String;") predicate { parameterTypes.count() == 2 } custom {parameterTypes.count() == 2 } // Same as predicate. } ``` -------------------------------- ### BytecodePatchContext.classDefs.getOrReplaceMutable(classDef) Source: https://github.com/revanced/revanced-patcher/blob/main/docs/5_apis.md Makes a class definition mutable, allowing modifications. It creates a lazy mutable copy that replaces the original upon first access. ```APIDOC ## `BytecodePatchContext.classDefs.getOrReplaceMutable(classDef)` ### Description By default, classes are immutable. This function creates a lazy mutable copy of a class definition, allowing modifications. Subsequent accesses return the same mutable copy. ### Method `getOrReplaceMutable(classDef)` ### Parameters - **classDef** (ClassDef) - The class definition to make mutable. ### Request Example ```kt apply { val mutableClass = classDefs.getOrReplaceMutable(classDef) mutableClass.methods.add(Method()) } ``` ### Response - **mutableClass** (MutableClassDef) - A mutable copy of the provided class definition. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.