fix(YouTube - Spoof app version): Force old settings menus if spoofing to older app targets (#4490)

This commit is contained in:
LisoUseInAIKyrios 2025-02-22 11:40:06 +02:00 committed by GitHub
parent 33711f74f7
commit 45e7c46dd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 7 deletions

View File

@ -19,6 +19,7 @@ import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.ThemeHelper;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
import app.revanced.extension.youtube.settings.preference.ReturnYouTubeDislikePreferenceFragment;
import app.revanced.extension.youtube.settings.preference.SponsorBlockPreferenceFragment;
@ -63,6 +64,10 @@ public class LicenseActivityHook {
if (Settings.RESTORE_OLD_SETTINGS_MENUS.get()) {
return false;
}
// Spoofing can cause half broken settings menus of old and new settings.
if (SpoofAppVersionPatch.isSpoofingToLessThan("19.35.36")) {
return false;
}
// On the first launch of a clean install, forcing the cairo menu can give a
// half broken appearance because all the preference icons may not be available yet.

View File

@ -405,12 +405,6 @@ public class Settings extends BaseSettings {
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
// Old spoof versions that no longer work reliably.
if (SPOOF_APP_VERSION_TARGET.get().compareTo(SPOOF_APP_VERSION_TARGET.defaultValue) < 0) {
Logger.printInfo(() -> "Resetting spoof app version target");
SPOOF_APP_VERSION_TARGET.resetToDefault();
}
// Migrate renamed enum.
//noinspection deprecation
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {

View File

@ -1,8 +1,29 @@
package app.revanced.patches.youtube.layout.spoofappversion
import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val toolBarButtonFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Landroid/view/MenuItem;")
custom { method, _ ->
method.containsLiteralInstruction(menuItemView) &&
indexOfGetDrawableInstruction(method) >= 0
}
}
internal fun indexOfGetDrawableInstruction(method: Method) = method.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/content/res/Resources;" &&
reference.name == "getDrawable"
}
internal val spoofAppVersionFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)

View File

@ -1,10 +1,16 @@
package app.revanced.patches.youtube.layout.spoofappversion
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
@ -12,7 +18,25 @@ import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal var menuItemView = -1L
private set
internal val spoofAppVersionResourcePatch = resourcePatch {
dependsOn(
resourceMappingPatch
)
execute {
menuItemView = resourceMappings["id", "menu_item_view"]
}
}
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/spoof/SpoofAppVersionPatch;"
@ -24,6 +48,7 @@ val spoofAppVersionPatch = bytecodePatch(
"Patching 19.16.39 includes additional older spoofing targets.",
) {
dependsOn(
spoofAppVersionResourcePatch,
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
@ -62,6 +87,32 @@ val spoofAppVersionPatch = bytecodePatch(
}
)
/**
* If a user really wants to spoof to very old versions with the latest app target
* they can modify the import/export spoof version. But when spoofing the 19.20.xx
* or earlier the Library tab can crash due to missing image resources trying to load.
* As a temporary workaround, do not set an image in the toolbar when the enum name is UNKNOWN.
*/
toolBarButtonFingerprint.method.apply {
val getDrawableIndex = indexOfGetDrawableInstruction(this)
val enumOrdinalIndex = indexOfFirstInstructionReversedOrThrow(getDrawableIndex) {
opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.returnType == "I"
}
val insertIndex = enumOrdinalIndex + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setImageDrawable"
} + 1
addInstructionsWithLabels(
insertIndex,
"if-eqz v$insertRegister, :ignore",
ExternalLabel("ignore", getInstruction(jumpIndex))
)
}
val insertIndex = spoofAppVersionFingerprint.patternMatch!!.startIndex + 1
val buildOverrideNameRegister =
spoofAppVersionFingerprint.method.getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
@ -71,7 +122,7 @@ val spoofAppVersionPatch = bytecodePatch(
"""
invoke-static {v$buildOverrideNameRegister}, $EXTENSION_CLASS_DESCRIPTOR->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$buildOverrideNameRegister
""",
"""
)
}
}