Skip to content

fix(mobile): fresh Android builds no longer crash on launch - #20118

Open
marmar9615-cloud wants to merge 2 commits into
pingdotgg:mainfrom
marmar9615-cloud:fix/android-fbjni-crash
Open

marmar9615-cloud wants to merge 2 commits into
pingdotgg:mainfrom
marmar9615-cloud:fix/android-fbjni-crash

Conversation

@marmar9615-cloud

Copy link
Copy Markdown

Problem

Fresh Android builds crash before JavaScript starts. react-native-shiki-engine 0.3.12 requests com.facebook.fbjni:fbjni:+, and Gradle now resolves that to fbjni 0.8.1 instead of React Native's 0.7.0. fbjni 0.8.1 is built with NDK 28 and imports __cxa_init_primary_exception. React Native's NDK 27 libc++_shared.so does not export that symbol, so libfbjni.so fails to load in MainApplication.onCreate. Debug and release builds resolve the same way. A Gradle cache that still holds 0.7.0 hides the crash until the cache expires.

Change

Add an Expo config plugin, registered next to withAndroidGradleHeap, that appends the block below to the generated root android/build.gradle.

// Added by withAndroidFbjniVersion: keep fbjni on the version React Native ships against.
allprojects {
  configurations.all {
    resolutionStrategy.force 'com.facebook.fbjni:fbjni:0.7.0'
  }
}

The force covers every Gradle project, so shiki-engine's own classpaths get 0.7.0 too, not only the app's. The tests compare the generated Groovy and Kotlin text with the fbjni version in React Native's installed version catalog. A React Native upgrade that moves fbjni therefore fails the tests until the pin moves with it.

shiki-engine 0.4.0, released October 13, drops fbjni:+ (skiniks/react-native-shiki-engine#275). Once the app is on 0.4.0, this pin is no longer needed. I did not bump it here because 0.4.0 also changes native module registration, caching and regex matching on Android and iOS, and I could not test those changes on a device.

A new config plugin changes the native fingerprint on both platforms, as #12394 did. Merging it should trigger new Android and iOS store builds, and an OTA update cannot replace libfbjni.so. It needs the Native Change label, which the fingerprint workflow does not add to fork PRs.

Scope and approval

Fixes #13710. Julius accepted the bug and prescribed this fix in the triage comment.

This replaces #13967. Thanks to bompus for the report, Julius for the triage, j-gaertig for the device confirmation, kvnloo for #13967, and andybergon for validating #13967 and suggesting the version catalog test.

Verification

These ran on this branch with React Native 0.88.0-rc.3 and Node 24.

  • Four plugin tests pass. They fail if the force applies only to :app or only to the root project, if it pins 0.8.1, if app.config.ts stops registering the plugin, or if a second prebuild appends the block again.
  • Two clean expo prebuild --platform android runs and one --no-clean run produce the same root build.gradle with one force block. Compared with main, the 92 generated Android files differ only by that block.
  • A clean iOS prebuild matches main in all 38 files after normalizing Xcode's random object IDs.
  • A multi-project Gradle probe uses the real react-android:0.88.0-rc.3 metadata. Without the block, the app and shiki-engine resolve fbjni 0.8.1 in release and debug, compile and runtime. With the block, all of them resolve 0.7.0 as a forced version. A force on :app alone leaves shiki-engine on 0.8.1.
  • In the published AARs, React Native's libfbjni.so and libc++_shared.so are byte-identical to fbjni 0.7.0's on all four ABIs. fbjni 0.8.1's libfbjni.so imports __cxa_init_primary_exception on every ABI, and React Native's libc++_shared.so does not export it.
  • Mobile typecheck passes. Lint and format pass on the three changed files, and git diff --check is clean.

Earlier runs on React Native 0.86.3, before the 0.88 upgrade, used the same force. j-gaertig's preview APK launched on a Galaxy A55. andybergon built release APKs for all four ABIs from #13967 and cold-launched the arm64 APK five times on an Android 16 emulator.

I did not build an APK or launch anything on this branch. The Gradle probe uses Gradle 9.5.1 stand-in projects, not AGP or the generated 9.4.1 wrapper. Expo's config loader fails on my machine, so I have no valid local fingerprint, and CI has to show the fingerprint change. If the pinned version changes later, run a clean prebuild, because --no-clean keeps an existing marked block.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T03:11:14.325186Z 1a0a185 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 16, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1a0a185

Macroscope's review found this PR approvable — The PR makes a narrowly scoped Android build correction by pinning fbjni to React Native's compatible version, preventing a pre-JavaScript startup crash. Its Expo wiring and Gradle generation behavior are covered by focused tests, with no new user-facing capability or sensitive configuration change.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 16, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ef0be155-716c-4240-a88c-46240e2c0d69
📥 Commits

Reviewing files that changed from the base of the PR and between f1e0a4d and 1a0a185.

📒 Files selected for processing: 3
  • apps/mobile/app.config.ts
  • apps/mobile/plugins/withAndroidFbjniVersion.cjs
  • apps/mobile/plugins/withAndroidFbjniVersion.test.mjs

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

The mobile app registers an Expo config plugin that forces fbjni 0.7.0 in the root Gradle build. The plugin supports Groovy and Kotlin DSL and has tests for generated output, repeated prebuild runs, and app registration.

Changes: Android fbjni version pin

Layer / File(s) Summary
Register and validate the Gradle version force
apps/mobile/plugins/withAndroidFbjniVersion.cjs, apps/mobile/app.config.ts, apps/mobile/plugins/withAndroidFbjniVersion.test.mjs
The plugin adds an fbjni 0.7.0 resolution force to the root Gradle build when its marker is absent. It supports Groovy and Kotlin DSL. The app registers the plugin, and tests cover both syntaxes, repeated prebuild runs, and the registered root-Gradle mod.

Priority: ⬆️ High

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: High

Merge Risk: ⚪ Minimal · up to 1a0a1

No identified issue blocks merging; an Android build and launch would provide additional confidence.

Security architecture risk: 🔵 Low · up to 1a0a1

The change is confined to Android native dependency selection and introduces no identified access or privilege expansion. Residual risk concerns version synchronization and regeneration of native builds during upgrades or rollback.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — The configured enforcement scope is fbjni dependency selection across Android Gradle project configurations using this generated root build script, rather than only the app module. The changed code does not introduce tenant, service-identity, IAM, secret, or network-policy operations.

Trust Boundaries and Controls

  • inferred — The exported function is a build-time configuration hook, not a newly exposed runtime endpoint. It consumes Gradle contents and language supplied by the prebuild pipeline and emits a fixed coordinate; unsupported languages throw before mutation. Influencing insertion through the marker requires control of build-file contents, not a newly introduced device or network input.
Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly describes the primary change: preventing fresh Android builds from crashing on launch. It is concise, specific, and uses conventional commit format.
Description check Passed The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the root cause, implementation, linked issue and approval, test results, known limitations…
Linked Issues check Passed The changes satisfy the coding requirement in #13710. app.config.ts registers withAndroidFbjniVersion.cjs. The plugin appends a root `allprojects { configurations.all { resolutionStrategy.force ..…
Out of Scope Changes check Passed The pull request changes only the Expo plugin registration, the fbjni Gradle plugin, and tests for that plugin. Each change supports the fix requested by #13710. No unrelated product behavior or depen…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android release builds crash on launch: react-native-shiki-engine resolves fbjni:+ to 0.8.1

1 participant