Multi-app ReVanced-compatible patches, plus a one-shot driver that builds, applies, signs, and repackages an APK/APKS for sideloading.
The layout mirrors ReVanced/revanced-patches so patches written here are liftable upstream, but each target app is its own Gradle subproject — one broken fingerprint can't knock out the build for unrelated apps.
revanced-cli-*.jar # Shared ReVanced CLI (at repo root — download separately, not committed)
patch-apks.sh # Driver: build → patch → sign → repack
add-app.sh # Scaffold a new app + pull its APKs from a device
build.gradle.kts # Root Gradle
settings.gradle.kts # Registers each :patches:<app> subproject
gradle/libs.versions.toml # Single source of truth for patcher/kotlin versions
patches/<app>/ # One Gradle subproject per app
build.gradle.kts
src/main/kotlin/app/revanced/patches/<app>/<category>/<Patch>.kt
apps/<app>/ # One directory per app
README.md # Target version, SHA-256s, install notes (autogenerated)
apks/ # Git-ignored — user supplies their own
Apps currently supported:
hidratespark(hidratenow.com.hidrate.hidrateandroidv4.6.9) — disable Google Play license check, unlock premiummeetup(com.meetupv2026.04.10.2881) — disable intro/profile/StepUp/MemberSub paywalls, hide Meetup+ trial banner, hide attendees paywall panels, auto-reject OneTrust cookie banner, unblur gated profile content, inject your own Maps API keytinder(com.tinderv17.15.0) — disable paywall flow + dynamic paywall sheet, dismiss every dialog upsell (Boost, MyLikes, Platinum Likes, Primetime, Secret Admirer, Headless Purchase), suppress ads-bouncer rewarded-video and standalone rewarded-video modalsstrava(com.stravav460.9) — consumes upstreampatches.rvpdirectly, no local patches subproject. Drop apatches-<ver>.rvpat the repo root and run./patch-apks.sh --app strava --patches patches-<ver>.rvp.
- JDK 17+
apksigner(sudo apt install apksigner) — only for.apksbundleskeytool(ships with the JDK)revanced-cli-*.jarat the repo root — grab a release from revanced/revanced-cli- A GitHub PAT with
read:packagesfor ReVanced's GitHub Packages Maven mirror. Set as env vars or in~/.gradle/gradle.properties:gprUser=<your-github-username> gprKey=<your-github-pat>
# Interactive: pick app → pick APK/APKS → pick patches
./patch-apks.sh
# Target a specific app
./patch-apks.sh --app hidratespark
# Unattended (applies every patch)
./patch-apks.sh --app hidratespark --no-uiOutput lands in build/<name>-patched.apks (or -patched.apk for a single APK). The driver prints the correct adb install or adb install-multiple command when it finishes.
# Fully interactive: picks a third-party package from the connected device,
# pulls every APK (base + splits), derives a shortname from the app label,
# records SHA-256s, and scaffolds patches/<name>/ + apps/<name>/
./add-app.sh
# Non-interactive on the package
./add-app.sh com.example.app
# Force a shortname (skip aapt-based derivation)
./add-app.sh --name example com.example.appThe script pulls every APK returned by pm path, bundles splits into an .apks zip, writes apps/<name>/README.md with the version + checksums, scaffolds the patches/<name>/ subproject, and registers it in settings.gradle.kts. Drop .kt patch files into patches/<name>/src/main/kotlin/app/revanced/patches/<name>/ and build.
WSL note: the Linux adb binary cannot see USB devices. add-app.sh detects WSL and prefers Windows adb.exe — install Android Platform Tools on Windows and put adb.exe on your PATH (or pass --adb <path>).
Every patch should:
- Use the
bytecodePatch { ... }DSL - Declare
compatibleWith("<package>"("<version>"))— without this the patch silently no-ops against other versions - Anchor fingerprints on fully-qualified class type + method name + signature rather than opcode patterns (types survive obfuscation better)
See patches/hidratespark/, patches/meetup/, and patches/tinder/ for working examples — return-true injection, return-void chokepoints on activity onCreate, DialogFragment dismiss-and-return-null, Compose-overload no-ops, and a resource patch (InjectMapsKeyPatch) that rewrites a manifest meta-data value. Detailed conventions and a working template are in CLAUDE.md.
High-locals gotcha:
addInstructionsinjects raw smali into the existing method, inheriting its.localscount. If.locals + parameter_count > 16, references top0/p1/etc may land above v15 and 4-bit-register instructions (const/4,invoke-virtual {...}non-range form) will fail to assemble withInvalid register: vNN. Useinvoke-virtual/range {p0 .. p0}and stash constants in a low local likev0. Seepatches/tinder/.../ads/DisableRewardedVideoPatch.ktfor the pattern.
APK binaries are not checked in — they're the vendor's IP. Each apps/<app>/README.md lists the target package, version, and SHA-256 of the files the patches were written against. Obtain them from a reputable mirror (APKMirror et al.) or re-run add-app.sh against a device with the app installed.
Each subproject is self-contained and pins the same patcher version as upstream, so a patch can be lifted to ReVanced/revanced-patches by moving the .kt file into their patches/src/main/kotlin/app/revanced/patches/<app>/ tree and matching their build.gradle.kts conventions.