If Google Play Still Rejects Your Flutter App After the May 2026 Deadline: A Practical Guide to the 16KB Page Size Requirement

“I fixed this last year — why is it getting rejected again?” That’s the question popping up over and over in Flutter developer communities and issue trackers over the past few weeks. Google Play’s 16KB memory page size requirement was originally enforced starting November 1, 2025, with individual extension requests able to push it back to as late as May 31, 2026. Today is July 24, 2026, which means even that extension window closed nearly two months ago. And yet plenty of apps are still getting bounced on upload. The reason is almost always the same: the app’s own code is compliant, but a third-party native plugin it depends on still isn’t 16KB-aligned.
This isn’t another announcement recap — it’s a practical playbook for anyone actually stuck on this problem right now.
Key Takeaways
- Google Play requires 16KB page alignment for new apps/updates that target Android 15 (API 35) or higher and ship native code (.so files). Apps written purely in Dart are unaffected.
- The original deadline was November 1, 2025, extendable to May 31, 2026 via an individual extension request. Past that date, there’s no more grace period — it’s enforced immediately.
- The Flutter engine itself (
libflutter.so,libapp.so) has supported 16KB since Flutter 3.32.8. The real problem is almost always the.sofiles bundled by third-party plugins.- You can verify alignment yourself ahead of time with
zipalign,llvm-objdump, or the App Bundle Explorer in Play Console.- If you don’t add an alignment check to CI, this problem will come back.
Why the 16KB page size requirement exists, and who it applies to
Android has traditionally managed memory in 4KB units (pages). Starting with Android 15, AOSP added support for 16KB page sizes, and newer high-end devices (particularly those with more RAM) are increasingly shipping with 16KB as the default. In its own official documentation (developer.android.com/guide/practices/page-sizes), Google cites the following performance gains from internal testing — though Google itself notes these are “early results and may vary on real devices”:
- App launch time under memory pressure improved by an average of 3.16%, with some apps improving by up to 30%
- Power draw during app launch down by an average of 4.56%
- Camera hot-start time down 4.48% on average, cold-start down 6.60%
- System boot time down about 8% (roughly 950ms) on average
Based on these numbers, Google mandated that starting November 1, 2025, new apps and updates targeting Android 15 (API 35) or higher must support 16KB page sizes on 64-bit devices. As confirmed across several developer community threads since then (including “Clarification on 16 KB page size extension” on the Google Play developer community), submitting an individual extension request through Play Console could push that deadline out to May 31, 2026. At the time of writing (July 2026), that extension window has also closed, so any app that hasn’t addressed this gets blocked immediately at upload.
The important thing to note is that pure Dart/Flutter apps with no native code need to do nothing at all. Google’s own blog states explicitly that “apps without native code require no changes and are already compatible.” The real issue is the overwhelming majority of production Flutter apps that pull in native plugins with bundled .so files — for cameras, animations, databases, maps, payment SDKs, and more.
How to check if your app is affected: a 3-step diagnosis
Step 1 — Pull the list of native plugins first
Start by identifying which dependencies in pubspec.yaml are likely to include native code. The usual suspects are cameras, databases (sqlite, realm, isar native backends), maps (google_maps_flutter), animation libraries (rive, lottie native renderers), image processing (flutter_image_compress), payment/security SDKs, crash reporters (sentry_flutter, firebase_crashlytics), WebRTC, and ML inference libraries (tflite, onnxruntime).
Step 2 — Inspect the .so files inside your build output directly
Suspicion alone isn’t enough — you need to open up the actual build artifact and check.
# Produce a release build first
flutter build appbundle --release
# List the .so files bundled inside
unzip -l build/app/outputs/bundle/release/app-release.aab | grep "\.so"
You can verify whether each .so is 16KB-aligned directly with llvm-objdump (example path on macOS):
$ANDROID_HOME/ndk/<NDK_VERSION>/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objdump \
-p path/to/librive_text.so | grep LOAD
If the output shows align 2**14 (16384 bytes), you’re fine. If it shows 2**13 (8192) or lower, that’s 4KB alignment, and it’s a problem. bundletool is also handy for checking an entire AAB at once:
bundletool dump config --bundle=app-release.aab | grep alignment
# PAGE_ALIGNMENT_16K is fine, PAGE_ALIGNMENT_4K means it isn't fixed yet
For a single APK, use zipalign’s verification mode:
$ANDROID_HOME/build-tools/35.0.0/zipalign -v -c -P 16 4 app-release.apk
If you’re using Android Studio, the fastest route is File > Profile or Debug APK (or Build > Analyze APK), then checking the Alignment column under the lib/arm64-v8a folder. Whichever file shows a warning icon is your culprit.
Step 3 — Pre-validate before uploading to Play Console
Play Console’s App Bundle Explorer automatically flags 16KB-unaligned libraries when you upload an AAB. The rejection messages that keep showing up in the wild look like this:
- “App bundle contains native libraries that aren’t aligned to 16 KB page boundaries”
- “librive_text.so — 4 KB LOAD section alignment, but 16 KB is required for 16 KB devices”
Since the message spells out the exact filename, all you need to do is trace that .so back to whichever plugin it came from.
Flutter / NDK / AGP version compatibility matrix
| Component | Minimum required | Recommended | Notes |
|---|---|---|---|
| Flutter SDK | 3.32.8+ | Latest stable (3.35 or newer) | The engine itself supports 16KB starting at 3.32.8. Check your current version with flutter doctor -v |
| Android NDK | r27+ | r28 series | Starting at r28, 16KB alignment is compiled by default. r27 requires manually adding a linker flag |
| AGP (Android Gradle Plugin) | 8.5.1+ | Latest 8.7.x or newer | 8.3–8.5 produce 16KB alignment, but bundletool won’t auto-zipalign the APK |
| Gradle | 8.9+ | Latest matching your AGP version | Based on the compatible pairing with AGP 8.5.1 |
| Android SDK Build-Tools | 35.0.0+ | Latest | The zipalign -P 16 option is only supported from this version onward |
| compileSdk / targetSdk | 35 | 35 or higher | Corresponds to the Android 15 API level |
There’s one trap to watch for. As of July 2026, Flutter’s flutter_tools Gradle plugin defaults to NDK version 27.0.12077973 (confirmed in flutter/flutter issue #175022). r27 technically meets the minimum requirement, but it does not compile with 16KB alignment by default, so to be safe you need to either add the linker flag manually or bump the NDK to the r28 series. Specify it in android/app/build.gradle (or .kts) like this:
android {
ndkVersion "28.2.13676358" // Check the download page for the latest r28.x and substitute it here
defaultConfig {
externalNativeBuild {
cmake {
// If you must stick with r27, add this flag
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
}
}
}
}
If you’re on a legacy project running AGP 8.0 or below, you’ll also need this line in gradle.properties:
android.bundle.enableUncompressedNativeLibs=false
There’s one more bug that keeps getting reported in the wild. On certain Flutter 3.32.8/3.35.1 and AGP combinations, raising minSdkVersion to 23 or higher triggers a 16KB warning in the App Bundle Explorer even on a freshly generated project (flutter/flutter issue #173949). Dropping minSdkVersion back to 21 or lower makes the warning disappear, but that’s a workaround, not a real fix — it’s better to prioritize getting Flutter/AGP onto the latest stable versions instead.
When you run into an unpatched third-party plugin: real cases and how to handle them
The most frustrating situation is when your own code is fixed, but the vendor of a plugin you depend on hasn’t rebuilt its .so yet. Here are two real cases worth looking at.
Case 1 — Rive animations. The legacy rive package (the 0.13.x series) ships librive_text.so built with 4KB alignment, so Play Console rejects it outright. The rive-app/rive-flutter repo has this request logged repeatedly for well over a year, across issues #458, #488, #524, #539, #547, and #553. The actual fix isn’t clinging to the old rive package — it’s migrating to its successor package, rive_native. Starting at version 0.0.3, rive_native’s changelog explicitly lists “Android: support 16 KB page sizes,” referencing issue #479.
Case 2 — SQLite. sqlite3_flutter_libs resolved this at version 0.5.25, with its changelog stating “Support 16KiB page sizes on Android 15.” That said, as of now (0.6.0+eol) the package itself is deprecated, and its changelog notes that “sqlite3_flutter_libs is no longer needed starting with sqlite3 3.x.” In other words, for older projects, simply upgrading to current packages is often the fix in itself.
These two cases point to a practical order of operations:
-
First, try upgrading to the latest version. Most popular packages have already shipped a fix or are working on one. Search the changelog first for keywords like “16KB”, “page size”, or “alignment.”
-
Use
dependency_overridesto pin a specific transitive dependency version. This is useful when the top-level package hasn’t updated, but the native binding package inside it has a newer version available.dependency_overrides: rive_native: ^0.0.5 -
Gradle
excludeplus manually specifying the latest AAR. If the vendor has published new.sofiles as a separate Maven artifact, you can exclude the outdated AAR pulled in by the plugin and add the new version as a direct dependency instead.implementation("com.example:some-native-sdk:2.3.0") { exclude group: "com.example", module: "some-native-sdk-legacy" } -
Swap in your own
.sovia ajniLibssource set. If you’ve obtained a community-recompiled 16KB-aligned binary, or rebuilt one yourself with the NDK, add a source set that takes priority over the vendor’s AAR.android { sourceSets { main { jniLibs.srcDirs += ["src/main/jniLibs16k"] } } packagingOptions { pickFirst "lib/arm64-v8a/librive_text.so" } } -
If nothing else works, fork it. If the plugin is open source, forking the repo, bumping just the NDK version to r28, rebuilding, and pointing
pubspec.yamlat your git fork is a reasonable stopgap.dependencies: rive: git: url: https://github.com/<your-org>/rive-flutter.git ref: fix/16kb-alignment -
As a last resort, consider a replacement library. If there’s no timeline for a vendor fix, swapping in a different package with similar functionality is also an option (for example, considering a Lottie-based alternative in place of an outdated animation library).
One thing worth making explicit: the device-level “16KB backward-compatibility mode” (adb shell setprop bionic.linker.16kb.app_compat.enabled true) is meant to make testing easier during development — it is not a way to get past Play Console review. It’s a setting on the user’s device, not a property of the build you ship.
Adding automated 16KB alignment checks to your CI pipeline
Fixing it once isn’t the end of the story. If a plugin version gets downgraded, or a new teammate adds an unaligned SDK, the problem comes back. Automatically verifying alignment on every release build in CI, and failing the build before it ever reaches Play Console, is the key to preventing regressions. Here’s a GitHub Actions example:
name: android-release-check
on:
push:
branches: [main]
jobs:
check-16kb-alignment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: "stable"
- name: Build App Bundle
run: flutter build appbundle --release
- name: Download bundletool
run: |
BUNDLETOOL_URL=$(curl -s https://api.github.com/repos/google/bundletool/releases/latest \
| grep "browser_download_url.*jar" | cut -d '"' -f 4)
curl -sL -o bundletool.jar "$BUNDLETOOL_URL"
- name: Extract universal APK
run: |
java -jar bundletool.jar build-apks \
--bundle=build/app/outputs/bundle/release/app-release.aab \
--output=out.apks --mode=universal
unzip -o out.apks -d out_apks
- name: Verify 16KB page alignment
run: |
ZIPALIGN=$ANDROID_HOME/build-tools/35.0.0/zipalign
$ZIPALIGN -v -c -P 16 4 out_apks/universal.apk || \
(echo "::error::16KB page alignment failed — check your .so files" && exit 1)
If this step fails, the zipalign output tells you exactly which .so is the problem, so you can immediately trace that filename back to the plugin responsible. If you’re working with a larger team, having Renovate or Dependabot automatically open update PRs for native packages that have caused trouble before — rive_native, sqlite3, google_maps_flutter, sentry_flutter — also helps prevent this from recurring.
Wrap-up checklist
- Pulled the list of native-dependent plugins from
pubspec.yaml - Ran
flutter build appbundle --releaseand directly verified.soalignment withzipalign -c -P 16orllvm-objdump - Upgraded to Flutter 3.32.8+, NDK r28 series, AGP 8.5.1+, and Build-Tools 35.0.0+
- Re-checked whether changing
minSdkVersiontriggers a new App Bundle Explorer warning - For unpatched plugins, checked the changelog for “16KB/page size/alignment” keywords to see if a fixed version exists
- If no updated version exists, evaluated workarounds in order:
dependency_overrides, swappingjniLibs, forking - Added an alignment verification step to CI to prevent regressions in future releases
If you’re stuck on this right now, the root cause is almost never your own code — it’s an outdated third-party native dependency. Work through the steps above one by one, and you can usually pin down the cause within a day.