Updating a React Native app to support Android 16 KB memory pages

March 23, 2026

Starting with Android 15, devices may use 16 KB memory pages instead of the traditional 4 KB. Since November 1, 2025, Google Play has required new apps and updates targeting Android 15+ devices to support 16 KB page sizes on 64-bit devices.

When I first looked at this requirement, I expected it to be an Android build configuration task: some Gradle flag, an NDK setting, maybe a release build tweak. It turned out to be less glamorous and more useful: an audit of every native library our React Native app shipped.

The JavaScript code was not the problem. The real question was which npm packages were adding .so files to the final APK/AAB, and whether those binaries were compatible with 16 KB pages.

What I had to understand first

Android loads native libraries (.so files) from your APK/AAB. On 16 KB page devices, libraries compiled with 4 KB alignment assumptions can fail to load or crash at startup.

Google's guidance and tooling point you toward the native binary layer:

  • Page sizes documentation
  • Play Console pre-launch reports flag non-compliant libraries
  • The fix is almost always upgrade the dependency that ships the .so, not patch your app code

That last point changed how I approached the work. I stopped looking for one global Android setting and started building an inventory.

The audit table was the turning point

I started from a Play Console warning and cross-checked the build with APK Analyzer. The important move was mapping every flagged .so file back to the package that brought it into the app.

Library Flagged .so files Fix version
react-native-reanimated libreanimated.so, libworklets.so 3.17.0+
expo libexpo-modules-core.so SDK bump
react-native-pdf libpdfiumandroid.so 7.0.1+
@d11/react-native-fast-image libavif_android.so, libglide-webp.so 8.11.0+
react-native-keychain libconceal.so 10.0.0+

This table did two things. First, it made the problem finite. Second, it stopped the team from randomly upgrading native dependencies and hoping the warning would disappear.

The keychain case was the most interesting one. libconceal.so came from Facebook Conceal, which the library removed in v10. Upgrading keychain fixed 16 KB compliance and dropped unmaintained native code. That mattered beyond the Play Console warning because Keychain also sits close to authentication and biometric unlock flows.

Dependency order mattered more than expected

My first instinct was to bump every flagged package directly. In a React Native app tied to Expo and native module compatibility, that is risky. Some versions are effectively pinned by the Expo SDK or by the React Native version.

The order that worked was:

  1. Expo SDK β€” determines compatible versions of most native modules
  2. Reanimated β€” frequent native ABI coupling with RN version
  3. Keychain, PDF, Fast Image β€” independent bumps where semver allowed
  4. Rebuild Android from clean β€” ./gradlew clean and clear CMake caches when NDK artifacts stick

I would not treat this as a normal dependency refresh. It is closer to a native release preparation task: upgrade one layer, rebuild cleanly, inspect the resulting artifacts, and only then move to the next flagged library.

Validation had to use release-like builds

Debug builds can lie because they do not always include the same native artifact set as release builds. The checks that gave me confidence were:

  • An emulator configured for 16 KB pages (when available in SDK tools)
  • Physical Android 15+ devices
  • CI release builds β€” debug builds sometimes link different artifact sets

The manual smoke tests were intentionally boring: app startup, login, animated transitions, PDF rendering, cached images, and one screen per upgraded native library. The goal was not broad product validation; it was proving that every upgraded native dependency still loaded and behaved in the flows where we used it.

This could not ship over the air

These upgrades changed native binaries. CodePush and Expo Updates cannot deliver them. That sounds obvious, but it affects planning.

The work had to go into a native release train. That meant:

  • bumping the native app version
  • updating OTA target binary ranges for active release branches
  • running Android-heavy regression flows
  • submitting a new store build
  • waiting for Play Console validation to confirm the .so warnings were gone

If your team normally thinks of dependency bumps as quick background work, this is the wrong mental model. Treat 16 KB compliance as store-release work with a deadline.

What I now check before submitting

Before Play upload:

  • Build release AAB locally or from CI
  • Run Google’s alignment checks / Play pre-launch report
  • Confirm no new .so warnings appear
  • Spot-check app startup and one screen per upgraded library (PDF viewer, animated transitions, cached images)

What I would do again

  • Start from the audit table β€” map each .so to exactly one npm package; do not upgrade randomly.
  • Keychain v10 was a two-for-one β€” 16 KB fix plus removal of Conceal.
  • Expo pins the ecosystem β€” if Expo SDK blocks a library version, escalate SDK upgrade first.
  • Plan a native release β€” treat this as compliance work with a hard deadline, not a background chore.

If Play Console flags 16 KB issues on your React Native app, I would resist the urge to start with Gradle tweaks. Find the package shipping each .so, upgrade or replace that package, cut a native build, and verify the report. Repeat until the warning is gone.

The experience was a good reminder that React Native apps are still native apps at release time. JavaScript can hide a lot of platform complexity during feature development, but store compliance eventually brings you back to the binaries you ship.


Profile picture

Hi, I'm Pavel Ivanov, a staff engineer building React Native apps and AI-powered products.

I write about frontend and mobile engineering, React and React Native, platform architecture, technical leadership, and the practical side of building reliable products and teams.

Say hi on LinkedIn.

* use of site content is strictly prohibited without prior written approval