From 0e020c5760e423feb427ab67c486d0f5cffeb587 Mon Sep 17 00:00:00 2001 From: Tymek Date: Tue, 13 Jan 2026 03:41:22 +0100 Subject: [PATCH 1/4] feat(Jakdojade) Add `Remove ads` patch --- patches/api/patches.api | 4 ++ .../patches/jakdojade/ad/Fingerprints.kt | 50 +++++++++++++++++++ .../patches/jakdojade/ad/RemoveAdsPatch.kt | 41 +++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index 91942f4406..0094600069 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -352,6 +352,10 @@ public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt { public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/jakdojade/ad/RemoveAdsPatchKt { + public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/letterboxd/ads/HideAdsPatchKt { public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt new file mode 100644 index 0000000000..6c6b53cf63 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt @@ -0,0 +1,50 @@ +package app.revanced.patches.jakdojade.ad + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal val isPremiumFingerprint = fingerprint { + returns("Z") + accessFlags(AccessFlags.PUBLIC) + parameters() + opcodes( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.CONST_4, + Opcode.GOTO, + Opcode.CONST_4, + Opcode.RETURN + ) +} + +internal val premiumRenewalDateFingerprint = fingerprint { + returns("Ljava/lang/String;") + accessFlags(AccessFlags.PUBLIC) + parameters() + opcodes( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + ) +} + +internal val getGoogleProductFingerprint = fingerprint { + returns("Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct;") + accessFlags(AccessFlags.PUBLIC) + parameters("Lcom/citynav/jakdojade/pl/android/profiles/ui/profile/userprofile/model/PremiumType;") +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt new file mode 100644 index 0000000000..5a0aa1434b --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt @@ -0,0 +1,41 @@ +package app.revanced.patches.jakdojade.ad + +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions +import app.revanced.patcher.patch.bytecodePatch + +@Suppress("unused") +val removeAdsPatch = bytecodePatch( + name = "Remove ads", +) { + compatibleWith("com.citynav.jakdojade.pl.android") + + execute { + // Spoof isPremium() to always return true + // We can do this beacuse Jakdojade Premium's only feature is ad removal + isPremiumFingerprint.method.replaceInstructions( + 0, + """ + const/4 v0, 0x1 + return v0 + """, + ) + + // Spoof Premium renewal date in the UI + // We need to do the spoofing in order to avoid app crashes when opening profile menu + premiumRenewalDateFingerprint.method.replaceInstructions( + 0, + """ + const-string v0, "" + return-object v0 + """.trimIndent() + ) + // Spoof Premium type + getGoogleProductFingerprint.method.replaceInstructions( + 0, + """ + sget-object v0, Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct;->PREMIUM_YEARLY_V4:Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct; + return-object v0 + """.trimIndent() + ) + } +} From 7cf5102fb012f1cdef2d56ff3a420440a26c94dc Mon Sep 17 00:00:00 2001 From: Tymek Date: Tue, 13 Jan 2026 16:38:10 +0100 Subject: [PATCH 2/4] Fix(Jakdojade) Code style fixes --- patches/api/patches.api | 4 +-- .../{RemoveAdsPatch.kt => DisableAdsPatch.kt} | 29 ++++++++----------- .../patches/jakdojade/ad/Fingerprints.kt | 18 ++++++------ 3 files changed, 23 insertions(+), 28 deletions(-) rename patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/{RemoveAdsPatch.kt => DisableAdsPatch.kt} (62%) diff --git a/patches/api/patches.api b/patches/api/patches.api index 0094600069..c457c4fdee 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -352,8 +352,8 @@ public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt { public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/jakdojade/ad/RemoveAdsPatchKt { - public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +public final class app/revanced/patches/jakdojade/ad/DisableAdsPatchKt { + public static final fun getDisableAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/letterboxd/ads/HideAdsPatchKt { diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/DisableAdsPatch.kt similarity index 62% rename from patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt rename to patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/DisableAdsPatch.kt index 5a0aa1434b..63ebc9ed2f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/RemoveAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/DisableAdsPatch.kt @@ -2,40 +2,35 @@ package app.revanced.patches.jakdojade.ad import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions import app.revanced.patcher.patch.bytecodePatch +import app.revanced.util.returnEarly @Suppress("unused") -val removeAdsPatch = bytecodePatch( - name = "Remove ads", +val disableAdsPatch = bytecodePatch( + name = "Disable ads", ) { compatibleWith("com.citynav.jakdojade.pl.android") execute { - // Spoof isPremium() to always return true - // We can do this beacuse Jakdojade Premium's only feature is ad removal - isPremiumFingerprint.method.replaceInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """, - ) + // Spoof isPremium() to always return true. + // We can do this beacuse Jakdojade Premium's only feature is ad removal. + isPremiumFingerprint.method.returnEarly(true) - // Spoof Premium renewal date in the UI - // We need to do the spoofing in order to avoid app crashes when opening profile menu - premiumRenewalDateFingerprint.method.replaceInstructions( + // Spoof Premium renewal date in the UI. + // We need to do the spoofing in order to avoid app crashes when opening profile menu. + getPremiumRenewalDateFingerprint.method.replaceInstructions( 0, """ const-string v0, "" return-object v0 - """.trimIndent() + """ ) - // Spoof Premium type + // Spoof Premium type. getGoogleProductFingerprint.method.replaceInstructions( 0, """ sget-object v0, Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct;->PREMIUM_YEARLY_V4:Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct; return-object v0 - """.trimIndent() + """ ) } } diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt index 6c6b53cf63..818ba5eacd 100644 --- a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt @@ -17,18 +17,18 @@ internal val isPremiumFingerprint = fingerprint { Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT, Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.RETURN +// Opcode.IGET_OBJECT, +// Opcode.INVOKE_VIRTUAL, +// Opcode.MOVE_RESULT, +// Opcode.IF_NEZ, +// Opcode.CONST_4, +// Opcode.GOTO, +// Opcode.CONST_4, +// Opcode.RETURN ) } -internal val premiumRenewalDateFingerprint = fingerprint { +internal val getPremiumRenewalDateFingerprint = fingerprint { returns("Ljava/lang/String;") accessFlags(AccessFlags.PUBLIC) parameters() From 36d1e83f2a2d7adfa9a725dc4dcb98c26e82b44b Mon Sep 17 00:00:00 2001 From: Tymek Date: Tue, 13 Jan 2026 16:40:02 +0100 Subject: [PATCH 3/4] Chore(Jakdojade) Removed unnecessary commented code --- .../app/revanced/patches/jakdojade/ad/Fingerprints.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt index 818ba5eacd..5c1bb21342 100644 --- a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ad/Fingerprints.kt @@ -17,14 +17,6 @@ internal val isPremiumFingerprint = fingerprint { Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT, Opcode.IF_EQZ, -// Opcode.IGET_OBJECT, -// Opcode.INVOKE_VIRTUAL, -// Opcode.MOVE_RESULT, -// Opcode.IF_NEZ, -// Opcode.CONST_4, -// Opcode.GOTO, -// Opcode.CONST_4, -// Opcode.RETURN ) } From 4a71df5214a386962e3e1c278af59d78c91dfa93 Mon Sep 17 00:00:00 2001 From: Tymek Date: Thu, 19 Mar 2026 01:49:54 +0100 Subject: [PATCH 4/4] Fix(Jakdojade) Renamed `ad` to `ads` and used `returnEarly` --- patches/api/patches.api | 2 +- .../patches/jakdojade/ads/DisableAdsPatch.kt | 30 +++++++++++++ .../patches/jakdojade/ads/Fingerprints.kt | 42 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/DisableAdsPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/Fingerprints.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index c457c4fdee..2091c7d27b 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -352,7 +352,7 @@ public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt { public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/jakdojade/ad/DisableAdsPatchKt { +public final class app/revanced/patches/jakdojade/ads/DisableAdsPatchKt { public static final fun getDisableAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/DisableAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/DisableAdsPatch.kt new file mode 100644 index 0000000000..b1f223ed94 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/DisableAdsPatch.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.jakdojade.ads + +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.util.returnEarly + +@Suppress("unused") +val disableAdsPatch = bytecodePatch( + name = "Disable ads", +) { + compatibleWith("com.citynav.jakdojade.pl.android") + + execute { + // Spoof isPremium() to always return true. + // We can do this beacuse Jakdojade Premium's only feature is ad removal. + isPremiumFingerprint.method.returnEarly(true) + + // Spoof Premium renewal date in the UI. + // We need to do the spoofing in order to avoid app crashes when opening profile menu. + getPremiumRenewalDateFingerprint.method.returnEarly("") + // Spoof Premium type. + getGoogleProductFingerprint.method.replaceInstructions( + 0, + """ + sget-object v0, Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct;->PREMIUM_YEARLY_V4:Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct; + return-object v0 + """ + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/Fingerprints.kt new file mode 100644 index 0000000000..560eb80a40 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/jakdojade/ads/Fingerprints.kt @@ -0,0 +1,42 @@ +package app.revanced.patches.jakdojade.ads + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal val isPremiumFingerprint = fingerprint { + returns("Z") + accessFlags(AccessFlags.PUBLIC) + parameters() + opcodes( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + ) +} + +internal val getPremiumRenewalDateFingerprint = fingerprint { + returns("Ljava/lang/String;") + accessFlags(AccessFlags.PUBLIC) + parameters() + opcodes( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + ) +} + +internal val getGoogleProductFingerprint = fingerprint { + returns("Lcom/citynav/jakdojade/pl/android/billing/output/GoogleProduct;") + accessFlags(AccessFlags.PUBLIC) + parameters("Lcom/citynav/jakdojade/pl/android/profiles/ui/profile/userprofile/model/PremiumType;") +} \ No newline at end of file