- Fix BunnyLog compile error in Sideloading.x (leftover from Bunny->Revenge rename; only RevengeLog is defined) - Remove duplicated -loadConfig/+defaultConfig methods in LoaderConfig.m - Repoint CI's ipa-patcher download at a live mirror with a pinned checksum (Cristiandis/ipa-patcher was deleted upstream) - Add a second injection hook on RCTInstance/-_loadScriptFromSource: for React Native's Bridgeless mode, alongside the existing RCTCxxBridge hook. Discord's Android build already runs Bridgeless (confirmed via revenge-xposed's hook targets) and revenge-bundle now pins RN 0.81, which defaults to it - so the legacy bridge hook this tweak relied on was very likely dead. Unverified against a real device; see AUDIT.md. See AUDIT.md for the full iOS-vs-Android comparison and remaining gaps.
5 KiB
iOS parity audit (2026-08-03)
Revenge dropped official iOS support; this repo was archived upstream in Nov 2024
(revenge-mod/revenge-tweak, last commit 35ad28b) while the Android loader
(revenge-mod/revenge-xposed) kept shipping. This audit compares the two and fixes
what could be fixed without a jailbroken device to test against.
Fixed in this fork
Sources/Sideloading.x:BunnyLog(...)referenced a macro that no longer exists (the project was renamed Bunny → Revenge; onlyRevengeLogis defined inHeaders/Logger.h). This made the file fail to compile. Fixed by usingRevengeLog.Sources/LoaderConfig.m:-loadConfigand+defaultConfigwere each defined twice in the same@implementation(leftover merge conflict). Removed the duplicates..github/workflows/deploy.yml: the CI patcher step pointed atCristiandis/ipa-patcherreleaserelease-pyon, which 404s — that repo no longer exists. Repointed at the still-live forkbunny-mod/ipa-patcher(same tag, release build) and pinned it with a verified SHA-256 checksum. (These three match the fixes proposed in the never-merged upstream PR #8, which the sole maintainer confirmed worked but never landed before the repo was archived.)
The real blocker: this tweak's hook point is very likely dead
Sources/Tweak.x hooks RCTCxxBridge -executeApplicationScript:url:async: — the
script-injection point for React Native's legacy bridge. Evidence points to
Discord having moved off that architecture entirely:
revenge-bundle'spackage.jsonpinsreact-native: 0.81.4, which defaults to the New Architecture ("Bridgeless mode").revenge-xposed(the actively-maintained Android loader) hookscom.facebook.react.runtime.ReactInstance$loadJSBundle$1— the Bridgeless-mode class — not the legacyCatalystInstanceImpl, and itsDiscordDevSupport.ktexplicitly targetscom.facebook.react.devsupport.BridgelessDevSupportManager.
Cross-platform RN apps built from one codebase almost always enable/disable the New
Architecture together, so if Android Discord is Bridgeless, iOS Discord almost
certainly is too — meaning RCTCxxBridge is likely never instantiated on current
Discord iOS builds, and the tweak's only injection point silently never fires.
Fix applied (unverified): added a second hook, %hook RCTInstance /
-_loadScriptFromSource:, the Bridgeless-mode equivalent, confirmed against React
Native's actual upstream source
(ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm). Both hooks
now share one injection pipeline (runRevengeInjection, factored out of the old
single hook body); Logos skips a %hook target gracefully if the class isn't
present at runtime, so shipping both is safe regardless of which architecture the
installed Discord build actually uses.
Since RCTSource (the type _loadScriptFromSource: takes) has no public
initializer, makeRCTSource() (Sources/Utils.m) builds one by poking its private
ivars directly — the same technique RN's own private RCTSourceCreate() uses
internally.
This has not been run against a real device or the current Discord iOS binary.
It's a best-effort port grounded in verified upstream RN source and the confirmed
Android hook target, not a tested fix. Needs a jailbreak + Xcode/Theos to validate;
if _loadScriptFromSource: turns out to have a different selector name in Discord's
actual build (obfuscation is unlikely for framework code, but app-specific
subclasses could differ), it'll need adjusting via class-dump/Frida against the
live binary.
Remaining feature gap vs. Android (not attempted here)
Beyond the injection hook, revenge-xposed has grown a much larger feature set
that iOS has no equivalent of. Porting these is real native engineering work, not
something to guess blind without a device to test each step against:
| Feature | Android | iOS |
|---|---|---|
| Script injection | RevengeScriptLoader + Bridgeless hook |
Fixed above (unverified) |
| Theme/font/sideloading | themes/fonts/sysColors, resource-ID fix |
Theme.m/Fonts.x/Sideloading.x (present, untouched) |
| Native↔JS RPC bridge | RevengeBridge — bidirectional calls smuggled through existing exposed RN native modules (RNSVGRenderableManager.getBBox, FileReaderModule.readAsDataURL) |
none |
| Plugin system | External plugin loading + repos (PluginLoader, RepoStore, RepoInstall, Resolver, ...) |
none |
| Internal plugins | Recovery mode, no-track, OTA-update prevention, example plugin | none |
| Dev support | LogBox + shake-to-recovery wired into RN's dev menu | none |
| Caches/lifecycle management | Caches.kt, LifecycleSupport.kt |
none |
The bridge + plugin system is the biggest gap and the most architecturally novel part of the Android side — it's what everything else (internal plugins, dev support) is built on. Recommend treating it as its own follow-up project once the injection hook above is confirmed working on-device, rather than attempting it speculatively.