fix(Spotify): Fix Hide Create button and Sanitize sharing links for older but supported app targets (#5159)

This commit is contained in:
Nuckyz
2025-06-11 17:20:19 -03:00
committed by GitHub
parent 756b28dca0
commit e7dd061c51
5 changed files with 73 additions and 41 deletions

View File

@ -37,20 +37,24 @@ public final class HideCreateButtonPatch {
return null;
}
String stringifiedNavigationBarItem = navigationBarItem.toString();
try {
String stringifiedNavigationBarItem = navigationBarItem.toString();
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
componentFilter.getFilterRepresentation() + " not available, skipping");
continue;
}
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
componentFilter.getFilterRepresentation() + " not available, skipping");
continue;
}
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
" matched the filter " + componentFilter.getFilterRepresentation());
return null;
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " +
navigationBarItem + " matched the filter " + componentFilter.getFilterRepresentation());
return null;
}
}
} catch (Exception ex) {
Logger.printException(() -> "returnNullIfIsCreateButton failure", ex);
}
return navigationBarItem;

View File

@ -202,37 +202,41 @@ public final class UnlockPremiumPatch {
return false;
}
String stringifiedContextMenuItem = contextMenuItem.toString();
try {
String stringifiedContextMenuItem = contextMenuItem.toString();
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
boolean allMatch = true;
StringBuilder matchedFilterRepresentations = new StringBuilder();
for (List<ComponentFilter> componentFilters : CONTEXT_MENU_ITEMS_COMPONENT_FILTERS) {
boolean allMatch = true;
StringBuilder matchedFilterRepresentations = new StringBuilder();
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
ComponentFilter componentFilter = componentFilters.get(i);
for (int i = 0, filterSize = componentFilters.size(); i < filterSize; i++) {
ComponentFilter componentFilter = componentFilters.get(i);
if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
componentFilter.getFilterRepresentation() + " not available, skipping");
continue;
if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "isFilteredContextMenuItem: Filter " +
componentFilter.getFilterRepresentation() + " not available, skipping");
continue;
}
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
allMatch = false;
break;
}
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
if (i < filterSize - 1) {
matchedFilterRepresentations.append(", ");
}
}
if (!stringifiedContextMenuItem.contains(componentFilter.getFilterValue())) {
allMatch = false;
break;
}
matchedFilterRepresentations.append(componentFilter.getFilterRepresentation());
if (i < filterSize - 1) {
matchedFilterRepresentations.append(", ");
if (allMatch) {
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
" because the following filters matched: " + matchedFilterRepresentations);
return true;
}
}
if (allMatch) {
Logger.printInfo(() -> "Filtering context menu item " + stringifiedContextMenuItem +
" because the following filters matched: " + matchedFilterRepresentations);
return true;
}
} catch (Exception ex) {
Logger.printException(() -> "isFilteredContextMenuItem failure", ex);
}
return false;

View File

@ -72,7 +72,7 @@ val hideCreateButtonPatch = bytecodePatch(
if (oldNavigationBarAddItemMethod != null) {
// In case an older version of the app is being patched, hook the old method which adds navigation bar items.
// Return null early if the navigation bar item title resource id is the old Create button title resource id.
// Return early if the navigation bar item title resource id is the old Create button title resource id.
oldNavigationBarAddItemFingerprint.methodOrNull?.apply {
val getNavigationBarItemTitleStringIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
@ -89,6 +89,16 @@ val hideCreateButtonPatch = bytecodePatch(
val isOldCreateButtonDescriptor =
"$EXTENSION_CLASS_DESCRIPTOR->isOldCreateButton(I)Z"
val returnEarlyInstruction = if (returnType == "V") {
// In older implementations the method return value is void.
"return-void"
} else {
// In newer implementations
// return null because the method return value is a BottomNavigationItemView.
"const/4 v0, 0\n" +
"return-object v0"
}
addInstructionsWithLabels(
0,
"""
@ -98,9 +108,7 @@ val hideCreateButtonPatch = bytecodePatch(
# If this navigation bar item is not the Create button, jump to the normal method logic.
if-eqz v0, :normal-method-logic
# Return null early because this method return value is a BottomNavigationItemView.
const/4 v0, 0
return-object v0
$returnEarlyInstruction
""",
ExternalLabel("normal-method-logic", firstInstruction)
)

View File

@ -3,6 +3,7 @@ package app.revanced.patches.spotify.misc.privacy
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val shareCopyUrlFingerprint = fingerprint {
returns("Ljava/lang/Object;")
@ -23,9 +24,15 @@ internal val shareCopyUrlLegacyFingerprint = fingerprint {
}
internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters("L", "Ljava/lang/String;")
opcodes(
Opcode.GOTO,
Opcode.IF_EQZ,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
)
literal {
'\n'.code.toLong()
}

View File

@ -8,6 +8,7 @@ import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -56,7 +57,15 @@ val sanitizeSharingLinksPatch = bytecodePatch(
shareUrlParameter = "p2"
} else {
shareSheetFingerprint = formatAndroidShareSheetUrlFingerprint
shareUrlParameter = "p1"
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod.accessFlags
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags)) {
// In newer implementations the method is static, so p0 is not `this`.
"p1"
} else {
// In older implementations the method is not static, making it so p0 is `this`.
// For that reason, add one to the parameter register.
"p2"
}
}
shareSheetFingerprint.method.addInstructions(