fix(tiktok/settings): make compatible with newer versions (#1057)

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
d4rkk3y 2022-11-20 23:09:59 +07:00 committed by GitHub
parent 50977c01a2
commit 54cea3d5d0
4 changed files with 106 additions and 61 deletions

View file

@ -0,0 +1,18 @@
package app.revanced.patches.tiktok.misc.settings.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility
@Name("about-onclick-method-fingerprint")
@TikTokSettingsCompatibility
@Version("0.0.1")
object AboutOnClickMethodFingerprint : MethodFingerprint(
strings = listOf(
"//setting/about",
"enter_from",
"settings_page",
"enter_settings_about"
)
)

View file

@ -5,10 +5,10 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility
@Name("ad-personalization-activity-fingerprint") @Name("ad-personalization-activity-on-create-fingerprint")
@TikTokSettingsCompatibility @TikTokSettingsCompatibility
@Version("0.0.1") @Version("0.0.1")
object AdPersonalizationActivityFingerprint : MethodFingerprint( object AdPersonalizationActivityOnCreateFingerprint : MethodFingerprint(
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/AdPersonalizationActivity;") && methodDef.definingClass.endsWith("/AdPersonalizationActivity;") &&
methodDef.name == "onCreate" methodDef.name == "onCreate"

View file

@ -8,7 +8,7 @@ import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompa
@Name("copyright-settings-string-fingerprint") @Name("copyright-settings-string-fingerprint")
@TikTokSettingsCompatibility @TikTokSettingsCompatibility
@Version("0.0.1") @Version("0.0.1")
object CopyRightSettingsStringFingerprint : MethodFingerprint( object SettingsOnViewCreatedFingerprint : MethodFingerprint(
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/SettingNewVersionFragment;") && methodDef.definingClass.endsWith("/SettingNewVersionFragment;") &&
methodDef.name == "onViewCreated" methodDef.name == "onViewCreated"

View file

@ -5,6 +5,7 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
@ -14,85 +15,111 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.tiktok.misc.integrations.patch.TikTokIntegrationsPatch import app.revanced.patches.tiktok.misc.integrations.patch.TikTokIntegrationsPatch
import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility
import app.revanced.patches.tiktok.misc.settings.fingerprints.AdPersonalizationActivityFingerprint import app.revanced.patches.tiktok.misc.settings.fingerprints.AboutOnClickMethodFingerprint
import app.revanced.patches.tiktok.misc.settings.fingerprints.CopyRightSettingsStringFingerprint import app.revanced.patches.tiktok.misc.settings.fingerprints.AdPersonalizationActivityOnCreateFingerprint
import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsOnViewCreatedFingerprint
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.iface.reference.StringReference import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.iface.reference.TypeReference
@Patch @Patch
@DependsOn([TikTokIntegrationsPatch::class]) @DependsOn([TikTokIntegrationsPatch::class])
@Name("tiktok-settings") @Name("settings")
@Description("Add settings menu to TikTok.") @Description("Adds settings for ReVanced to TikTok.")
@TikTokSettingsCompatibility @TikTokSettingsCompatibility
@Version("0.0.1") @Version("0.0.1")
class TikTokSettingsPatch : BytecodePatch( class TikTokSettingsPatch : BytecodePatch(
listOf( listOf(
AdPersonalizationActivityFingerprint, AdPersonalizationActivityOnCreateFingerprint,
CopyRightSettingsStringFingerprint SettingsOnViewCreatedFingerprint,
AboutOnClickMethodFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
//Replace string `Copyright Policy` to 'Revanced Settings` in TikTok settings. // Patch Settings UI to add 'Revanced Settings'.
val method1 = CopyRightSettingsStringFingerprint.result!!.mutableMethod val targetIndexes = findOptionsOnClickIndex()
val implementation1 = method1.implementation!! with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) {
for ((index, instruction) in implementation1.instructions.withIndex()) { for (index in targetIndexes) {
if (instruction.opcode != Opcode.CONST_STRING) continue if (
val string = ((instruction as ReferenceInstruction).reference as StringReference).string instruction(index).opcode != Opcode.NEW_INSTANCE ||
if (string != "copyright_policy") continue instruction(index - 4).opcode != Opcode.MOVE_RESULT_OBJECT
var targetIndex = index )
while (targetIndex >= 0) { return PatchResultError("Hardcode offset changed.")
targetIndex-- patchOptionNameAndOnClickEvent(index, context)
val invokeInstruction = implementation1.instructions[targetIndex] }
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue }
val methodName = ((invokeInstruction as Instruction35c).reference as MethodReference).name // Implement settings screen in `AdPersonalizationActivity`
if (methodName != "getString") continue with(AdPersonalizationActivityOnCreateFingerprint.result!!.mutableMethod) {
val resultInstruction = implementation1.instructions[targetIndex + 1] for ((index, instruction) in implementation!!.instructions.withIndex()) {
if (resultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) continue if (instruction.opcode != Opcode.INVOKE_SUPER) continue
val overrideRegister = (resultInstruction as OneRegisterInstruction).registerA val thisRegister = (instruction as Instruction35c).registerC
method1.replaceInstruction( addInstructions(
targetIndex + 1, index + 1,
""" """
const-string v$overrideRegister, "Revanced Settings" invoke-static {v$thisRegister}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->initializeSettings(Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;)V
return-void
""" """
) )
break break
} }
//Change onClick to start settings activity.
val clickInstruction = implementation1.instructions[index - 1]
if (clickInstruction.opcode != Opcode.INVOKE_DIRECT)
return PatchResultError("Can not find click listener.")
val clickClass = ((clickInstruction as ReferenceInstruction).reference as MethodReference).definingClass
val mutableClickClass = context.findClass(clickClass)!!.mutableClass
val mutableOnClickMethod = mutableClickClass.methods.first {
it.name == "onClick"
}
mutableOnClickMethod.addInstructions(
0,
"""
invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V
return-void
"""
)
break
}
//Implement revanced settings screen in `AdPersonalizationActivity`
val method2 = AdPersonalizationActivityFingerprint.result!!.mutableMethod
for ((index, instruction) in method2.implementation!!.instructions.withIndex()) {
if (instruction.opcode != Opcode.INVOKE_SUPER) continue
val thisRegister = (instruction as Instruction35c).registerC
method2.addInstructions(
index + 1,
"""
invoke-static {v$thisRegister}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->initializeSettings(Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;)V
return-void
"""
)
break
} }
return PatchResultSuccess() return PatchResultSuccess()
} }
private fun findOptionsOnClickIndex(): IntArray {
val results = IntArray(2)
var found = 0
with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) {
for ((index, instruction) in implementation!!.instructions.withIndex()) {
// Old UI settings option to replace to 'Revanced Settings'
if (instruction.opcode == Opcode.CONST_STRING) {
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
if (string == "copyright_policy") {
results[0] = index - 2
found++
}
}
// New UI settings option to replace to 'Revanced Settings'
if (instruction.opcode == Opcode.NEW_INSTANCE) {
val onClickClass = ((instruction as Instruction21c).reference as TypeReference).type
if (onClickClass == AboutOnClickMethodFingerprint.result!!.mutableMethod.definingClass) {
results[1] = index
found++
}
}
if (found > 1) break
}
}
return results
}
private fun patchOptionNameAndOnClickEvent(index: Int, context: BytecodeContext) {
with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) {
// Patch option name
val overrideRegister = (instruction(index - 4) as OneRegisterInstruction).registerA
replaceInstruction(
index - 4,
"""
const-string v$overrideRegister, "Revanced Settings"
"""
)
// Patch option OnClick Event
with(((instruction(index) as ReferenceInstruction).reference as TypeReference).type) {
context.findClass(this)!!.mutableClass.methods.first { it.name == "onClick" }
.addInstructions(
0,
"""
invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V
return-void
"""
)
}
}
}
} }