Skip to content

fix: Encode XML files as UTF-8 to fix compilation of resources#339

Merged
oSumAtrIX merged 1 commit intoReVanced:devfrom
Taknok:fix-surrogate
Jun 20, 2025
Merged

fix: Encode XML files as UTF-8 to fix compilation of resources#339
oSumAtrIX merged 1 commit intoReVanced:devfrom
Taknok:fix-surrogate

Conversation

@Taknok
Copy link
Contributor

@Taknok Taknok commented Apr 19, 2025

The android implementation of the transformer encodes the emoji in a form called "surrogate", but aapt and apktool do not understand the surrogate form. Thus, detect surrogate and recompute the traditional code point value before writing it to file allowing aapt and apktool to rebuild the app successfully.

It should fix some cases (mainly for google app) of ReVanced/revanced-manager#2142

@LisoUseInAIKyrios
Copy link

LisoUseInAIKyrios commented Apr 19, 2025

For reference, this different solution appears to fix the same issue by exporting to a utf16 string then recoding to utf8.

At first glance I'm not sure if it's better or worse than the solution in this PR.

@Taknok
Copy link
Contributor Author

Taknok commented Apr 19, 2025

I tried the modifications in the abandoned PR without success for the rebuild of the google phone app.

Should I rebase my branch on dev ?

@LisoUseInAIKyrios
Copy link

LisoUseInAIKyrios commented Apr 19, 2025

Rebasing is best since it's merging to dev.

@oSumAtrIX
Copy link
Member

oSumAtrIX commented Apr 19, 2025

I dislike band-aid solutions. For a couple of painful days I am experimenting a proper solution such as using a different transformer implementation like Saxon. Hopefully a proper solution can be found. If not, I'd prefer to outsource this fix-up solution as a wrapped document() API in patches repo

@Taknok
Copy link
Contributor Author

Taknok commented Apr 19, 2025

I agree, but the cleanest would be to fix the android transformer (to keep unicode point) or the aapt code (to handle surrogate form). I was not sure about introducing a new lib in the source code. Thus, I opted for the less impacting solution.

The wrapped solution or a argument for document() could be possible to. I could update the PR for this.

@Taknok
Copy link
Contributor Author

Taknok commented Apr 22, 2025

The core of the issue lies in the Android SDK based on OpenJDK, which in turn include Apache Xalan code. Java represents characters using UTF-16 (source). As a result, high Unicode code points are split into surrogate pairs (two char values). When parsed by Xalan's TreeWalker (link), these pairs are processed as two separate characters.

Subsequently, ToXMLStream or ToStream fails to recognize the two utf16 chars as a single Unicode character and encodes each part separately, producing an incorrect surrogate representation. This is a known issue, tracked by the following tickets:

The ToHTMLStream has been fixed (PR #163), but no release has been published since 2023, so the fix is not available in official SDKs like Android or OpenJDK.

Conclusion: A fix for the Xalan transformer is unlikely to be available in the near future.

I also explored using the Saxon-HE transformer. Unfortunately, Saxon is not designed to support Android. During transformer creation, it depends on javax.xml.transform.stax and javax.xml.stream—two packages that Google chose not to include in Android’s core Java libraries. You can verify this in the list of supported packages: https://developer.android.com/reference/packages.html

To use Saxon, we would need to port those two packages to Android, which is likely beyond the scope of this repository.

That leaves us with three options:

  1. Adopt a third-party XSLT transformer that supports Android. But which one ?
  2. Use the regex-based approach proposed in this PR. On 10 runs I have an average of 1m21s for patching the google phone app
  3. Convert the full string to UTF-16 and back to UTF-8, letting the cast merge surrogate bytes correctly On 10 runs I have an average of 1m18s for patching the google phone app

Regex based : Taknok@c20e804
UTF casting : Taknok@ba57bcb

@oSumAtrIX What would be the best ? the 3rd option with an optional parameter for the context.document(resource, enforce_utf8=true).use... ?
By default the enforce would be false

@oSumAtrIX
Copy link
Member

I was thinking of a more efficient solution which is to hook the output stream and modify it. This avoids writing to string, modifying it, then writing it to the file:

ChatGPT gave this as a starter:

import java.io.OutputStream
import java.io.Writer
import java.io.OutputStreamWriter

class UnicodeCorrectingWriter(outputStream: OutputStream, charset: String = "UTF-8") : Writer() {
    private val writer = OutputStreamWriter(outputStream, charset)
    private var pendingHighSurrogate: Char? = null

    override fun write(cbuf: CharArray, off: Int, len: Int) {
        for (i in off until off + len) {
            val ch = cbuf[i]
            if (Character.isHighSurrogate(ch)) {
                pendingHighSurrogate = ch
            } else if (Character.isLowSurrogate(ch) && pendingHighSurrogate != null) {
                val codePoint = Character.toCodePoint(pendingHighSurrogate!!, ch)
                writer.write(String(Character.toChars(codePoint)))
                pendingHighSurrogate = null
            } else {
                if (pendingHighSurrogate != null) {
                    // Write invalid pending high surrogate as-is
                    writer.write(pendingHighSurrogate!!.toInt())
                    pendingHighSurrogate = null
                }
                writer.write(ch.toInt())
            }
        }
    }

    override fun flush() {
        if (pendingHighSurrogate != null) {
            writer.write(pendingHighSurrogate!!.toInt())
            pendingHighSurrogate = null
        }
        writer.flush()
    }

    override fun close() {
        flush()
        writer.close()
    }
}

I haven't tested it but maybe this works. Would merge if this approach can be used.

@Taknok
Copy link
Contributor Author

Taknok commented May 2, 2025

I will look into it, thank for the hint

@Taknok
Copy link
Contributor Author

Taknok commented May 3, 2025

After quick look, the code never enter the highsurrogate, thus it never correctly encode the emoji.

if (Character.isHighSurrogate(ch)) {
  pendingHighSurrogate = ch

Furthermore it takes more than 4min to reach the crash when repacking the res. I will continue to look into it to make it works, but it seems to not be the best performance strategy.

@Taknok
Copy link
Contributor Author

Taknok commented May 5, 2025

So unfortunately, the chatGPT method does not work as is, as the ToStream serializer write char by char to the stream when we reach this block : https://android.googlesource.com/platform/external/apache-xml/+/650a6cfd4d6b2d38b88ada03694ae19cc448d07b/src/main/java/org/apache/xml/serializer/ToStream.java#1609
The writer has to record the state of the potential surrogate and process the logic (as done in the xalan updated ToStream.java code).
The performance of this method is the lower among all. It tooks 1m42s average (when ~1m20s for the others). Due to the complexity of the writer, this method seems to be the less futur proof as it depends of the calls of ToStream.

My tracking branch: Taknok@ca2de8e

My personnal ranking of the techniques:

  1. UTF casting Taknok@ba57bcb
  2. regex Taknok@c20e804
  3. writer Taknok@ca2de8e

Available on discord if needed.

@kitadai31
Copy link
Contributor

  1. UTF casting Taknok@ba57bcb

Wait, does setOutputProperty(OutputKeys.ENCODING, "UTF-16") work on Android Runtime!?

Yeah, I also confirmed with Android 6.0 and 15.
I didn’t know that at all...

Because it doesn't work on JRE.
On JRE, setOutputProperty(OutputKeys.ENCODING, "XXX") only has an effect when a Document instance is created on the memory.
If a Document is created from an existing XML file, it will have no effect.

References:
https://discord.com/channels/952946952348270622/953965039105232906/1333603549904375909
https://stackoverflow.com/questions/15592025/transformer-setoutputpropertyoutputkeys-encoding-utf-8-is-not-working
https://bugs.openjdk.org/browse/JDK-8227616


Then, you don't need to use StringWriter or convert to UTF-8.
AAPT2's XML parser understands encoding="UTF-16" and can compile UTF-16 XML files successfully.
So just output with UTF-16.

Adding just one line will fix the issue.

TransformerFactory.newInstance()
    .newTransformer()
    .apply { setOutputProperty(OutputKeys.ENCODING, "UTF-16") }  // Add like this?
    .transform(DOMSource(this), StreamResult(stream))

(a condition for checking AndroidRuntime could be added)

@oSumAtrIX
Copy link
Member

If this is all and a conditional check is added, I'd merge it with a comment referencing the Android issue tracker

@Taknok
Copy link
Contributor Author

Taknok commented May 8, 2025

There is not surrogate issue on JRE as the openjdk correctly implement the conversion. Thus the conditional check is still needed ?

I will try without the UTF8 , but I think y my tests it was not working without

@Taknok
Copy link
Contributor Author

Taknok commented May 8, 2025

Here are the requested modifications. Tell me if you want some adjustments.

@kitadai31
Copy link
Contributor

kitadai31 commented May 8, 2025

It worked!
I patched GPhotos on Manager with Patches 5.19.0 (the last patches version that photos compiling is not fixed) successfully.

@Taknok
Copy link
Contributor Author

Taknok commented May 8, 2025

You can also use google phone app with this patch to check if issue is fixed : https://github.com/Taknok/revanced-patches

true
} catch (e: ClassNotFoundException) {
false
}
Copy link
Contributor

@kitadai31 kitadai31 May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to companion object so that you can avoid checking this every time

Also, System.getProperty("java.runtime.name") == "Android Runtime" is simpler

(This property has probably not been changed since the beginning, Even in Android 4.x, before ART was introduced, it was “Android Runtime”.)

@kitadai31
Copy link
Contributor

Nope, outputting in UTF-16 caused problems when patching other apps
Converting to UTF-8 is probably necessary

Sorry for jumping to conclusions...

- Device Info
ReVanced Manager: 1.25.0-dev.1
Model: Pixel 3
Android version: 15
Supported architectures: arm64-v8a, armeabi-v7a, armeabi
Root permissions: Yes

- Patch Info
App: com.google.android.youtube v20.12.46 (Suggested: 20.12.46)
Patches version: v5.22.0
Patches added: Default
Patches removed: None
Default patch options changed: None

- Settings
Allow changing patch selection: false
Version compatibility check: true
Show universal patches: false
Patches source: revanced/revanced-patches

- Logs
Reading APK
Decoding app manifest
Loading patches
Deleting existing temporary files directory
Decoding resources
Initializing lookup maps
Executing patches
Applied 52 patches
GmsCore support failed: app.revanced.patcher.patch.PatchException: The patch "GmsCore support" depends on "ResourcePatch", which raised an exception:
app.revanced.patcher.patch.PatchException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@aec901d) 
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend$execute(Unknown Source:143)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend$execute(Unknown Source:65)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:190)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:2)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:1)
	at kotlinx.coroutines.flow.SafeFlow.collect(Unknown Source:102)
	at app.revanced.manager.flutter.MainActivity$runPatcher$1$patcherResult$1$1.invokeSuspend(Unknown Source:74)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(Unknown Source:11)
	at kotlinx.coroutines.DispatchedTask.run(Unknown Source:134)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(Unknown Source:91)
	at kotlinx.coroutines.JobKt.runBlocking$default(Unknown Source:104)
	at app.revanced.manager.flutter.MainActivity.runPatcher$lambda$34(Unknown Source:360)
	at app.revanced.manager.flutter.MainActivity.$r8$lambda$_NYn7P0Ss3RCL0-SqEFL-opMsQw(Unknown Source:0)
	at app.revanced.manager.flutter.MainActivity$$ExternalSyntheticLambda6.run(Unknown Source:18)
	at java.lang.Thread.run(Thread.java:1119)
Caused by: org.xml.sax.SAXParseException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@aec901d) 
	at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:147)
	at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:107)
	at app.revanced.patcher.util.Document.<init>(SourceFile:2)
	at app.revanced.patcher.util.Document.<init>(SourceFile:4)
	at app.revanced.patcher.patch.ResourcePatchContext.document(SourceFile:2)
	at app.revanced.patches.shared.misc.gms.GmsCoreSupportPatchKt.gmsCoreSupportResourcePatch$lambda$35$lambda$34$addSpoofingMetadata(GmsCoreSupportPatch.kt:568)
	at app.revanced.patches.shared.misc.gms.GmsCoreSupportPatchKt.gmsCoreSupportResourcePatch$lambda$35$lambda$34(GmsCoreSupportPatch.kt:622)
	at app.revanced.patches.shared.misc.gms.GmsCoreSupportPatchKt.$r8$lambda$lRRewJm6n_a-02ysO3PqlF2CFs8(Unknown Source:0)
	at app.revanced.patches.shared.misc.gms.GmsCoreSupportPatchKt$$ExternalSyntheticLambda3.invoke(Unknown Source:15)
	at app.revanced.patcher.patch.Patch.execute(Unknown Source:7)
	at app.revanced.patcher.patch.ResourcePatch.execute$revanced_patcher(Unknown Source:9)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend$execute(Unknown Source:124)
	... 14 more

	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend$execute(Unknown Source:113)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:190)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:2)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:1)
	at kotlinx.coroutines.flow.SafeFlow.collect(Unknown Source:102)
	at app.revanced.manager.flutter.MainActivity$runPatcher$1$patcherResult$1$1.invokeSuspend(Unknown Source:74)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(Unknown Source:11)
	at kotlinx.coroutines.DispatchedTask.run(Unknown Source:134)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(Unknown Source:91)
	at kotlinx.coroutines.JobKt.runBlocking$default(Unknown Source:104)
	at app.revanced.manager.flutter.MainActivity.runPatcher$lambda$34(Unknown Source:360)
	at app.revanced.manager.flutter.MainActivity.$r8$lambda$_NYn7P0Ss3RCL0-SqEFL-opMsQw(Unknown Source:0)
	at app.revanced.manager.flutter.MainActivity$$ExternalSyntheticLambda6.run(Unknown Source:18)
	at java.lang.Thread.run(Thread.java:1119)
Change package name failed: app.revanced.patcher.patch.PatchException: The patch "Change package name" raised an exception: app.revanced.patcher.patch.PatchException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@9750f0a) 
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:320)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:2)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:1)
	at kotlinx.coroutines.flow.SafeFlow.collect(Unknown Source:102)
	at app.revanced.manager.flutter.MainActivity$runPatcher$1$patcherResult$1$1.invokeSuspend(Unknown Source:74)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(Unknown Source:11)
	at kotlinx.coroutines.DispatchedTask.run(Unknown Source:134)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(Unknown Source:91)
	at kotlinx.coroutines.JobKt.runBlocking$default(Unknown Source:104)
	at app.revanced.manager.flutter.MainActivity.runPatcher$lambda$34(Unknown Source:360)
	at app.revanced.manager.flutter.MainActivity.$r8$lambda$_NYn7P0Ss3RCL0-SqEFL-opMsQw(Unknown Source:0)
	at app.revanced.manager.flutter.MainActivity$$ExternalSyntheticLambda6.run(Unknown Source:18)
	at java.lang.Thread.run(Thread.java:1119)
Caused by: org.xml.sax.SAXParseException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@9750f0a) 
	at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:147)
	at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:107)
	at app.revanced.patcher.util.Document.<init>(SourceFile:2)
	at app.revanced.patcher.util.Document.<init>(SourceFile:4)
	at app.revanced.patcher.patch.ResourcePatchContext.document(SourceFile:2)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt.changePackageNamePatch$lambda$9$lambda$8(ChangePackageNamePatch.kt:78)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt.$r8$lambda$6AkdPHArk5z26dp2iCI31m62ogY(Unknown Source:0)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt$$ExternalSyntheticLambda4.invoke(Unknown Source:6)
	at app.revanced.patcher.patch.Patch.finalize(Unknown Source:9)
	at app.revanced.patcher.patch.ResourcePatch.finalize$revanced_patcher(Unknown Source:9)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:308)
	... 12 more

	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:382)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:2)
	at app.revanced.patcher.Patcher$invoke$1.invoke(SourceFile:1)
	at kotlinx.coroutines.flow.SafeFlow.collect(Unknown Source:102)
	at app.revanced.manager.flutter.MainActivity$runPatcher$1$patcherResult$1$1.invokeSuspend(Unknown Source:74)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(Unknown Source:11)
	at kotlinx.coroutines.DispatchedTask.run(Unknown Source:134)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(Unknown Source:91)
	at kotlinx.coroutines.JobKt.runBlocking$default(Unknown Source:104)
	at app.revanced.manager.flutter.MainActivity.runPatcher$lambda$34(Unknown Source:360)
	at app.revanced.manager.flutter.MainActivity.$r8$lambda$_NYn7P0Ss3RCL0-SqEFL-opMsQw(Unknown Source:0)
	at app.revanced.manager.flutter.MainActivity$$ExternalSyntheticLambda6.run(Unknown Source:18)
	at java.lang.Thread.run(Thread.java:1119)
Caused by: app.revanced.patcher.patch.PatchException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@9750f0a) 
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:320)
	... 12 more
Caused by: org.xml.sax.SAXParseException: Unexpected token (position:TEXT ���@1:8 in java.io.InputStreamReader@9750f0a) 
	at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:147)
	at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:107)
	at app.revanced.patcher.util.Document.<init>(SourceFile:2)
	at app.revanced.patcher.util.Document.<init>(SourceFile:4)
	at app.revanced.patcher.patch.ResourcePatchContext.document(SourceFile:2)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt.changePackageNamePatch$lambda$9$lambda$8(ChangePackageNamePatch.kt:78)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt.$r8$lambda$6AkdPHArk5z26dp2iCI31m62ogY(Unknown Source:0)
	at app.revanced.patches.all.misc.packagename.ChangePackageNamePatchKt$$ExternalSyntheticLambda4.invoke(Unknown Source:6)
	at app.revanced.patcher.patch.Patch.finalize(Unknown Source:9)
	at app.revanced.patcher.patch.ResourcePatch.finalize$revanced_patcher(Unknown Source:9)
	at app.revanced.patcher.Patcher$invoke$1.invokeSuspend(Unknown Source:308)
	... 12 more
Compiling modified resources
/data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/apk/AndroidManifest.xml:1: error: not well-formed (invalid token).
An error occurred:
brut.androlib.exceptions.AndrolibException: brut.common.BrutException: could not exec (exit code = 1): [/data/app/~~uxzK18kQmnPAJcAbOvR0jw==/app.revanced.manager.flutter.development-yPDJNdvuT9xMrXHjOgBweQ==/lib/arm64/libaapt2.so, link, -o, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/patched/resources/resources.apk, --package-id, 127, --min-sdk-version, 26, --target-sdk-version, 35, --version-code, 1553610176, --version-name, 20.12.46, --no-auto-version, --no-version-vectors, --no-version-transitions, --no-resource-deduping, --allow-reserved-package-id, --warn-manifest-validation, -e, /data/user/0/app.revanced.manager.flutter.development/cache/APKTOOL9182088485613914028.tmp, -0, arsc, -I, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/1.apk, --manifest, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/apk/AndroidManifest.xml, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/apk/build/resources.zip]
	at app.revanced.patcher.patch.ResourcePatchContext.get(SourceFile:146)
	at app.revanced.patcher.Patcher.get(Unknown Source:18)
	at app.revanced.manager.flutter.MainActivity.runPatcher$lambda$34(Unknown Source:391)
	at app.revanced.manager.flutter.MainActivity.$r8$lambda$_NYn7P0Ss3RCL0-SqEFL-opMsQw(Unknown Source:0)
	at app.revanced.manager.flutter.MainActivity$$ExternalSyntheticLambda6.run(Unknown Source:18)
	at java.lang.Thread.run(Thread.java:1119)
Caused by: brut.common.BrutException: could not exec (exit code = 1): [/data/app/~~uxzK18kQmnPAJcAbOvR0jw==/app.revanced.manager.flutter.development-yPDJNdvuT9xMrXHjOgBweQ==/lib/arm64/libaapt2.so, link, -o, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/patched/resources/resources.apk, --package-id, 127, --min-sdk-version, 26, --target-sdk-version, 35, --version-code, 1553610176, --version-name, 20.12.46, --no-auto-version, --no-version-vectors, --no-version-transitions, --no-resource-deduping, --allow-reserved-package-id, --warn-manifest-validation, -e, /data/user/0/app.revanced.manager.flutter.development/cache/APKTOOL9182088485613914028.tmp, -0, arsc, -I, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/1.apk, --manifest, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/apk/AndroidManifest.xml, /data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/revanced-temporary-files/apk/build/resources.zip]
	at brut.util.OS.exec(Unknown Source:72)
	at app.revanced.patcher.patch.ResourcePatchContext.get(SourceFile:142)
	... 5 more
Something went wrong:
PathNotFoundException: Cannot copy file to '/data/user/0/app.revanced.manager.flutter.development/files/lastPatchedApp.apk', path = '/data/user/0/app.revanced.manager.flutter.development/files/patcher/tmp-KGGWPD/out.apk' (OS Error: No such file or directory, errno = 2)

@Taknok Taknok marked this pull request as draft May 8, 2025 19:18
@Taknok
Copy link
Contributor Author

Taknok commented May 8, 2025

Draft waiting UTF8 revert

Comment on lines 37 to 47

