Independent product studio · Swedenhello@karelialabs.com

Guide

Android apps with NDK code, Kotlin or Java and Google Play's 16 KB page size rule

Short answerAn app written only in Kotlin or Java, libraries and SDKs included, already supports 16 KB pages. With native code: build with NDK r28 or newer (or add Google's linker flags), use AGP 8.5.1 or higher, update SDKs with native libraries and check every 64-bit library.

Updated

What the Play Console message means

Google's page size guide says that all apps targeting Android 15 (API level 35) and higher must support 16 KB memory page sizes on 64-bit devices on Google Play, and that from February 1, 2027 updates without 16 KB support can't be released. Play Console shows a compatibility warning for a bundle that doesn't support them.

Google Play already requires new apps and updates to target API level 36 (Google's target API rule; Wear OS, Android Automotive OS, Android TV and Android XR have lower levels). So for a phone or tablet app, the 16 KB rule applies to every update that contains native code.

The warning is about native libraries, the .so files for the 64-bit ABIs arm64-v8a and x86_64. A library fails when its LOAD segments are aligned to 4 KB instead of 16 KB, or when it is stored uncompressed and does not start on a 16 KB boundary in the zip. The libraries can be your own, built with the NDK, or come with an SDK you added.

Does your app have native code?

Google's page says that an app that only uses Kotlin or Java code, including all its libraries and SDKs, already supports 16 KB devices, though Google still recommends testing it in a 16 KB environment. An app has native code if it uses the NDK, links a third-party native library or SDK, or is made with an app builder that uses native libraries on the device.

A dependency added for something else can bring native code with it, for example an SDK for crash reporting or storage. List the .so files in the build to be sure. Google's guide and the vendor pages linked here were read on 15 November 2026.

Find the library that fails

  1. List the native libraries in the build. In a macOS, Linux or Git Bash terminal: unzip -l app-release.aab | grep '\.so$'. In Windows PowerShell: tar -tf .\app-release.aab | Select-String '\.so$'. In an AAB they are under base/lib/<abi>/, in an APK under lib/<abi>/.
  2. Look at the arm64-v8a and x86_64 folders; the rule is about 64-bit devices. Match each file name against the table below to see whether it comes from the engine, a plugin or an SDK.
  3. Check how each library is aligned. Ship Check (below) checks all of them at once. In Android Studio, Build > Analyze APK... shows an Alignment column that warns about every library that is not 16 KB aligned.
LibraryComes fromWhat to do
Your own librariesYour NDK codeRebuild as below.
libc++_shared.soThe NDK's C++ runtimeGoogle says copies from NDK r26 and lower are not always 16 KB aligned. Rebuild with a newer NDK, or link the C++ library statically if you can't.
libsentry.so, libsentry-android.soSentry Android SDKSentry Java SDK 7.18.0 added 16 KB support. Update Sentry.
libmmkv.soMMKV (Tencent)MMKV 1.3.14 lists 16K page size support. Update MMKV.
libcrashlytics*.soFirebase Crashlytics NDKUpdate the Crashlytics NDK dependency. We have not checked which release added 16 KB support.
libbugsnag-ndk.so, libbugsnag-plugin-android-anr.soBugsnag Android SDKUpdate the Bugsnag SDK. We have not checked which release added 16 KB support.
libapplovin-native-crash-reporter.soAppLovin SDKUpdate the AppLovin SDK, or the mediation SDK that bundles it. We have not checked which release added 16 KB support.
libdatastore_shared_counter.soAndroidX DataStoreUpdate androidx.datastore to a release built with NDK r28 or newer.

Rebuild your own native code

NDK r28 and higher compile 16 KB-aligned by default. With NDK r27 or lower, add Google's two linker flags. For ndk-build, in Android.mk:

LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384

For CMake, in CMakeLists.txt:

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    "-Wl,-z,max-page-size=16384"
    "-Wl,-z,common-page-size=16384"
)
  • Prebuilt shared libraries in your project have to be recompiled the same way.
  • Code must not assume a 4 KB page. Use getpagesize() or sysconf(_SC_PAGESIZE) instead of the PAGE_SIZE constant, which is undefined in 16 KB mode from NDK r27.

Package the libraries for 16 KB

Libraries stored uncompressed must start on a 16 KB boundary in the zip. Use Android Gradle Plugin 8.5.1 or higher. If you can't, Google's page describes packaging them compressed with useLegacyPackaging, which makes the installed app larger. To see what an AAB asks for:

bundletool dump config --bundle=app-release.aab | grep alignment

PAGE_ALIGNMENT_16K means the bundle asks for 16 KB zip alignment; PAGE_ALIGNMENT_4K means the APKs built from it get 4 KB aligned libraries.

What an older NDK build looks like

We ran Ship Check on Termux 0.118.3 from F-Droid, a plain NDK app whose libraries carry NDK r22b markers. All four of its 64-bit libraries, libtermux.so and libtermux-bootstrap.so for arm64-v8a and x86_64, are 4 KB aligned and fail Google's RELRO rule. They are the app's own libraries, so Ship Check lists them by file name.

Check the build before you upload it

  1. Open Ship Check and drop the .aab or .apk on the page. It is free, runs in your browser and nothing is uploaded.
  2. Read the 16 KB results. Every 64-bit library is checked for LOAD segment alignment and for Google's RELRO rule, and each failing library is named with the engine, plugin or SDK that ships it where Ship Check knows it. A library it does not know is listed by file name.
  3. On a build server, run Ship Check CLI: node shipcheck.mjs app-release.aab --fail-on=error. It exits with code 1 when a check fails, so the pipeline stops before the upload. Add --date 2027-02-01 to see the build as it will be judged on that day.

Alignment is not the only test. Google's page also has a rule for the GNU_RELRO segment: if it ends inside a 16 KB page that also holds writable data, the app crashes with a segmentation fault (SIGSEGV) on a 16 KB device when that data is written. Google says this typically happens with libraries built with NDK r27 or lower without the 16 KB flags.

Ship Check reads what is in the file. It cannot see your Play Console, and a passing report does not guarantee that Google Play accepts the app.

Test on a 16 KB device

Google's page lists the ways: an Android Emulator with a 16 KB system image, Cuttlefish, or the Boot with 16KB page size developer option on Pixel 8 and Pixel 9 series phones. adb shell getconf PAGE_SIZE returns 16384 when the device runs with 16 KB pages.

The same rule in other engines

FAQ

My app is made with an app builder. Does this apply?

If the builder puts native libraries in your app, yes: Google's page counts an app made by a third-party app builder that uses native libraries as having native code. List the .so files in the build or drop it on Ship Check. Only the builder's maker can rebuild libraries that fail.

I only write Kotlin. Do I need to do anything?

If no library or SDK in the app ships a .so file, Google's page says the app already supports 16 KB devices. Check the build to be sure, and test it in a 16 KB environment.

What does PAGE_ALIGNMENT_4K in bundletool mean?

That the APKs built from the bundle get 4 KB aligned .so files in the zip. Google's page says to use AGP 8.5.1 or higher.

Is my build uploaded anywhere?

No. Ship Check reads the file in your browser, and Ship Check CLI reads it on your own machine.

More guides

More from Karelia Labs