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.patches.tiktok.misc.settings.annotations.TikTokSettingsCompatibility
@Name("ad-personalization-activity-fingerprint")
@Name("ad-personalization-activity-on-create-fingerprint")
@TikTokSettingsCompatibility
@Version("0.0.1")
object AdPersonalizationActivityFingerprint : MethodFingerprint(
object AdPersonalizationActivityOnCreateFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/AdPersonalizationActivity;") &&
methodDef.name == "onCreate"

View file

@ -8,7 +8,7 @@ import app.revanced.patches.tiktok.misc.settings.annotations.TikTokSettingsCompa
@Name("copyright-settings-string-fingerprint")
@TikTokSettingsCompatibility
@Version("0.0.1")
object CopyRightSettingsStringFingerprint : MethodFingerprint(
object SettingsOnViewCreatedFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/SettingNewVersionFragment;") &&
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.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
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.patches.tiktok.misc.integrations.patch.TikTokIntegrationsPatch
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.CopyRightSettingsStringFingerprint
import app.revanced.patches.tiktok.misc.settings.fingerprints.AboutOnClickMethodFingerprint
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.iface.instruction.OneRegisterInstruction
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.reference.MethodReference
import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.iface.reference.TypeReference
@Patch
@DependsOn([TikTokIntegrationsPatch::class])
@Name("tiktok-settings")
@Description("Add settings menu to TikTok.")
@Name("settings")
@Description("Adds settings for ReVanced to TikTok.")
@TikTokSettingsCompatibility
@Version("0.0.1")
class TikTokSettingsPatch : BytecodePatch(
listOf(
AdPersonalizationActivityFingerprint,
CopyRightSettingsStringFingerprint
AdPersonalizationActivityOnCreateFingerprint,
SettingsOnViewCreatedFingerprint,
AboutOnClickMethodFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
//Replace string `Copyright Policy` to 'Revanced Settings` in TikTok settings.
val method1 = CopyRightSettingsStringFingerprint.result!!.mutableMethod
val implementation1 = method1.implementation!!
for ((index, instruction) in implementation1.instructions.withIndex()) {
if (instruction.opcode != Opcode.CONST_STRING) continue
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
if (string != "copyright_policy") continue
var targetIndex = index
while (targetIndex >= 0) {
targetIndex--
val invokeInstruction = implementation1.instructions[targetIndex]
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue
val methodName = ((invokeInstruction as Instruction35c).reference as MethodReference).name
if (methodName != "getString") continue
val resultInstruction = implementation1.instructions[targetIndex + 1]
if (resultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) continue
val overrideRegister = (resultInstruction as OneRegisterInstruction).registerA
method1.replaceInstruction(
targetIndex + 1,
// Patch Settings UI to add 'Revanced Settings'.
val targetIndexes = findOptionsOnClickIndex()
with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) {
for (index in targetIndexes) {
if (
instruction(index).opcode != Opcode.NEW_INSTANCE ||
instruction(index - 4).opcode != Opcode.MOVE_RESULT_OBJECT
)
return PatchResultError("Hardcode offset changed.")
patchOptionNameAndOnClickEvent(index, context)
}
}
// Implement settings screen in `AdPersonalizationActivity`
with(AdPersonalizationActivityOnCreateFingerprint.result!!.mutableMethod) {
for ((index, instruction) in implementation!!.instructions.withIndex()) {
if (instruction.opcode != Opcode.INVOKE_SUPER) continue
val thisRegister = (instruction as Instruction35c).registerC
addInstructions(
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
}
//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()
}
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
"""
)
}
}
}
}