it.outputStream().use { stream ->
TransformerFactory.newInstance()
.newTransformer()
.transform(DOMSource(this), StreamResult(stream))
it.outputStream().use {
val transformer = TransformerFactory.newInstance().newTransformer()
if (isAndroid) {
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16")
}
transformer.transform(DOMSource(this), StreamResult(it))
}
Copy link
Contributor

@kitadai31 kitadai31 May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean removing it.outputStream().use { } and passing the File to StreamResult() directly
My bad

Copy link
Contributor Author

@Taknok Taknok May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

val transformer = TransformerFactory.newInstance().newTransformer()
if (isAndroid) {
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16")
}
transformer.transform(DOMSource(this), StreamResult(it))

instead of

it.outputStream().use {
    val transformer = TransformerFactory.newInstance().newTransformer()
    if (isAndroid) {
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16")
    }
    transformer.transform(DOMSource(this), StreamResult(it))
}

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor Author

@Taknok Taknok May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thus, as we need to enforce the UTF-8 conversion, I cannot remove this section as replacing this with StreamResult(file) will remove the control on the encoding, which is precisely what we want to achieve.

Final code would be :

            val writer = StringWriter()
            TransformerFactory.newInstance().newTransformer().apply {
                if (isAndroid) {
                    setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
                    setOutputProperty(OutputKeys.ENCODING, "UTF-16")
                }

                transform(DOMSource(this@Document), StreamResult(writer))
            }

            it.outputStream().use { stream ->
                stream.write(writer.toString().toByteArray(Charsets.UTF_8))
            }

Are you ok with it ?

I successfully patch youtube and google phone (+aapt2 v35.0.2) with it:

Youtube:

- Device Info
ReVanced Manager: 1.24.0
Model: Pixel 7
Android version: 15
Supported architectures: arm64-v8a
Root permissions: Yes

- Patch Info
App: com.google.android.youtube v20.12.46 (Suggested: 20.12.46)
Patches version: v5.22.0
Patches added: Default
Patches removed: None
Default patch options changed: None

- Settings
Allow changing patch selection: false
Version compatibility check: true
Show universal patches: false
Patches source: revanced/revanced-patches

- Logs
Reading APK
Decoding app manifest
Loading patches
Deleting existing temporary files directory
Decoding resources
Initializing lookup maps
Executing patches
Applied 53 patches
Compiling modified resources
Aligning APK
Signing APK
Patched APK

Google Phone:

- Device Info
ReVanced Manager: 1.24.0
Model: Pixel 7
Android version: 15
Supported architectures: arm64-v8a
Root permissions: Yes

- Patch Info
App: com.google.android.dialer v172.0.749600042 (Suggested: Any)
Patches version: v1.0.0
Patches added: Default
Patches removed: None
Default patch options changed: None

- Settings
Allow changing patch selection: false
Version compatibility check: true
Show universal patches: false
Patches source: Taknok/revanced-patches

- Logs
Reading APK
Decoding app manifest
Loading patches
Deleting existing temporary files directory
Decoding resources
Initializing lookup maps
Executing patches
Adding '.' to search hint to visually detect patched app
Applied 1 patches
Compiling modified resources
Aligning APK
Signing APK
Patched APK

Copy link
Contributor Author

@Taknok Taknok May 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to use the outputStream() to be able to call write(). As we use outputStream() we have to use "use" to ensure the descriptor is closed

@Taknok Taknok marked this pull request as ready for review May 9, 2025 16:28
@kitadai31
Copy link
Contributor

In the end, we went back to the approach mentioned in LisoUseInAIKyrios's first comment.

But I'm thinking of using a FileWriter directly instead of using a StringWriter.
Since FileWriter uses the system default encoding, and Android's default encoding is always UTF-8, I expect it to write in UTF-8.

If this were possible, the serialized result would be written directly to a file, so there would be no performance impact.
I'll try this tomorrow

@Taknok
Copy link
Contributor Author

Taknok commented May 9, 2025

This function patches youtube and google phone without error:

    override fun close() {
        file?.let {
            if (readerCount[it]!! > 1) {
                throw IllegalStateException(
                    "Two or more instances are currently reading $it." +
                        "To be able to close this instance, no other instances may be reading $it at the same time.",
                )
            } else {
                readerCount.remove(it)
            }

            val transformer = TransformerFactory.newInstance().newTransformer().apply {
                if (isAndroid) {
                    setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
                    setOutputProperty(OutputKeys.ENCODING, "UTF-16")
                }
            }

            it.writer().use { writer ->
                transformer.transform(DOMSource(this), StreamResult(writer))
            }
        }
    }

@oSumAtrIX
Copy link
Member

Why is

                    setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")

needed?

@Taknok
Copy link
Contributor Author

Taknok commented May 10, 2025

Because we want to have an UTF-8 XML at the end, thus we have to explicitly say to not write the encoding as we perform the conversion : it.writer() set by default a charsets.UTF-8

@oSumAtrIX
Copy link
Member

So as I understand the transformer writes as utf16 and then the writer as utf8? Why are we omitting the xml declaration. It doesn't have to do anything with encoding from what I am seeing

@Taknok
Copy link
Contributor Author

Taknok commented May 10, 2025

The origin:

  1. App
  2. Apktool decode XML to UTF-8
  3. Java read UTF-8 and set it well in memory, string IB memory handles wells UTF-8. When writing to a file on the string it calls .toCharsArray() which encode it into a 16bits chars list (but some unicode needs overflow and are split into 2 16bits chars)
    4.1 openjdk, when writing, is aware of this potential issue. So it handle the writing by checking if the 16chars is a high point unicode and if the encoding is UTF-8, if yes, it goes to a special flow writing the 16charsunicode.
    4.2 Android is not aware of it, it thinks that it is handling UTF-8 that are only 16chars, if this unicode is unknown, so it writes it as an entity as would do JavaScript.
  4. Apktool recompiles the res, it do not understand surrogate unicode, if it reads one (like in Android senario) it crashes.

The fix:

  1. In memory we have a UTF-8 string with correct high point emoji.
  2. The toStream class will be called and split the strings with toCharsArray() (else we need to rewrite the whole ToStream from xalan, I tried this but there is private class etc in xalan increasing complexity and code copy).
  3. We tell to the writer that it will handle 16 bits char (UTF-16), but the charset used will be UTF-8 (default value of the file writers), so the output file should not have an xml header forcing to UTF-18 as we used UTF-8 charset.
  4. Aapt2 reads the file with UTF-8 and high point encoded value.

If you want to follow the flow in the debugging mode, you have to set a breaking in the characters() function for the ToStream.java class (called by the xml TreeWalker.java) and follow step by step the code for each case

@kitadai31
Copy link
Contributor

kitadai31 commented May 10, 2025

For JRE, there is no need to use Writer
I suggest this code
Also I tried adding some comments, I hope it helps

            val transformer = TransformerFactory.newInstance().newTransformer()
            if (isAndroid) {
                // Set to UTF-16 to prevent surrogate pairs from being escaped to broken numeric character references.
                transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-16")
                // The XML declaration will have encoding="UTF-16", but we're going to write it back in UTF-8, so omit it.
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
                // Use FileWriter to output the XML file in UTF-8 encoding.
                it.writer().use { writer ->
                    transformer.transform(DOMSource(this), StreamResult(writer))
                }
            } else {
                transformer.transform(DOMSource(this), StreamResult(it))
            }

@Taknok
Copy link
Contributor Author

Taknok commented May 11, 2025

Perf test with youtube and default patch:
Manager main branch + patcher main with surrogate fix : 334s
Manager main branch + patcher main branch vanilla : 349s

@Taknok
Copy link
Contributor Author

Taknok commented May 12, 2025

The (slightly) better performance is due to the buffered writer that buffer the chars wrote one by one. A main branch build with a buffered writer (https://github.com/Taknok/revanced-patcher/tree/main-buffered) have a patch time (for youtube with default selection) of 290s

@Taknok
Copy link
Contributor Author

Taknok commented Jun 19, 2025

Hi @kitadai31
This is a gentle reminder about this PR I opened a month ago, no rush at all. Whenever you have a chance to take a look, I'd really appreciate your feedback.

@LisoUseInAIKyrios
Copy link

The (slightly) better performance is due to the buffered writer that buffer the chars wrote one by one. A main branch build with a buffered writer (https://github.com/Taknok/revanced-patcher/tree/main-buffered) have a patch time (for youtube with default selection) of 290s

Make a pull request with that one liner change. A ~1 minute reduction in patch time is desirable.

@Taknok
Copy link
Contributor Author

Taknok commented Jun 19, 2025

Euh... ok but the way of how is formulated your message seems that the fix of the surrogate crash is not desirable ? O.o

@LisoUseInAIKyrios
Copy link

LisoUseInAIKyrios commented Jun 20, 2025

This PR is definitely desired. I was speaking half off topic about that other change.

I'm not reviewing this PR so someone else needs to approve it.

@kitadai31
Copy link
Contributor

I think this PR is ready

@oSumAtrIX oSumAtrIX changed the title fix: Use correct surrogate pairs for emojis fix: Encode XML files as UTF-8 to fix compilation of resources Jun 20, 2025
Copy link
Member

@oSumAtrIX oSumAtrIX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the comment is right, this is fine to merge

Unicode may has high value that overflows the 16bits range, java
encodes char using 16bits, thus those high Unicode are spitted in two
16bits chars called surrogate form. Unfortunately, aapt2 do not handle
Unicode in surrogate form and crash when apktool try to repack the res.
Explicitly telling the transformer to handle 16bits solve the issue.

Co-authored-by: kitadai31 <90122968+kitadai31@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
@Taknok
Copy link
Contributor Author

Taknok commented Jun 20, 2025

I will rebase this PR on the new dev

@oSumAtrIX oSumAtrIX merged commit 4f2ef3c into ReVanced:dev Jun 20, 2025
1 check passed
@Taknok
Copy link
Contributor Author

Taknok commented Jun 20, 2025

🎉

@Taknok Taknok deleted the fix-surrogate branch June 20, 2025 14:43
github-actions bot pushed a commit that referenced this pull request Jun 20, 2025
# [21.1.0-dev.3](v21.1.0-dev.2...v21.1.0-dev.3) (2025-06-20)

### Bug Fixes

* Encode XML files as UTF-8 to fix compilation of resources ([#339](#339)) ([4f2ef3c](4f2ef3c))
@kitadai31
Copy link
Contributor

kitadai31 commented Jul 6, 2025

@Taknok Hey, your last commit broke everything!
A use of Writer was removed accidentally.
When UTF-16 is set to the output encoding, it must be output with Writer to make the final output file UTF-8.
So a Writer must be used in isAndroid block.


Also, after some testing, I found that OutputStream is same with or without .buffered().
I created a custom FileOutputStream and FileWriter that record the number of writes, and measured the number of times each write was called, with and without wrapping it in Buffered, when output an XML file.

The number of times write() was called while outputting YT's public.xml.
MyFileOutputStream without buffering: 119
MyFileOutputStream with buffering: 119
MyFileWriter without buffering 1461632
MyFileWriter with buffering: 238

This result shows that when constructing a StreamResult, a Writer must be wrapped in Buffered, but an OutputStream does not need to be wrapped.
The XML Transformer is likely doing its own buffering if the target is an OutputStream.
Therefore, #347 (perf: Use a buffered writer to reduce IO overhead) was actually not necessary.

The source code I used to test:
https://gist.github.com/kitadai31/f087562d19a740e43ff472a8afcf623b

This PR basically needs to be reverted to the point of dfb7f05 (Before force-pushed)
I will open a PR to fix these.

@Taknok
Copy link
Contributor Author

Taknok commented Jul 6, 2025

Ok tag me in the PR you open

@kitadai31
Copy link
Contributor

kitadai31 commented Jul 6, 2025

@Taknok PR opened #356

@Taknok
Copy link
Contributor Author

Taknok commented Jul 6, 2025

Thank you

github-actions bot pushed a commit that referenced this pull request Oct 16, 2025
# [21.1.0](v21.0.0...v21.1.0) (2025-10-16)

### Bug Fixes

* Add back missing log by naming logger correctly ([#332](#332)) ([e4e66b0](e4e66b0))
* Correctly save XML files in UTF-8 by using a bufferedWriter ([#356](#356)) ([33fadcb](33fadcb))
* Encode XML files as UTF-8 to fix compilation of resources ([#339](#339)) ([4f2ef3c](4f2ef3c))
* Support UTF-8 chars when compiling instructions in Smali in non UTF-8 environments ([#331](#331)) ([bb8771b](bb8771b))

### Features

* Add identity hash code to unnamed patches ([88a3252](88a3252))
* Use option name as key for simplicity and consistency ([754b02e](754b02e))

### Performance Improvements

* Use a buffered writer to reduce IO overhead ([#347](#347)) ([99f4318](99f4318))
github-actions bot pushed a commit that referenced this pull request Oct 16, 2025
# [21.1.0](v21.0.0...v21.1.0) (2025-10-16)

### Bug Fixes

* Add back missing log by naming logger correctly ([#332](#332)) ([e4e66b0](e4e66b0))
* Correctly save XML files in UTF-8 by using a bufferedWriter ([#356](#356)) ([33fadcb](33fadcb))
* Encode XML files as UTF-8 to fix compilation of resources ([#339](#339)) ([4f2ef3c](4f2ef3c))
* Support UTF-8 chars when compiling instructions in Smali in non UTF-8 environments ([#331](#331)) ([bb8771b](bb8771b))

### Features

* Add identity hash code to unnamed patches ([88a3252](88a3252))
* Use option name as key for simplicity and consistency ([754b02e](754b02e))

### Performance Improvements

* Use a buffered writer to reduce IO overhead ([#347](#347)) ([99f4318](99f4318))
github-actions bot pushed a commit to LisoUseInAIKyrios/revanced-patcher that referenced this pull request Nov 28, 2025
# 1.0.0-dev.1 (2025-11-28)

* build(Needs bump)!: Bump dependencies ([d5f89a9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d5f89a903f019c199bdb27a50287124fc4b4978e))
* feat Use `Set` as super type for `PatchBundleLoader` ([4b76d19](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4b76d1959691babf8c99d3d5235df4a4388956f0))
* feat!: add `classDef` parameter to `MethodFingerprint` ([#175](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/175)) ([a205220](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a2052202b23037150df6aadc47f6e91efcd481cf))
* feat!: Add patch annotation processor ([3fc6a13](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3fc6a139eef67237c116fb4e3e29bf9542d3a981))
* feat!: merge integrations only when necessary ([6e24a85](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6e24a85eabd1e7a1484fad229d5ba55c3ba1f1b4))
* feat!: Remove patch annotations ([3b4db3d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3b4db3ddb72cdcee8af2f787eadf58eeb37543de))
* feat(fingerprint)!: `StringsScanResult` for `MethodFingerprint` ([3813e28](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3813e28ac2ad6710d8d935526ca679e7b1b5980e))
* fix!: check for two methods parameters orders ([#183](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/183)) ([b6d6a75](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b6d6a7591ba1c0b48ffdef52352709564da8d9be))
* fix!: implement extension functions consistently ([aacf900](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/aacf9007647b1cc11bc40053625802573efda6ef))
* refactor!: move extension functions to their corresponding classes ([a12fe7d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a12fe7dd9e976c38a0a82fe35e6650f58f815de4))
* refactor!: move utility methods from `MethodFingerprintUtils` `MethodFingerprint` ([d802ef8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d802ef844edf65d4d26328d6ca72e3ddd5a52b15))
* refactor!: Remove `Fingerprint` interface ([54a2f8f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/54a2f8f16fddf2b2ed47eb23717ba3734c4a6c5d))
* refactor!: rename parameter ([526a3d7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/526a3d7c359e2d95d26756da0f88d5ce975f5d9b))
* refactor!: use proper extension function names ([efdd01a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/efdd01a9886b6f06af213731824621964367b2a3))

### Bug Fixes

* (will revert, only for future reference) Fix existing bug that has existed for years: Always use up to date methods for searching with string lookup ([7ba0294](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7ba0294f585dff464af8bcaec558d4d5ab2797ce))
* `compareSignatureToMethod` not matching correctly in case opcodes are null ([cca12aa](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/cca12aa34a60d766c02e55241df847f7d230d4d7))
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([6cb7cdb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6cb7cdb0b2a2b954adb04033e0f2d3ccb4604545))
* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/835a421cc0588b92c2995e9d74727069d14b1750))
* `JarPatchBundle` loading non-class files to class loader ([849616d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/849616dc2b6e30ec1fa1d8a8f9c1f881fc11676a))
* `MethodWalker` not accounting for all reference instructions ([48068cb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/48068cb3d79e283ff1cad9f3f78dc1d0fcd14f83))
* `PackageMetadata` ([7399450](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/739945013962fd80d2635fff126d84046870f956))
* `replaceWith` not replacing classes with used class proxies ([4178a1e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4178a1eedce1436ffeb3ddd6952ce0b6ec87d5a0))
* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5a2f02b97dcde95dbe901fa68cca6c6c0219cb82)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
* Accept `PatchSet` in `PatchesConsumer#acceptPatches` ([716825f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/716825f232bf1aab3a97723968562aa6dbdb20b1))
* Account for source patch dependency for tests ([6918418](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/69184187d90f126478d2f49415c1e3381217557f))
* Add back missing log by naming logger correctly ([#332](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/332)) ([e4e66b0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e4e66b0d8bb0986b79fb150b9c15da35b8e11561))
* Add binary backwards compatibility, allow patching v21 patches ([568b485](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/568b4858df8ae9da9100a636b2062207a73ef201))
* Add clear match method for shared fingerprints ([d1d5557](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d1d5557b5a60052d1dec5f95c83aabbbb3b7b4b7))
* add docs (trigger release) ([6628b78](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6628b7870fc052da40be0d50a7e2b0b6c57743cc))
* add execute permission to `./gradlew` file ([#46](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/46)) ([34f607a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/34f607aa24d89a777d906cc887203f343ce3fd07))
* add imports to fix failing tests ([43d6868](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/43d6868d1f59922f9812f3e4a2a890f3b331def6))
* add tests for PathOption ([d6308e1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d6308e126c6217b098192c51b6e98bc85a8656bd))
* adding existing classes to the patchers cache ([9659a61](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9659a61c5c3a84714160b78b32cc337a97c8caa9))
* allow setting `DexClassLoader.optimizedDirectory` ([11a3378](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/11a337865947a6ac74a63ebb3f3f9bc2610f7771))
* Always make the generated patch depend on the source patch ([8de3063](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8de30633ae6eb7acf7f0a351e26d4a6c2fdbdfec))
* always return PatchResultSuccess on patch success ([996c4ac](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/996c4acb2061db776430ad8b07bfdb3fe32861f6))
* applying no patches throwing error ([5ca5a1c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5ca5a1c29e087ce7e4b6d5e593b775365803151d))
* applyPatches not returning successful patches ([f806cb3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f806cb38c571cdd22016396ee1874ee18c91b79f))
* avoid ignoring test resources (fixes [#1](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/1)) ([d5a3c76](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d5a3c76389ba902c22ddc8b7ba1a110b7ff852df))
* broken deprecation message ([62aa295](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/62aa295e7372014238415af36d902a4e88e2acbc))
* callback for each file instead of class ([930768d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/930768dfb31dc5fa6c248050b08ac117c40ee0a3))
* callback only when inteded ([e3bf367](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e3bf367ad6615b30b06027d65f906b2588567a7f))
* Catch correct exception ([637d487](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/637d48746ff8694e01c5aead1c75a9a1efeb5ac8))
* catch exceptions from closing patches ([d5d6f85](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d5d6f85084c03ed9c776632823ca12394a716167))
* check `CONST_STRING_JUMP` instructions for matching string ([058d292](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/058d292ad5e297f4c652ff543c13e77a39f7fb1b))
* check dependencies for resource patches ([9c07ffc](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9c07ffcc7af9f088426528561f4321c5cc6b5b15))
* Check for class type exactly instead of with contains ([#310](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/310)) ([69f2f20](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/69f2f20fd99162f91cd9c531dfe47d00d3152ead))
* check if fingerprint string is substring of any string references ([c5de9e2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c5de9e29889dffd18b31e62a892881cc48e8b607))
* check if patch option requirement is met ([14a73bf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/14a73bfcafac36bce2b8466788d460edde7a14fd))
* Classes not being written properly because of array shifting ([6e4db11](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6e4db110c8fdd16fb0c0ce81f427d84f2a3b6ee0))
* clear method lookup maps ([#198](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/198)) ([9d81baf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9d81baf4b4ca7514f8a1009e72218638609a7c7f))
* clear method lookup maps before initializing them ([#210](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/210)) ([746544f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/746544f9d51d1013bb160075709cd26bffd425b3))
* close open files ([#75](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/75)) ([123ad54](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/123ad54c150bd04f4b8ef5c65334ea468ceb99cc))
* close stream when closing `DomFileEditor` ([77604d4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/77604d40785847b775155c0e75b663a3c7336aa3))
* compare any methods parameters ([#101](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/101)) ([085a3a4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/085a3a479d7bd411dcb0492b283daca538c824a1))
* correct access flags of `PackageMetadata` ([416d691](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/416d69142f50dab49c9ea3f027e9d53e4777f257))
* Correctly save XML files in UTF-8 by using a bufferedWriter ([#356](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/356)) ([33fadcb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/33fadcbd0c7076b848bdca4d62a9c684d5781232))
* current must be calculated after increment ([5f12bab](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5f12bab5df97fbe6e2e62c1bf2814a2e682ab4f3))
* decode in correct order ([8fb2f2d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8fb2f2dc1d3b9b1e9fd13b39485985d2886d52ae))
* Delegate `PatchBundleLoader` by mutable set of patches ([9a109c1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9a109c129b135a634be1aad4130a06d9e8e96ecd))
* delete test that is now too clunky since a context must be passed ([c37ecb8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c37ecb893f4f8a4a70d33a9fc65ef062d2796ce1))
* dexlib must be propagated ([b738dcd](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b738dcd7ea04f5fe56e66af46fb11541fe54f6af))
* disable correct loggers ([c2d89c6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c2d89c622e06e58e5042e1a00ef67cee8a246e53))
* do not flag resource table as sparse when main package is not loaded ([b832812](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b832812767a06ec6ec232291e6d14c8c2f14118c))
* do not load annotations as patches ([519359a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/519359a9eb0e9dfa390c5016e9fe4a7490b8ab18))
* Do not resolve the proxied patch to the proxy in the dependency list ([e112837](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e11283744a21fe2d09435e99d6924462b6aac3b8))
* Do not set `CompatiblePackage.versions` if `@CompatiblePackage.versions` is empty ([6b1e0a1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6b1e0a16568124e9f82fb5740353360fa8ec614a))
* Do not set patch fields if they are empty ([a76ac04](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a76ac04214a2ab91e3b2f9dddb13ed52816fe723))
* DomFileEditor opening in- and output streams on the same file ([83187c9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/83187c9edd7b088bc18960c5eb9a2042ca536b5f))
* Downgrade smali to fix dex compilation issue ([5227e98](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5227e98abfaa2ff1204eb20a0f2671f58c489930))
* Encode XML files as UTF-8 to fix compilation of resources ([#339](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/339)) ([4f2ef3c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4f2ef3c47cea76a26c464cfb45d4bb57fe7198b5))
* enforce aapt v2 ([b68b0bf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b68b0bf3d735f54b92ad7dad8132f77e9007063f))
* failing tests temporarily ([fc05fe7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/fc05fe79deec2486bb746d33e803ad052e68f8de))
* fallback to patch class name instead of `java.lang.Class` class name ([4164cb0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4164cb0deacc7e1eed9fce63dab030180f28b762))
* Filter for patches correctly ([4bc4b0d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4bc4b0dc0104073b62528d02a88383cecd7a50e7))
* Find dependency in `context.allPatches` ([670f015](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/670f0153de10c6f0db25b08df1c01a2905037f84))
* **fingerprint:** do not throw on `MethodFingerprint.result` getter ([2f7e62e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/2f7e62ef65422f2c75ef8b09b9cd27076e172b30))
* fix classes having multiple instances of fields ([7cc8a7d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7cc8a7dec321774c1d3f2f1a87ac91f952c4fb7e))
* fix classes having multiple method instances ([398239d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/398239dc10a3ea04e46adb3be176c897876e5587))
* Fix SMALI compilation on devices with RTL language ([#242](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/242)) ([356f1f1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/356f1f155348347a8f318a2e024716ebf4fec99b))
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([e6c2501](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e6c2501539540301d5b70014de460e5452a09b04))
* fuzzy resolver warning params were turned around ([e5bea06](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e5bea06353805f004d607124a8ebed138f84d583))
* get framework ids to compile resources ([f2cb7ee](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f2cb7ee7dffa573c31df497cf235a3f5d120f91f))
* give ClassWriter a ClassReader for symtable ([41749ba](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/41749ba8290b2dec5dd2ab6e0bc9d714887a1a05))
* goodbye security ([8f3ac77](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8f3ac7702a2b3ee98c55aeac6a1b9972f99664cc))
* **gradle:** publish source and javadocs ([c236ebe](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c236ebe0789f9c78d610769f0feda2b64fa4a128))
* handle null properly ([#64](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/64)) ([482af78](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/482af78f2ba23b8003fc9961df5fde54d7295d5c))
* handle option types and nulls properly ([aff4968](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/aff4968e6f67239afa3b5c02cc133a17d9c3cbeb))
* handle private companion objects ([ad3d332](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ad3d332e27d07e9d074bbaaf51af7eb2f9bfc7d5))
* Improve exception message wording ([5481d0c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5481d0c54ccecc91cd8d15af1ba2d3285a33e5ab))
* Improve smali regex filter ([bb06381](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bb063811a99a25d4a247c3337284614f5a97ee2e))
* incorrect pattern offset ([f3b5f67](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f3b5f67b395167c1b9411b2374f3ef584b57b6cf))
* invalid type propagation in options ([b873228](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b873228ef0a9e6e431a4278c979caa5fcc508e0d)), closes [#98](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/98)
* invalid types for example options ([79f91e0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/79f91e0e5a6d99828f30aae55339ce0d897394c7))
* invert fingerprint resolution condition of `customFingerprint` ([e2faf4c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e2faf4ca9b6de23300b20ab471ee9dc365b04339))
* **Io:** fix finding classes by name ([b957501](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b957501e709028005c4d6c7857022980205b6861))
* **Io:** JAR loading and saving ([#8](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/8)) ([310a7c4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/310a7c446b547d84b02c5da2161958e77ce69f0d))
* log decoding resources after logging deleting resource cache directory ([db62a16](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/db62a1607b4a9d6256b5f5153decb088d9680553))
* Log the correct patch names ([9fdb8f0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9fdb8f087f62babf6081879db65c80db639aa0a7))
* Make `CompatiblePackage.versions` a property ([67b7dff](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/67b7dff67a212b4fc30eb4f0cbe58f0ba09fb09a))
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([4e56652](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4e566524299674426fb0344d09db3b0c1cb3d300))
* Make constructor internal as supposed ([7f44174](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7f44174d91f0af0d50a83d80a7103c779241e094))
* Make it work on Android 12 and lower by using existing APIs ([#312](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/312)) ([a44802e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a44802ef4ebf59ae47213854ba761c81dadc51f3))
* Make it work on Android by not using APIs from JVM unavailable to Android. ([2be6e97](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/2be6e97817437f40e17893dfff3bea2cd4c3ff9e))
* make patcher version public ([76c45dd](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/76c45dd7c1ffdca57e30ae7109c9fe0e5768f877))
* make warnings nullable instead of lateinit ([8f1a629](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8f1a629191668e05917dc797e486647e55276d59))
* Match fingerprint before delegating the match property ([5d996de](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5d996def4d3de4e2bfc34562e5a6c7d89a8cddf0))
* match to correct signature method parameters ([1ee2e4b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1ee2e4ba56097c5e06c93c9ce04cb5543f0e4a67))
* Merge all extensions before initializing lookup maps ([8c4dd5b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8c4dd5b3a309077fa9a3827b4931fc28b0517809))
* Merge extension only when patch executes ([#315](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/315)) ([aa472eb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/aa472eb9857145b53b49f843406a9764fbb7e5ce))
* Merge integrations when required ([06c2b76](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/06c2b76f11ac1bfe43d51d54d425e7577ecefdf6))
* **MethodResolver:** fix cd57a8c9a0db7e3ae5ad0bca202e5955930319ab ([cbd8df2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/cbd8df2df008ef37c6b43e2a8442c41f24be9358))
* **MethodResolver:** strip labels and line numbers so opcode patterns match ([699c730](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/699c730a7cecf31878827d645e845490a37de4cb))
* **MethodResolver:** strip labels nodes so opcode patterns match ([82c5306](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/82c530650f926dd026d263cfe23a7d67cb27bbf2))
* MethodSignature#resolved throwing an exception ([c612676](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c612676543282155143471b71a095e26023806ea))
* missing additional items [skip ci] ([0ebab8b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0ebab8bf598d993df6e340651205cba48f1ef725))
* more useful error message ([4b2e323](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4b2e3230ec74fa3a57ae86067e5cb7cecbe45013))
* Move proxy package out of cache package ([ce21bd6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ce21bd60f34d78b94d6d85f2c5375bc934ed4091))
* move version properties file to correct package ([e985676](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e985676c2d8e5d6cb907d371de30428caaa6da43))
* mutability of local variable `modified` ([0e87ef5](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0e87ef56c418d5c37d58abb9b27f85e25fd44f81))
* NPE on method lookup ([#195](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/195)) ([fcef434](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/fcef4342e8bde73945e8315aef6337cc8a8d8572))
* null check causing an exception ([338bd9f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/338bd9f7394afd84e5e195a7f8155c813812cfb5))
* nullable signature members ([#10](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/10)) ([674461f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/674461f08daabbf92cb54e4eadb408226fac47af))
* Only allow setting `MethodFingerprint#result` privately ([aed1eac](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/aed1eac3157317acf87f522750cf2f41509606c3))
* only close succeeded patches ([b8151eb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b8151ebccb5b27dd9e06fa63235cf9baeef1c0ee))
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5938f6b7ea25103a0a1b56ceebe49139bc80c6f5))
* only enable logging for ReVanced ([783ccf8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/783ccf8529f5d16aa463982da6977328306232bb))
* only run list option check if not null ([4055939](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4055939c089e3c396c308c980215d93a1dea5954))
* Patch should have access to the Cache ([4dd820f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4dd820ffdf1b98fe41b50f7cb2670b89acfbb99d))
* Patcher not writing resolved methods ([fac44a5](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/fac44a50c39d8c102bd3e7ca4dd1bb86d29f7b57))
* Patcher setting BuildOptions too late ([6a5c873](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6a5c8735fb8a5d6f7e9c606734b6684c7fa99e7f))
* PathOption should be open, not sealed ([a562e47](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a562e476c085841efbc7ee98b01d8e6bb18ed757))
* print full exception when patch fails ([7cf79e6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7cf79e68e0e9dfd9faddee33139b127b71882d3e))
* Print patch name instead of class name ([4e7811e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4e7811ea07762667a1f22526dc176022038f60eb))
* Print stack trace of exception ([aa71146](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/aa71146b1bf4ffebcc81a1663e15abae89e97ff0))
* publicize types when merging files if necessary ([#137](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/137)) ([9ec720e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9ec720e983785d8b1dde330cc0e0e0f914c1803c))
* qualifying `Element` with wrong package ([024fa86](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/024fa867e115f984cfa3e395b78f4f43aa81709b))
* reaching all constructors not possible ([c459beb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c459beb5f898d797f2f03ed36326bd9cfad03d31))
* reformat (trigger release) ([bf48945](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bf4894592bf9ee9c6233abc91f538b7b8ef986a0))
* remove `count` instead of `count + 1` instructions with `removeInstructions` ([#167](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/167)) ([98f8eed](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/98f8eedecd72b0afe6a0f099a3641a1cc6be2698))
* remove broken code ([0e72a6e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0e72a6e85ff9a6035510680fc5e33ab0cd14144f))
* remove default param from Package.versions ([4b81318](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4b813187107e85dc267dbc2d353884b2cc671cc4))
* remove dependency to fork of Apktool ([11abc67](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/11abc67d9ab7d7b273fd4cd4c53af54008a80585))
* remove javadoc jar (also trigger release) ([56f6ca3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/56f6ca38919b522c0d5558eabffa4aee41cc0b0b))
* remove leftover debug code ([0f30eac](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0f30eac32ce66d8b90906c02ef7e7854feeecc33))
* Remove log management ([d51bc32](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d51bc32e37a865194c3825471085b3ccf8c78421))
* remove repeatable from PatchDeprecated ([6e73631](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6e73631d4d21e5e862f07ed7517244f36394e5ca))
* remove requirement for solution [skip ci] ([#80](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/80)) ([9a4d30e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9a4d30e15234ef62844f035c58a1143674d4c12e))
* remove unnecessary dummy nop instructions ([#111](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/111)) ([f9bc95f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f9bc95f220aa434308ce6950ba6ad2e7efac9c8a))
* Replace original classdef with proxy class immediately ([0f198c4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0f198c4428509df0478985c77e2e2fb13fe8b37c))
* resolve failing builds ([a263fdf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a263fdfd413fc05098e28d4800e36ce7d313085b))
* resource patcher ([31815ca](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/31815ca9ea990f16b3600d61fd570c1805be1c82))
* Retain existing null opcode behavior ([e2707e1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e2707e179f02cf4c61e7f3c58731199c34b6855d))
* return mutable set of classes ([66a9b76](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/66a9b768457e98fdde0b61f9a8d6aed4c1872027))
* return resourceFile to caller ([1f75777](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1f75777cf985bf08483033ec541937d3e733347b))
* returning failure on success ([48c4ea2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/48c4ea2f6d9de319383a49ea2d4c6ffb4f687a2b))
* revert soft dependencies ([7b2d058](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7b2d058144b0718992d329731e2af7cc704e4370))
* revert using `OutputStream.nullOutputStream` ([f02a426](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f02a42610b7698fc8cc6bc5183c9ccba2ed96cda))
* Run code-block if `executablePatches` does not yet contain `patch` ([1d7aeca](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1d7aeca696be873dfaf88eaa6d312949a3b8572b))
* Search method map for existing class proxy ([a1e909b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a1e909b16337c538f8f8b475801d8b1804163bfe))
* set index for insertAt to 0 by default ([d5b4c99](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d5b4c99c00272e3e5afec2fa0a489ba618f2a81a))
* set marklimit to Integer.MAX_VALUE ([e6e468f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e6e468fbb5c20b08c8bd59bafc794acea907e4b4))
* set package metadata correctly ([02d6ff1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/02d6ff15fe87c2352de29749610e9d72db8ba418))
* set resource table via resource decoder ([e0f8e1b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e0f8e1b71a295948b610029c89a48f52762396b6))
* show error message if cause is null ([f9da2ad](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f9da2ad531644617ad5a2cc6a1819d530e18ba22))
* show error message instead of `null` ([8d95b14](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8d95b14f350b47ec029f35e776f6e627aaf5f607))
* string signature in `SignatureResolver` ([e5ae970](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e5ae9700096924e63b15a08079dce40ae07202d8))
* supply the parent classloader to `DexClassLoader` ([0f15077](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0f15077225600b65200022c1a318e504deb472b9))
* Support UTF-8 chars when compiling instructions in Smali in non UTF-8 environments ([#331](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/331)) ([bb8771b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bb8771bb8b8ab1724d957e56f4de88c02684d87b))
* Suppress logger when loading patches in `PatchBundleLoader` ([72c9eb2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/72c9eb212985f99f3390cf1faa10ab547d2dbe7e))
* Suppress unused for addFiles ([3d6a1d3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3d6a1d38f339ce2c5d82b7ac46c208c6702d6d44))
* Temporarily turn off failing tests ([a3852a6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a3852a6e9b36be637ca8121096f36ddb9a14e683))
* **tests:** access `patternScanResult` through `scanResult` ([76676fb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/76676fb5673a9e92517ee3a13943cdc98dd5102a))
* throwing in case the opcode patterns do not match ([3144ec8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3144ec872ac8651b8c0a9311ae508d5c3cc734ce))
* typo in ListOption ([3921648](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/392164862c83d6e76b2a2113d6f6d59fef0020d1))
* update apktool ([ab866bb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ab866bb8ef4792d8f2a51edc79e687b5b636c621))
* update apktool ([051afd9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/051afd98d065f71556392139d77c20b4c2dc7dd1))
* update apktool to fork ([566ecef](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/566ecefa2bd4cde5ebfb2b22dc56cd8bf9f396bd))
* update dependency `app.revanced:multidexlib2` ([#150](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/150)) ([dd7dd38](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/dd7dd383577dcfc95e97f77b446a89b41b589dc0))
* use `Exception` instead of `MethodNotFoundException` ([2fc4ec4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/2fc4ec40217a917ea6106ddc87be332f725aa13c))
* use `MethodUtil.methodSignaturesMatch` instead of `Method.softCompareTo` ([bd053b7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bd053b7e9974c0282d56e6762459db7070452e4a))
* Use `Patch#toString` to get patch class name, when no name available ([c9a8260](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c9a82608f7f2d6b3e64c0c949ea5d9f76fa46165))
* use `versionCode` if `versionName` is unavailable ([6e1b647](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6e1b6479b677657c226693e9cc6b63f4ef2ee060))
* use Array instead of Iterable for methodParameters ([dfac8f0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/dfac8f03a362fd273527f552d9eae121505fd4e0))
* Use correct module name ([080fbe9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/080fbe9feb9d4ea9ec4e599ecef296eacd803b05))
* Use correct super class type ([f590436](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f590436399f6385c51cea54618251b5d823c31f9))
* use instruction index instead of strings list index for `StringMatch` ([843e62a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/843e62ad290ee0a707be9322ee943921da3ea420))
* Use non-nullable type for options ([ea6fc70](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ea6fc70caab055251ad4d0d3f1b5cf53865abb85))
* Use null for compatible package version when adding packages only ([736b3ee](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/736b3eebbfdd7279b8d5fcfc5c46c9e3aadbee12))
* using old instance of `Androlib` when saving ([a4d8be2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a4d8be20fcd444b08ec9c43f9f7029f8bacbbc41))
* Validate 1 or more instructions or opcodes ([6c58248](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6c582484a242ba4bc39e39d31897c385dcba5cef))
* version not working with apktool due to cache ([03f5ee0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/03f5ee088b1b96b88cb7aeb323443b6209a13950))
* workflow on dev branch ([428f7f4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/428f7f4decb00d28c9bf137ef4cd1d5fd4a0821e))
* write all classes ([f068fc8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f068fc87ff8e204826639318af39e48e683254da))
* wrong value for iterator in PatchOptions ([e31ac1f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e31ac1f132df56ba7d2f8446d289ae03ef28f67d))

### Code Refactoring

* bump multidexlib2 to 2.5.2.r2 ([a6c6b49](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a6c6b4979af42936cb26608541a4f7a66393b3f0))
* Change `PatchOption` from abstract to open class ([09cd6aa](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/09cd6aa568988dd5241bfa6a2e12b7926a7b0683))
* Change all references from Array to Iterable ([72f3cad](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/72f3cad3f98001b0109b07373ed9cc57a9001cfa))
* Change data classes to actual classes ([6192089](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6192089b71bdca15765369f3e607ddd1f8266205))
* Convert extension functions to member functions ([e2ca507](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e2ca50729da7085799c0ff6fc4f7afaf82579738))
* convert Patch to abstract class ([cb9b1b9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/cb9b1b9416c699c68d0fca228d4f8ca6fb634cb5))
* Improve Patch Options ([6b909c1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6b909c1ee6b8c2ea08bbca059df755e2e5f31656))
* improve structure and public API ([6b8977f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6b8977f17854ef0344d868e6391cb18134eceadc))
* improve structuring of classes and their implementations ([4aa14bb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4aa14bbb858af9253eae9328b759f3298b65a215))
* Internalize processor constructor ([a802d0d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a802d0df463695976e85d8391762942eb977920b))
* migrate from `Signature` to `Fingerprint` ([efa8ea1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/efa8ea144528fcff588e782468845c315a7d6abd))
* Move files to simplify package structure ([124a2e9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/124a2e9d3efb88f0f038ae306d941e918ad3ad3c))
* Optimize Signature class ([#11](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/11)) ([7faa001](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7faa001406c1f28dc2182cf6d1ab19504f4e3eb9))
* Remove deprecated classes and members ([a4212f6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a4212f6bf952971541c4550e20f6bf57a382e19a))
* Rename `net.revanced` to `app.revanced` ([7087230](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/70872307e33282b37dd5fb315b56022ab73bf582))

### Features

* `Closeable` patches ([bbd40bf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bbd40bf2f6ff200705f2bcb272dd1680bb244e3f))
* `Dependencies` annotation ([893d4c6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/893d4c699bad4c70002fc691c261447d01948b5c))
* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ad6c5c827389d10eae473dc66557a699df8c3280))
* `PatchLoader` ([ec9fd15](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ec9fd15f9b9b9968be7fb5cb384eb8ee2a0c9ba3))
* Add 'classFingerprint' (parent fingerprint) ([4d38837](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4d388372327af960c569d085341a63412f787f75))
* Add `findParentMethod` utility method ([#4](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/4)) ([bbb2c54](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bbb2c547aae8dd774a1a883de24fe45da463fa35))
* add `MethodWalker` ([7755bbc](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7755bbc645773e49053fb9ad2b6fd18a7f488659))
* add `MutableMethod.getInstructions` extension function ([fae4029](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/fae4029cfccfad7aa3dd8f7fbef1c63ee26b85b3))
* add `p` naming scheme to smali compiler ([79909cf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/79909cf260c0578e88ad22d63397957dbaa91702))
* Add `PatchExtensions#registerNewPatchOption` function to simplify instantiation and registration of patch options ([4a91845](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4a9184597be99cd458496cce0ee68994e6b8735c))
* Add `PatchOption#valueType` to handle type erasure ([a46e948](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a46e948b5a0cf9bc8d31f557e371cd7d7c2f5b1c))
* Add ability to create options outside of a patch ([d310246](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d310246852504b08a15f6376bbf25ac7c6fae76f))
* add appreciation message for new contributors ([d674362](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d67436271ddca9ccfe008272c1ca82c6123ae7ee))
* Add constructor to initialize patches without annotations ([462fbe2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/462fbe2cadf56d8b0dde33319256021093bd39d5))
* add extensions for cloning methods ([01bfbd6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/01bfbd656ee06cb2cab951c43d7f76a465a40830))
* add findClass method with className ([4087f49](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4087f498638ee88ba3eaca792039fe481f404732))
* Add first tests ([544bcf7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/544bcf76bd8a8c790c2f799606ad8c9ac7d2aa82))
* Add function to reset options to their default value ([ebbaafb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ebbaafb78e88f34faeafe9ff8532afe29231bd79))
* Add function to reset options to their default value ([e6de90d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e6de90d300bc9c82ca1696cb898db04c65a1cd5b))
* add fuzzy resolver ([7a56dca](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7a56dca004cd793121a59ea854c77f4c1a01bd6f))
* Add getter for default option value ([c7922e9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c7922e90d0c6ae83f513611c706ebea33c1a2b63))
* add getValue & setValue for PatchOption ([2572cd0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/2572cd04b5da4eeae738c8dde31493177edf0bf8))
* Add identity hash code to unnamed patches ([88a3252](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/88a325257494939a79fb30dd51d60c5c52546755))
* add immutableMethod ([c63b20f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c63b20fa65aba8bb060a4a7a652747cba7198c2b))
* add inline smali compiler ([bfe4e3e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/bfe4e3e298ac963936ca9621e12aefbe56260826))
* add missing setter to `MutableMethod` ([8f3ecc3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8f3ecc318c39f0270aff53efdee7a1c8d82af421))
* add missing test for fields ([6b8b057](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6b8b0573d479e227b45dc36a6abac622c3ccebdd))
* Add option to use single threaded writer for dex files ([77dbee3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/77dbee3d6ae7b8dc77543e036624daa68ae63504))
* add or extension for AccessFlags ([00c85b5](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/00c85b5d750ccc8de69ad4101220b19eeaf99bcb))
* add overload to get instruction as type ([49c173d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/49c173dc14137ddd198a611e9882dc71300831ee))
* Add patch annotation processor ([#231](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/231)) ([a29931f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a29931f2ec0a666dba209b54855425d9dc2f4462))
* Add patch metadata ([642e903](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/642e9031eb3727ebdca22c75b7c5c602a8775da0)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
* add Patch#dependsOn extension ([523f67b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/523f67b238646caaa9b7676a0e238ce82adbdda4))
* add PathOption back ([172655b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/172655bde06efdb0955431b44d269e6a64fe317a))
* add replace and remove extensions ([#50](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/50)) ([92ac5e4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/92ac5e4dc25f612856e2b5e528cf5fd48a5f20af))
* add SafeClassWriter ([6626014](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6626014ef3dde2f98a53f75d71eeb0de85189bf3))
* Add warnings for Fuzzy resolver ([715a2ad](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/715a2ad025d127b5a8225ce50202a859f53c7f50))
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([1db735b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1db735b1e2b570bdb1ddce0b9cd724c580113a84))
* allow custom aapt path to be specified ([8eb4a8f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8eb4a8f87ae7679a272f3224273a37a31d4bb121))
* allow custom framework path to be specified ([d3a580e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d3a580ea19d7c2d5d8c97650b1e6396ea0a7fc25))
* Allow unknown opcodes using `null` ([0e5f4ba](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0e5f4ba2d55288415c4d1be70ab6a8ab8c1c0d10))
* apply changes from ReVanced Patcher ([ba9d998](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ba9d99868103406fe36b9aa0cfaa0ed5023edfab))
* Convert APIs to Kotlin DSL ([#298](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/298)) ([11a911d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/11a911dc674eb0801649949dd3f28dfeb00efe97))
* default value for `Package.versions` annotation parameter ([131dedd](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/131dedd4b021fe1c3b0be49ccba4764b325770ea))
* Deprecate `Version` annotation ([c9bbcf2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c9bbcf2bf2b0f50ab9100380a3a66c6346ad42ac))
* deprecation for patches ([80c2e80](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/80c2e809251cdb04d2dd3b3bfdbb8844bdfa31fa))
* do not fix methods or methods in class merger ([4102f43](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4102f43b8a9473fd0ee96c5d4fb8f6e9b4e30e70))
* do not log instantiation of ReVanced Patcher ([273dd8d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/273dd8d388f8e9b7436c6d6145a94c12c1fabe55))
* exclusive mutable access to files ([814ce0b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/814ce0b9ae29725417c86b7d11b40d025724a426))
* feature request issue template ([1b39278](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1b39278b24ba2f964d93bd8ad2e28472ee036d90))
* Finish first patcher test ([0d8d19e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0d8d19e708a47315e28e7493618568ea40f1e062))
* fix method and field access when merging classes ([5c09ef7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5c09ef7837f9b731e137b66c19da77f63c007595))
* Improve `SignatureResolver` ([139a23b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/139a23b7500a2d2577df47caf3fd0c5ec891a8d8))
* Improve Fingerprint API ([#316](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/316)) ([0abf1c6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0abf1c6c0279708fdef5cb66b141d07d17682693))
* improve logging ([c20dfe1](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c20dfe12d5c737264b844e6634de11bf1e1629f0))
* Improve Smali Compiler ([6bfe571](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6bfe5716c38181bbe9476b5c6ad29526edb4e022))
* Improve various APIs  ([#317](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/317)) ([b824978](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b8249789df8b90129f7b7ad0e523a8d0ceaab848))
* improved Patch Options ([e722e3f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e722e3f4f9dc64acf53595802a0a83cf46ee96b8))
* issue templates [skip ci] ([112bc99](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/112bc998f4761a647cb9eab7454e35264fa96fd9))
* load patches in lexicographical order ([e8f2087](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e8f2087a6ffa6077fb3a6a69e29f3aec72e2fc1b))
* log failed patches due to failed dependencies ([a467fbb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a467fbb704eebe812cdec14025398dab2af43959))
* log when merging integrations ([983563e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/983563efb6d7c8d289464b8bf71a016b8a735630))
* logging class ([caf2745](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/caf2745805ffd4b59fa81e79cc489b1a1a5c5d89))
* make `aaptPath` nullable ([#146](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/146)) ([9f0a09a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9f0a09a7569fd5dd78afa27cb66a73d1662edc69))
* Make `PatchOption#values` nullable ([56ce9ec](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/56ce9ec2f98ff351c3d42df71b49e5c88f07e665))
* Match fingerprints by instruction filters ([31f6122](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/31f61222d7bd2f96f357fa6ebf8e544ab653215d))
* merge classes on addition ([#127](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/127)) ([a925650](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a9256500440f9b4117f1b8813ba0097dafee4ebb))
* migrate logger to `slf4j` ([8f66f9f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8f66f9f606a785ac947b0e553822877f211d82df))
* migrate to `DexPatchBundle` and `JarPatchBundle` ([8615798](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8615798711185b30ce622d9d09faba21f3a92f97))
* migrate to dexlib ([3651981](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/36519811610192e299834e9d00627a94faad56a9))
* Minor refactor and return proxy, if class has been proxied already ([4b26305](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4b26305bd57ba9e3eb3e34218ffe10d6c5a2f598))
* Move fingerprint match members to fingerprint for ease of access by using context receivers ([0746c22](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0746c22743a9561bae2284d234b151f2f8511ca5))
* Name patch option value validator property correctly ([caa634f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/caa634fac6d7a717f54e3b015827c8858fd637b9))
* nullability for `BytecodePatch` constructor ([#59](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/59)) ([4ea030d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4ea030d0a03f736bbecbd491317ba2167b18fe94))
* nullable parameters ([7882a8d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7882a8d928cad8de8cfea711947fc02659549d20))
* optional `forStaticMethod` parameter for `InlineSmaliCompiler.compileMethodInstructions` ([41e8860](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/41e88605c33d1f0d9e7f5466cac03a3b339afb82))
* patch dependencies annotation and `PatcherOptions` ([6c65952](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6c65952d80a795a3ef4a37877123e9375025d3ae))
* patch options ([#81](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/81)) ([fbb09f3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/fbb09f38dce49adc7f63b71bdf2df2ef0b84db04))
* PatchOptions#nullify to nullify an option ([371f0c4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/371f0c4d0bf96e7f6db35085efccaed3000a096c))
* properly make use of logging facade ([ba56a6a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ba56a6a2eef503c0d6cdd846ddce2e1474d8ed1a))
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([6cb1fdf](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6cb1fdf6171e1ab75b7ee28163965eacc00cc5a0))
* Read and write arbitrary files in APK files ([f1d7217](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f1d72174956c42234664dce152a27e6854e347e2))
* registry for patch options ([2431785](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/2431785d0e494d6271c6951eec9adfff9db95c17))
* remaining mutable `EncodedValue` classes ([3f97cc8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3f97cc8e1fa10546d7069e01e5e66a537b0d6f7e))
* remove `Path` option ([#202](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/202)) ([69e4a49](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/69e4a490659ebc4fb4bf46148634f4b064ef1713))
* remove deprecated functions ([ada5a03](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/ada5a033de3cf94e7255ec2d522520f86431f001))
* Remove patch annotation processor ([4456031](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/445603145979a6f67823a79f9d6cd140299cff37))
* remove unused annotation `DirectPatternScanMethod` ([538b2a8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/538b2a859962570c700362afc88704ed3611aa87))
* remove unused annotation `SincePatcher` ([4ae9ad0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4ae9ad09d64a3f69512ccb037f816cb847d7350f))
* remove unused extension `dependsOn` ([797286b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/797286b7588646272dea2fd35e8e78b0ffb18a0f))
* remove unused patch extensions ([5583904](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/55839049948033ad02414517fd3ba03619216aec))
* Retrieve annotations in super and interface classes ([7aeae93](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/7aeae93f3d9a13e294fe1bdb2586f79908af60af))
* return a `File` instance instead of `ExtFile` ([68174bb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/68174bbd6b4df47a91b610c2b97dbae55b594163))
* RwLock for opening files in `DomFileEditor` ([db4348c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/db4348c4faf51bfe29678baacfbe76ba645ec0b9))
* section `acknowledgements` for issue templates ([a0cb449](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a0cb449c60310917141e2809abaa16b4174dc002))
* simplify adding instructions ([e47b67d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e47b67d7ec521f288644afb89baf4146dc9bc87d))
* SincePatcher annotation ([25f74dc](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/25f74dc5e9ed1a09258345b920d4f5a0dd7da527))
* Soft Dependencies for Patches ([8c12f8d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/8c12f8d488f939cc932e826aad0b20876ae165b7))
* sort patches in lexicographical order ([a306561](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a306561b55ac848792046378f582a036f7ffab03)), closes [#125](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/125)
* streams overload for `XmlFileHolder` ([6f72c4c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6f72c4c4c051e48c8d03d2a7b2cfc1c53028ed86))
* string signature ([#22](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/22)) ([612515a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/612515acf8539febf952f258d30aa3d4b631e3b7))
* Use a map for `PatchOption#values` ([54ac139](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/54ac1394a914d3eed7865ec697e8016834134911))
* use annotations instead of metadata objects ([d20f7fd](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d20f7fd6e1ede6ec7baccb1500ab3fc66d78df73))
* Use option name as key for simplicity and consistency ([754b02e](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/754b02e4ca66ec10764d5205c6643f2d86d0c6a2))
* use streams to write the dex files ([64bae88](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/64bae884dcb72550a3218e149f3ca0fd0ca03aaf))
* utility functions to get metadata of patch & sigs ([54511a4](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/54511a4fc6417d7fe0c868d441e7d6b0ec9e218d))
* validator for patch options ([4e2e772](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4e2e77238957d7732326cfe5e05145bf7dab5bfb))
* yield the patch result ([dde5385](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/dde5385232abddc8a85d6e9a939549b71dd9130e))

### Performance Improvements

* check type instead of class ([c7ef264](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/c7ef2644d83e1d8e84decb0631a6549d394180fc))
* compare types of classes ([55d6945](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/55d694579ac2718b9e2c61ca5f38419c3775ef87))
* Copy strings only if strings are found ([f5a1b26](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f5a1b269334a3dd481f3c669dccfdce2b70c01f3))
* decode manifest only when not using resource patcher ([4f60bea](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4f60bea81e0bbe85dc6c3150238980292a1e52ab))
* decode resources only when necessary ([3ba4be2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/3ba4be240bf0a424e4bbfbaca9605644fda0984e))
* depend on `androlib` instead of `ApkDecoder` ([cc9416d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/cc9416dd11b66140c2882021cbe5088659d85371))
* do not resolve empty signatures list ([b1eebc9](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b1eebc99a71269df33c37f35c1f56ea20a9d6bc0))
* Do not unnecessary resolve fingeprints twice ([#241](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/241)) ([4d6e08a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4d6e08a650dde6ec2e18611c5db1ab92b9a61dd1))
* **fingerprint:** do not resolve already resolved fingerprints ([4bfd7eb](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/4bfd7ebff8b6623b0da4a46d6048bed08c5070d4))
* Free memory earlier and remove negligible lookup maps ([d53aacd](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d53aacdad4ed3750ddae526fb307577ea36e6171))
* If no exact strings match, then check all methods that contain strings ([102eac5](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/102eac5beaa8c3cc1b524fa9933f431a90f1e2c6))
* If using partial string matches then only check classes with strings ([b7288b0](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/b7288b07d41ec2ae34a782724062a00e7fe8f730))
* lazy-ify all mutable clones ([d18a3b6](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d18a3b6a28cae4fcb1c4986903208298ee50b083))
* make exception an object ([75d2be8](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/75d2be88037c9cf5436ab69d92abea575409a865))
* optimize indexOf call away ([9991f39](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9991f39c9a4fa22a221aab0bbf9e08ca7f967fa9))
* resolve fingerprints using method maps ([#185](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/185)) ([d718134](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d718134ab26423e02708e01eba711737f9260ba0))
* Run the garbage collector after writing dex files ([d9fb241](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d9fb241d57b0c4340130c0e5900250e66730ea56))
* Skip return type check if access flags include constructor ([a0a0306](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/a0a0306d448b79125f275c330051821f30ca57d3))
* Tweak filtering of string literals ([72a6319](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/72a6319dc3f2792bcdc4b2ad8dd4daab7545bf5a))
* Use a buffered writer to reduce IO overhead ([#347](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/347)) ([99f4318](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/99f431897eb9e607987fd5d09b879d7eda442f3e))
* Use a hash set for fast lookup ([f1de9b3](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/f1de9b39eff1db44c00acd3e41902b3ec6124776))
* Use a map to merge integrations classes ([6059d3c](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/6059d3ca2685cb659023b171b95d4b9d279c6e53))
* Use a more performant class map load factor (10% faster patching of YT) ([9b6d95d](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/9b6d95d4f414a35ed68da37b0ecd8549df1ef63a))
* use Set instead of List since there are no dupes ([e65ebd2](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e65ebd27c250b1735acf73af0f6b03274b0137f6))
* Use smallest lookup map for strings ([1358d3f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/1358d3fa10cb8ba011b6b89cfe3684ecf9849d2f))
* use String List and compare instead of any lambda ([5bd416b](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/5bd416b409290906a6378344f70391e8692ae27f))

### Reverts

* AccessFlag extensions not working with IDE ([0bfb92a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/0bfb92a0cbd72df5ba513264efb583e201cfcf82))
* previous commits check for dupes in dexFile, not cache ([e810197](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/e810197e2aa64534f2e8637165d884cbefbce8ae))
* propagate dependencies ([365e1d7](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/365e1d7a4507b918a4c8170ce2c88f6c8ff1d474))
* Revert "build: Bump dependencies" ([d792240](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/d7922404bb9e769a034bd14d45b6600cc0f7a073))
* Revert "feat: Add 'classFingerprint' (parent fingerprint)" ([502ea98](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/502ea982acf5ddcd34e8d0a90d21055b3766ce3b))
* Revert "refactor: Change `ByteCodePatchContext` to a singleton object, remove `[@context](https://github.com/context)` usage, simplify instruction filter block calls." ([cfb873a](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/cfb873a73599ab533a685b4276171d6043009646))
* Revert "refactor: Deprecate pure opcode declarations"  It's still useful to sometimes use only opcodes and declaring entirely as instruction() is a lot of boilerplate code. ([5885984](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/58859846578673e3125cf8df532da7a4578b1296))
* revert breaking changes ([#106](https://github.com/LisoUseInAIKyrios/revanced-patcher/issues/106)) ([124332f](https://github.com/LisoUseInAIKyrios/revanced-patcher/commit/124332f0e9bbdaf4f1aeeb6a31333093eeba1642))

### BREAKING CHANGES

* Various APIs have been changed.
* Many APIs have been changed.
* Various old APIs are removed, and DSL APIs are added instead.
* This changes the signature of the `PatchOption` constructor.
* The `MethodFingerprint#result` member can now only be set inside `MethodFingerprint`.
* The `Fingerprint` interface is no longer present.
* Some extension functions are now member functions.
* This gets rid of data class members.
* Some deprecated classes and members are not present anymore.
* Classes and members have changed packages.
* This gets rid of the existing basic implementations of the `PatchOptions` type and moves extension functions.
* This changes the getter name of the property.
* Various patch constructor signatures have changed.
* This commit gets rid of deprecated constructors.
* This changes the super classes of some `PatchOptionException` classes
* This gets rid of the public constructor.
* `PatchBundleLoader` is not a map anymore
* This renames packages and the Maven package.
* The manifest for patches has been removed, and the properties have been added to patches. Patches are now `OptionsContainer`. The `@Patch` annotation has been removed in favour of the `@Patch` annotation from the annotation processor.
* Patch annotations have been removed. PatcherException is now thrown in various places. PatchBundleLoader is now a map of patches associated by their name. Patches are now instances.
* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
* This bump updates smali, a crucial dependency
* This removes the previously available `Path` option
* This changes the import paths for extension functions.
* This changes the names of extension functions
* This changes the name of functions
* This requires changes to `MethodFingerprint`
* This changes named parameters.
* This changes the signature of the `customFingerprint` function.
* `Patcher.addFiles` is now renamed to `Patcher.addIntegrations`

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
* various changes in which packages classes previously where and their implementation
* These extensions do not exist anymore and any use should be removed
* The extension does not exist anymore and any use should be removed
* The annotation does not exist anymore and any use should be removed
* Imports will have to be updated from `MethodFingerprintUtils` to `MethodFingerprint.Companion`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
* `MethodFingerprint` now has a field for `MethodFingerprintScanResult`. `MethodFingerprintScanResult` now holds the previous field `MethodFingerprint.patternScanResult`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
* Options has been moved from Patch to a new interface called OptionsContainer and are now handled entirely different. Make sure to check the examples to understand how it works.
* Patch options now use the PatchOptions registry class instead of an Iterable. This change requires modifications to existing patches using this API.
* Not backwards compatible, since a lot of classes where renamed.
* arrayOf has to be changed to listOf.
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
* Removed usage of ASM library
* Array<Int> was changed to IntArray. This breaks existing patches.
* Package name was changed from "net.revanced" to "app.revanced"
* Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
* Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
github-actions bot pushed a commit that referenced this pull request Feb 20, 2026
# [22.0.0](v21.0.0...v22.0.0) (2026-02-20)

* feat!: Replace fingerprint with matching and add Kotlin DSL to patcher API ([#385](#385)) ([c638090](c638090))

### Bug Fixes

* Add back missing log by naming logger correctly ([#332](#332)) ([e4e66b0](e4e66b0))
* Correctly save XML files in UTF-8 by using a bufferedWriter ([#356](#356)) ([33fadcb](33fadcb))
* Encode XML files as UTF-8 to fix compilation of resources ([#339](#339)) ([4f2ef3c](4f2ef3c))
* Return first indexed matcher indices as CompositeMatch.component2 ([c9796a8](c9796a8))
* Support UTF-8 chars when compiling instructions in Smali in non UTF-8 environments ([#331](#331)) ([bb8771b](bb8771b))

### Features

* Add identity hash code to unnamed patches ([88a3252](88a3252))
* Use option name as key for simplicity and consistency ([754b02e](754b02e))

### Performance Improvements

* Use a buffered writer to reduce IO overhead ([#347](#347)) ([99f4318](99f4318))

### BREAKING CHANGES

* Some APIs have been changed or removed, but most are deprecated and have backwards compatibility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants