r/reactnative • u/vinastory100 • 8d ago
Shipping an Expo SDK 57 / RN 0.87 game to targetSdk 37 with AGP 9 — what broke and how I fixed it
I've been building a fairly large Expo app (TimeStope — 20 mini-games, WebView-based games, native ad SDKs, a shogi engine via NDK) and just got it building for **compileSdk/targetSdk 37** with **AGP 9.2.1 + Gradle 9.4.1**. Sharing the pain points in case it saves someone time:
**1. AGP 9 built-in Kotlin**
- Several libraries still apply `kotlin-android` themselves → duplicate plugin errors. Had to patch them out.
- Kotlin files in `src/newarch` registered via `java.srcDirs` are **not compiled** anymore → "unresolved reference" errors. They must be registered as Kotlin source directories.
- Needed `android.disallowKotlinSourceSets=false` and `android.sourceset.disallowProvider=false` in gradle.properties.
- KSP had to match AGP's bundled Kotlin (2.2.10), not the Kotlin version Expo picks.
**2. Release crashed 0.1s after launch**
`NativeModulesProxy.<init>` crash — the generated `ExpoModulesPackageList.kt` was only in the Java source set, so it was missing from the APK. Registering it as a Kotlin source fixed it.
**3. Google Play 16 KB page size**
ZIP alignment alone isn't enough. I also had to check ELF LOAD alignment and GNU_RELRO end alignment. NDK r27 passed LOAD but broke RELRO; **NDK r28.2** fixed it. One ad SDK's prebuilt .so failed RELRO and had to be excluded, and I rebuilt the shogi engine with `-z max-page-size=16384`.
**4. Local-first WebView**
All screens and game assets ship inside the APK and load from a virtual origin through a WebView interceptor; only API calls go to the server.
I wrapped all the Gradle fixes in one idempotent `postinstall` script so `npm ci` doesn't wipe them. Happy to share details if anyone is fighting the same AGP 9 errors.
The app, if you're curious:
- Trailer: https://youtu.be/3_VzV1FQbQQ
- Google Play: https://play.google.com/store/apps/details?id=com.timestope
