Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
nmknm
57bf1e3697
Update compatibility for DisableAdsPatch 2026-03-06 14:50:45 +02:00
nmknm
c450a795ea
fix(duolingo): fix missing StringBuilder in skip energy recharge ads
Duolingo optimized the toString() method, removing StringBuilder. Replaced findFieldFromToString with custom smali bytecode parsing.
2026-03-06 14:49:38 +02:00
2 changed files with 37 additions and 4 deletions

View file

@ -10,7 +10,7 @@ val disableAdsPatch = bytecodePatch(
"Disable ads",
) {
// 6.55.3 and higher can show ads after each exercise.
compatibleWith("com.duolingo"("6.54.5"))
compatibleWith("com.duolingo")
execute {
// Couple approaches to remove ads exist:

View file

@ -2,7 +2,10 @@ package app.revanced.patches.duolingo.energy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.findFieldFromToString
import com.android.tools.smali.dexlib2.Opcode
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.StringReference
@Suppress("unused")
val skipEnergyRechargeAdsPatch = bytecodePatch(
@ -15,8 +18,38 @@ val skipEnergyRechargeAdsPatch = bytecodePatch(
initializeEnergyConfigFingerprint
.match(energyConfigToStringFingerprint.classDef)
.method.apply {
val energyField = energyConfigToStringFingerprint.method
.findFieldFromToString("energy=")
val toStringMethod = energyConfigToStringFingerprint.method
val instructions = toStringMethod.implementation!!.instructions.toList()
var energyField: String? = null
// Search for the string "energy=" and get the preceding IGET instruction.
for (i in instructions.indices) {
val instr = instructions[i]
val ref = (instr as? ReferenceInstruction)?.reference
if (ref is StringReference && ref.string.contains("energy=")) {
// Search backwards for the field getter (IGET)
for (j in i downTo 0) {
val prevInstr = instructions[j]
if (prevInstr.opcode == Opcode.IGET) {
val fieldRef = (prevInstr as ReferenceInstruction).reference as FieldReference
// Construct the full valid Smali field reference: Lclass;->name:type
energyField = "${fieldRef.definingClass}->${fieldRef.name}:${fieldRef.type}"
break
}
}
break
}
}
// Fallback: The first IGET instruction is guaranteed to be the 'energy' property.
if (energyField == null) {
val fallbackInstr = instructions.first { it.opcode == Opcode.IGET }
val fieldRef = (fallbackInstr as ReferenceInstruction).reference as FieldReference
energyField = "${fieldRef.definingClass}->${fieldRef.name}:${fieldRef.type}"
}
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
addInstructions(