mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-14 21:22:27 +01:00
feat(Instagram): Add Open links externally patch (#6012)
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
package app.revanced.extension.instagram.misc.links;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class OpenLinksExternallyPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean openExternally(String url) {
|
||||||
|
try {
|
||||||
|
// The "url" parameter to this function will be of the form.
|
||||||
|
// https://l.instagram.com/?u=<actual url>&e=<tracking id>
|
||||||
|
String actualUrl = Uri.parse(url).getQueryParameter("u");
|
||||||
|
if (actualUrl != null) {
|
||||||
|
Utils.openLink(actualUrl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "openExternally failure", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import android.content.res.Configuration;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -696,6 +697,18 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openLink(String url) {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(url));
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
||||||
|
Logger.printInfo(() -> "Opening link with external browser: " + intent);
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "openLink failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum NetworkType {
|
public enum NetworkType {
|
||||||
NONE,
|
NONE,
|
||||||
MOBILE,
|
MOBILE,
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
// Do not remove. Necessary for the extension plugin to be applied to the project.
|
dependencies {
|
||||||
|
compileOnly(project(":extensions:shared:library"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
package app.revanced.twitter.patches.links;
|
package app.revanced.twitter.patches.links;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public final class ChangeLinkSharingDomainPatch {
|
public final class ChangeLinkSharingDomainPatch {
|
||||||
private static final String DOMAIN_NAME = "https://fxtwitter.com";
|
private static final String DOMAIN_NAME = "https://fxtwitter.com";
|
||||||
private static final String LINK_FORMAT = "%s/%s/status/%s";
|
private static final String LINK_FORMAT = "%s/%s/status/%s";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static String formatResourceLink(Object... formatArgs) {
|
public static String formatResourceLink(Object... formatArgs) {
|
||||||
String username = (String) formatArgs[0];
|
String username = (String) formatArgs[0];
|
||||||
String tweetId = (String) formatArgs[1];
|
String tweetId = (String) formatArgs[1];
|
||||||
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static String formatLink(long tweetId, String username) {
|
public static String formatLink(long tweetId, String username) {
|
||||||
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,18 @@ package app.revanced.twitter.patches.links;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@Deprecated(forRemoval = true)
|
@Deprecated(forRemoval = true)
|
||||||
public final class OpenLinksWithAppChooserPatch {
|
public final class OpenLinksWithAppChooserPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static void openWithChooser(final Context context, final Intent intent) {
|
public static void openWithChooser(final Context context, final Intent intent) {
|
||||||
Log.d("ReVanced", "Opening intent with chooser: " + intent);
|
Logger.printInfo(() -> "Opening intent with chooser: " + intent);
|
||||||
|
|
||||||
intent.setAction("android.intent.action.VIEW");
|
intent.setAction("android.intent.action.VIEW");
|
||||||
|
|
||||||
|
|||||||
@@ -284,6 +284,10 @@ public final class app/revanced/patches/instagram/misc/extension/SharedExtension
|
|||||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/misc/links/OpenLinksExternallyPatchKt {
|
||||||
|
public static final fun getOpenLinksExternallyPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
|
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
|
||||||
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.links
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal const val TARGET_STRING = "Tracking.ARG_CLICK_SOURCE"
|
||||||
|
|
||||||
|
internal val inAppBrowserFunctionFingerprint = fingerprint {
|
||||||
|
returns("Z")
|
||||||
|
strings("TrackingInfo.ARG_MODULE_NAME", TARGET_STRING)
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.links
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/instagram/misc/links/OpenLinksExternallyPatch;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val openLinksExternallyPatch = bytecodePatch(
|
||||||
|
name = "Open links externally",
|
||||||
|
description = "Changes links to always open in your external browser, instead of the in-app browser.",
|
||||||
|
use = false,
|
||||||
|
) {
|
||||||
|
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
inAppBrowserFunctionFingerprint.let {
|
||||||
|
val stringMatchIndex = it.stringMatches?.first { match -> match.string == TARGET_STRING }!!.index
|
||||||
|
|
||||||
|
it.method.apply {
|
||||||
|
val urlResultObjIndex = indexOfFirstInstructionOrThrow(
|
||||||
|
stringMatchIndex, Opcode.MOVE_OBJECT_FROM16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register that contains the url after moving from a higher register.
|
||||||
|
val urlRegister = getInstruction<TwoRegisterInstruction>(urlResultObjIndex).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
urlResultObjIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->openExternally(Ljava/lang/String;)Z
|
||||||
|
move-result v$urlRegister
|
||||||
|
return v$urlRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package app.revanced.patches.twitter.misc.extension
|
package app.revanced.patches.twitter.misc.extension
|
||||||
|
|
||||||
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.twitter.misc.extension.hooks.applicationInitHook
|
||||||
|
|
||||||
val sharedExtensionPatch = sharedExtensionPatch("twitter")
|
val sharedExtensionPatch = sharedExtensionPatch("twitter", applicationInitHook)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package app.revanced.patches.twitter.misc.extension.hooks
|
||||||
|
|
||||||
|
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||||
|
|
||||||
|
internal val applicationInitHook =
|
||||||
|
extensionHook {
|
||||||
|
custom { method, classDef ->
|
||||||
|
classDef.type == "Lcom/twitter/app/TwitterApplication;" && method.name == "onCreate"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,27 +53,27 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
val replacementIndex =
|
linkSharingDomainFingerprint.let {
|
||||||
linkSharingDomainFingerprint.stringMatches!!.first().index
|
val replacementIndex = it.stringMatches!!.first().index
|
||||||
val domainRegister =
|
val domainRegister = it.method.getInstruction<OneRegisterInstruction>(
|
||||||
linkSharingDomainFingerprint.method.getInstruction<OneRegisterInstruction>(replacementIndex).registerA
|
replacementIndex
|
||||||
|
).registerA
|
||||||
|
|
||||||
linkSharingDomainFingerprint.method.replaceInstruction(
|
it.method.replaceInstruction(
|
||||||
replacementIndex,
|
replacementIndex,
|
||||||
"const-string v$domainRegister, \"https://$domainName\"",
|
"const-string v$domainRegister, \"https://$domainName\"",
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Replace the domain name when copying a link with "Copy link" button.
|
// Replace the domain name when copying a link with "Copy link" button.
|
||||||
linkBuilderFingerprint.method.apply {
|
linkBuilderFingerprint.method.addInstructions(
|
||||||
addInstructions(
|
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
invoke-static { p0, p1, p2 }, $EXTENSION_CLASS_DESCRIPTOR->formatLink(JLjava/lang/String;)Ljava/lang/String;
|
invoke-static { p0, p1, p2 }, $EXTENSION_CLASS_DESCRIPTOR->formatLink(JLjava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object p0
|
move-result-object p0
|
||||||
return-object p0
|
return-object p0
|
||||||
""",
|
"""
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
// Used in the Share via... dialog.
|
// Used in the Share via... dialog.
|
||||||
linkResourceGetterFingerprint.method.apply {
|
linkResourceGetterFingerprint.method.apply {
|
||||||
|
|||||||
Reference in New Issue
Block a user