Skip to content

feat: implement native bundle hash verification on iOS and Android#1

Merged
joshua-rogers-exodus merged 1 commit into
masterfrom
exo-doguhan/verify-on-native-side
May 15, 2026
Merged

feat: implement native bundle hash verification on iOS and Android#1
joshua-rogers-exodus merged 1 commit into
masterfrom
exo-doguhan/verify-on-native-side

Conversation

@exo-doguhan
Copy link
Copy Markdown

loadVerified was implemented in JS: fetch the bundle, call response.arrayBuffer(), hash in TypeScript. On large bundles, Hermes throws a RangeError at the engine level
(uncatchable).

Changes:

  • iOS / Android: loadVerifiedFromUrl is now a native method. Download, SHA-256 hash, and constant-time comparison all happen in native code.
  • (Android) process restart instead of in-process bridge swap: Unlike iOS (which tears down and recreates the bridge in-process) - (I suspect) due to Android's GC cannot guarantee the old Hermes runtime's native heap is freed before the new one allocates. Running both simultaneously crashes app. The module instead writes the bundle, sets a one-shot flag and restarts via startActivity + killProcess. The host app's ReactNativeHost reads the flag on next launch and serves the cached file.
  • (Android) Metro bypass required: RN 0.78 ignores getJSBundleFile() when getUseDeveloperSupport() is true and Metro is reachable. ReactInstanceManager calls DevSupportManager.handleReloadJS() regardless. The host app must return false from getUseDeveloperSupport() when a pending bundle exists.
    • One-shot behaviour: The remote bundle is active for one session only. The next cold start clears the latch and returns to Metro — matching iOS behaviour.
  • loadFromBase64 removed.
  • README: Android integration section rewritten to document the process-restart approach

Verified: tested end-to-end on iOS and Android by scanning a QR code pointing to a real S3 bundle with a correct SHA-256. Bridge reloaded from the verified file on both
platforms. On Android, confirmed one-shot behaviour: remote bundle active for one session, cold restart returns to Metro.

  JS-side response.arrayBuffer() on ~70 MB bundles triggers an engine-level
  abort in Hermes that bypasses the promise chain entirely. Move the download,
  SHA-256 hashing, and constant-time comparison into native code on both
  platforms.
@exo-doguhan exo-doguhan self-assigned this May 15, 2026
@joshua-rogers-exodus joshua-rogers-exodus merged commit 537b04a into master May 15, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants