feat(Hide ads): add Close fullscreen ads settings https://github.com/inotia00/ReVanced_Extended/issues/2017

This commit is contained in:
inotia00
2024-06-11 03:01:50 +09:00
parent 4aa18cce25
commit c003ad99bc
10 changed files with 163 additions and 103 deletions

View File

@ -1,18 +1,28 @@
package app.revanced.patches.shared.ads
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
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.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.ads.fingerprints.MusicAdsFingerprint
import app.revanced.patches.shared.ads.fingerprints.VideoAdsFingerprint
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexWithMethodReferenceName
import app.revanced.util.getWalkerMethod
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
abstract class BaseAdsPatch(
@ -59,4 +69,77 @@ abstract class BaseAdsPatch(
}
}
}
internal fun MethodFingerprintResult.hookNonLithoFullscreenAds(literal: Long) {
mutableMethod.apply {
val targetIndex = getWideLiteralInstructionIndex(literal) + 2
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideFullscreenAds(Landroid/view/View;)V"
)
}
}
internal fun MethodFingerprintResult.hookLithoFullscreenAds(context: BytecodeContext) {
mutableMethod.apply {
val dialogCodeIndex = scanResult.patternScanResult!!.endIndex
val dialogCodeField = getInstruction<ReferenceInstruction>(dialogCodeIndex).reference as FieldReference
if (dialogCodeField.type != "I")
throw PatchException("Invalid dialogCodeField: $dialogCodeField")
// Disable fullscreen ads
addInstructionsWithLabels(
0,
"""
move-object v0, p2
# In the latest version of YouTube and YouTube Music, it is used after being cast
check-cast v0, ${dialogCodeField.definingClass}
iget v0, v0, $dialogCodeField
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->disableFullscreenAds(I)Z
move-result v0
if-eqz v0, :show
return-void
""", ExternalLabel("show", getInstruction(0))
)
// Close fullscreen ads
// Find the instruction whose name is "show" in [MethodReference] and click the 'AlertDialog.BUTTON_POSITIVE' button.
// In this case, an instruction for 'getButton' must be added to smali, not in integrations
// (This custom dialog cannot be cast to [AlertDialog] or [Dialog])
val dialogIndex = getTargetIndexWithMethodReferenceName("show")
val dialogReference = getInstruction<ReferenceInstruction>(dialogIndex).reference
val dialogDefiningClass = (dialogReference as MethodReference).definingClass
val getButtonMethod = context.findClass(dialogDefiningClass)!!
.mutableClass.methods.first { method ->
method.parameters == listOf("I")
&& method.returnType == "Landroid/widget/Button;"
}
val getButtonCall = dialogDefiningClass + "->" + getButtonMethod.name + "(I)Landroid/widget/Button;"
val dialogRegister = getInstruction<FiveRegisterInstruction>(dialogIndex).registerC
val freeIndex = getTargetIndex(dialogIndex, Opcode.IF_EQZ)
val freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
addInstructions(
dialogIndex + 1, """
# Get the 'AlertDialog.BUTTON_POSITIVE' from custom dialog
# Since this custom dialog cannot be cast to AlertDialog or Dialog,
# It should come from smali, not integrations.
const/4 v$freeRegister, -0x1
invoke-virtual {v$dialogRegister, v$freeRegister}, $getButtonCall
move-result-object v$freeRegister
invoke-static {v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCloseButton(Landroid/widget/Button;)V
"""
)
}
}
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$PATCHES_PATH/FullscreenAdsPatch;"
}
}

View File

@ -18,7 +18,7 @@ import app.revanced.patches.shared.gms.fingerprints.GmsCoreSupportFingerprint.GE
import app.revanced.patches.shared.gms.fingerprints.GooglePlayUtilityFingerprint
import app.revanced.patches.shared.gms.fingerprints.PrimeMethodFingerprint
import app.revanced.patches.shared.gms.fingerprints.ServiceCheckFingerprint
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_PATH
import app.revanced.patches.shared.integrations.Constants.PATCHES_PATH
import app.revanced.patches.shared.packagename.PackageNamePatch
import app.revanced.util.getReference
import app.revanced.util.resultOrThrow
@ -106,7 +106,7 @@ abstract class BaseGmsCoreSupportPatch(
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.resultOrThrow().mutableMethod.addInstructions(
1, // Hack to not disturb other patches (such as the YTMusic integrations patch).
"invoke-static/range { p0 .. p0 }, $INTEGRATIONS_PATH/patches/GmsCoreSupport;->" +
"invoke-static/range { p0 .. p0 }, $PATCHES_PATH/GmsCoreSupport;->" +
"checkGmsCore(Landroid/app/Activity;)V",
)

View File

@ -1,9 +1,10 @@
package app.revanced.patches.shared.integrations
@Suppress("MemberVisibilityCanBePrivate", "SpellCheckingInspection")
@Suppress("MemberVisibilityCanBePrivate")
object Constants {
const val INTEGRATIONS_PATH = "Lapp/revanced/integrations/shared"
const val COMPONENTS_PATH = "$INTEGRATIONS_PATH/patches/components"
const val PATCHES_PATH = "$INTEGRATIONS_PATH/patches"
const val COMPONENTS_PATH = "$PATCHES_PATH/components"
const val INTEGRATIONS_SETTING_CLASS_DESCRIPTOR = "$INTEGRATIONS_PATH/settings/Setting;"
const val INTEGRATIONS_UTILS_CLASS_DESCRIPTOR = "$INTEGRATIONS_PATH/utils/Utils;"