Your app does not support 16 KB memory page sizes on Google Play Store

Fixing Your app does not support 16 KB memory page sizes on Google Play Store
Flutter · Android · Play Store

Fixing Flutter App Bundle Rejection:
16 KB Memory Page Size Error on Google Play Store

A complete, step-by-step troubleshooting guide — from diagnosing the failing native library to force-resolving the exact Gradle dependency causing Play Store rejection.

📅 May 2025 ⏱ 10 min read 🏷 Android · Flutter · NDK · Gradle
01 — Background

What Is the 16 KB Page Size Requirement?

Starting with Android 15, Google introduced support for devices that use 16 KB memory page sizes instead of the traditional 4 KB. This change primarily targets high-performance ARM64 devices where larger page sizes improve memory efficiency and app launch speed.

Google Play Store now requires all apps with native code to support 16 KB page alignment in their compiled .so (shared object) libraries. If even a single native library in your app bundle is aligned to 4 KB instead of 16 KB, your release will be blocked.

AlignmentHex ValuePlay StoreMeaning
4 KB0x1000❌ REJECTEDOld default — fails new requirement
16 KB0x4000✅ PASSRequired for Play Store compliance
64 KB0x10000✅ PASSFlutter engine default — fine

This affects not just your own Dart/native code, but every pre-built .so bundled by your Flutter plugins and Android dependencies. A single unaligned library from a third-party SDK is enough to trigger rejection.

02 — The Error

Understanding the Play Store Error

⛔ Play Store Error (Version Code)

Your app does not support 16 KB memory page sizes.
This App Bundle contains native code that is not aligned to 16 KB page boundaries. Learn More →

This error appears in the Play Console under App Bundle Explorer → Messages after uploading your release AAB. It is a hard blocker — the release cannot be published until resolved.

You may also see two accompanying warnings:

⚠️ Warning 1 — Unsupported Devices

This release no longer supports N devices that were supported in your previous release. This is caused by restricting abiFilters to 64-bit architectures only, dropping 32-bit ARM devices.

⚠️ Warning 2 — Missing Debug Symbols

This App Bundle contains native code, and you’ve not uploaded debug symbols. Symbols help analyze crashes and ANRs. This is a warning, not a blocker, but should be resolved.

03 — Fix 1

Upgrade NDK to Version 28

The most common root cause is using an NDK version older than 28. NDK 27 and below do not fully support 16 KB page alignment when compiling native code.

NDK Version16 KB SupportRecommendation
< 27.x❌ NoneDo not use
27.x⚠️ PartialWarnings become errors on Play Store
28.x✅ FullRequired minimum

Install NDK 28 in Android Studio

  1. Open SDK Manager

    Go to Android Studio → Settings → Appearance & Behavior → System Settings → Android SDK

  2. Select SDK Tools tab

    Check the “Show Package Details” checkbox in the bottom right corner.

  3. Install NDK 28.2.13676358

    Expand “NDK (Side by side)” and check version 28.2.13676358, then click Apply.

Set NDK version in build.gradle.kts

Kotlin DSL
// android/app/build.gradle.kts
android {
    namespace = "com.example.app"
    compileSdk = 35
    ndkVersion = "28.2.13676358"  // ✅ NDK 28 — 16 KB aligned
    // ndkVersion = "27.0.12077973"  // ❌ NDK 27 — fails Play Store
}
04 — Fix 2

Update build.gradle.kts Completely

Beyond the NDK version, several packaging and build settings must be configured correctly. Here is a complete, production-ready build.gradle.kts for a Flutter app targeting Play Store compliance:

android/app/build.gradle.kts
import java.util.Properties

plugins {
    id("com.android.application")
    id("com.google.gms.google-services")
    id("kotlin-android")
    id("dev.flutter.flutter-gradle-plugin")
}

android {
    val keystoreProperties = Properties().apply {
        load(File(rootDir, "key.properties").inputStream())
    }

    namespace = "com.example.app"
    compileSdk = 35
    ndkVersion = "28.2.13676358"  // ✅ Critical

    compileOptions {
        isCoreLibraryDesugaringEnabled = true
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 23
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName

        ndk {
            // 64-bit only — drops 32-bit devices but enables 16KB compliance
            abiFilters += listOf("arm64-v8a", "x86_64")
        }
    }

    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties["keyAlias"] as String
            keyPassword = keystoreProperties["keyPassword"] as String
            storeFile = file(keystoreProperties["storeFile"] as String)
            storePassword = keystoreProperties["storePassword"] as String
        }
    }

    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            isShrinkResources = true
            isCrunchPngs = false
            signingConfig = signingConfigs.getByName("release")
            ndk {
                debugSymbolLevel = "FULL"  // Required for debug symbols upload
            }
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    packaging {
        jniLibs {
            useLegacyPackaging = false  // ✅ Required for 16KB compliance
        }
        dex {
            useLegacyPackaging = false
        }
    }
}

flutter {
    source = "../.."
}

dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
    implementation(enforcedPlatform("com.google.firebase:firebase-bom:33.13.0"))
    implementation("com.google.firebase:firebase-analytics")
    implementation("com.google.firebase:firebase-auth")
    implementation("com.google.firebase:firebase-firestore")
    implementation("com.google.android.gms:play-services-ads:23.6.0")
    implementation("com.android.billingclient:billing:7.1.1")
}

kotlin {
    compilerOptions {
        jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
    }
}
05 — Fix 3

Diagnose Which .so File Is Failing

Updating the NDK alone often doesn’t fix the issue, because pre-built .so libraries bundled inside Flutter plugins and Android dependencies retain their original alignment. You need to identify exactly which library is failing.

Step 1 — Extract the AAB

bash
cd build/app/outputs/bundle/release/

unzip -o app-release.aab -d aab_extracted 2>/dev/null

# List all native libraries
find aab_extracted -name "*.so" | sort

Step 2 — Run the alignment checker script

Save the following as check_alignment.py and run it from the same directory:

Python
import struct, os

def check_alignment(filepath):
    with open(filepath, 'rb') as f:
        data = f.read()
    if data[:4] != b'\x7fELF':
        return "NOT_ELF"
    bits = data[4]  # 1=32bit, 2=64bit
    if bits == 2:  # 64-bit ELF
        e_phoff     = struct.unpack_from('<Q', data, 32)[0]
        e_phentsize = struct.unpack_from('<H', data, 54)[0]
        e_phnum     = struct.unpack_from('<H', data, 56)[0]
        for i in range(e_phnum):
            off    = e_phoff + i * e_phentsize
            p_type = struct.unpack_from('<I', data, off)[0]
            if p_type == 1:  # PT_LOAD segment
                return struct.unpack_from('<Q', data, off + 48)[0]
    return None

root = "aab_extracted"
bad, ok = [], []

for dirpath, _, files in os.walk(root):
    for fname in files:
        if not fname.endswith(".so"): continue
        fpath = os.path.join(dirpath, fname)
        align = check_alignment(fpath)
        entry = (os.path.basename(fpath), hex(align) if align else "N/A", fpath)
        (bad if align == 0x1000 else ok).append(entry)

print(f"\n{'FILE':<45} {'ALIGN':<10} STATUS")
print("-" * 70)
for name, a, _ in sorted(ok + bad, key=lambda x: x[0]):
    status = "✅ OK" if a == "0x4000" or a == "0x10000" else "❌ 4KB FAILING"
    print(f"{name:<45} {a:<10} {status}")

print(f"\n❌ {len(bad)} FAILING  ✅ {len(ok)} OK")
bash
python3 check_alignment.py

Reading the output

The script will print a table like this. Any line is a Play Store blocker:

Output
FILE                                          ALIGN      STATUS
----------------------------------------------------------------------
libapp.so                                     0x10000    ✅ OK
libbarhopper_v3.so                            0x1000     ❌ 4KB FAILING
libdatastore_shared_counter.so                0x4000     ✅ OK
libface_detector_v2_jni.so                    0x4000     ✅ OK
libflutter.so                                 0x10000    ✅ OK
libimage_processing_util_jni.so               0x1000     ❌ 4KB FAILING

❌ 2 FAILING  ✅ 4 OK
06 — Fix 4

Pinpoint the Exact Gradle Dependency

Once you know which .so files are failing, trace them back to their source Gradle artifact. This is the most important step — without it, you may update the wrong package.

bash
# Search the Gradle cache for the failing .so files
find ~/.gradle -name "libbarhopper_v3.so" 2>/dev/null
find ~/.gradle -name "libimage_processing_util_jni.so" 2>/dev/null

# Also search pub-cache for Flutter plugin sources
find ~/.pub-cache -name "libbarhopper_v3.so" 2>/dev/null

The output will reveal the exact artifact name and version. For example:

Output example
# libbarhopper_v3.so comes from:
~/.gradle/caches/.../jetified-barcode-scanning-17.2.0/jni/arm64-v8a/libbarhopper_v3.so

# libimage_processing_util_jni.so comes from:
~/.gradle/caches/.../jetified-camera-core-1.3.1/jni/arm64-v8a/libimage_processing_util_jni.so
💡 Key insight

In the example above, the culprits are ML Kit Barcode Scanning 17.2.0 (ships libbarhopper_v3.so at 4 KB alignment) and CameraX camera-core 1.3.x (ships libimage_processing_util_jni.so at 4 KB alignment). These are pulled in transitively by Flutter plugins such as mobile_scanner and camera.

07 — Fix 5

Force-Resolve the Failing Dependencies

The transitive dependencies pulling in the old .so files can be force-overridden in Gradle without changing your Flutter plugin versions. Add a resolution strategy to both your root and app-level Gradle files.

android/build.gradle.kts (root level)

Kotlin DSL — root build.gradle.kts
allprojects {
    configurations.all {
        resolutionStrategy {
            // ✅ ML Kit Barcode — 17.3.0+ is 16KB aligned
            force("com.google.mlkit:barcode-scanning:17.3.0")

            // ✅ CameraX — 1.4.1+ is 16KB aligned
            force("androidx.camera:camera-core:1.4.1")
            force("androidx.camera:camera-camera2:1.4.1")
            force("androidx.camera:camera-lifecycle:1.4.1")
            force("androidx.camera:camera-view:1.4.1")
        }
    }
}

android/app/build.gradle.kts (app level)

Add inside the android { } block, after the packaging { } section:

Kotlin DSL — app build.gradle.kts
configurations.all {
    resolutionStrategy {
        force("com.google.mlkit:barcode-scanning:17.3.0")
        force("androidx.camera:camera-core:1.4.1")
        force("androidx.camera:camera-camera2:1.4.1")
        force("androidx.camera:camera-lifecycle:1.4.1")
        force("androidx.camera:camera-view:1.4.1")
    }
}

Clear Gradle cache and rebuild

bash
# Clear the specific transform caches for the failing artifacts
rm -rf ~/.gradle/caches/modules-2/files-2.1/com.google.mlkit
rm -rf ~/.gradle/caches/modules-2/files-2.1/androidx.camera

# Full clean rebuild
flutter clean
cd android && ./gradlew clean && cd ..
flutter pub get

flutter build appbundle --release \
  --obfuscate \
  --split-debug-info=./debug-symbols/

# Verify the forced versions are being used
cd android && ./gradlew app:dependencies | grep -E "barcode-scanning|camera-core"

The dependencies output should show the forced upgrade:

Gradle output
com.google.mlkit:barcode-scanning:17.2.0 -> 17.3.0  ✅
androidx.camera:camera-core:1.3.1 -> 1.4.1          ✅
08 — Fix 6

Update Flutter Plugins to 16 KB-Safe Versions

Some Flutter plugins bundle their own native .so files directly in the plugin package (not via Gradle), which means Gradle force-resolution won’t help. These must be updated at the Flutter level.

PluginRiskAction
mobile_scanner🔴 HighUpgrade from v3 → v5.2.3+ (breaking changes)
google_mlkit_face_detection🔴 HighUpgrade to ^0.12.0
camera🔴 HighUpgrade to ^0.11.0+
speech_to_text🟡 MediumUpgrade to latest ^7.x
flutter_tts🟡 MediumUpgrade to latest ^4.x
google_maps_flutter🟡 MediumUpgrade to ^2.10.0+
razorpay_flutter🔴 HighContact vendor or use web checkout
⚠️ mobile_scanner v3 → v5 — Breaking API Change

Version 5 changes the onDetect callback signature. Update your code from onDetect: (barcode, args) to onDetect: (capture) { final barcodes = capture.barcodes; }.

💡 Closed-source SDKs (e.g. Razorpay)

If a third-party payment or analytics SDK ships a closed-source .so that is not 16 KB aligned, contact the vendor directly. As an interim, use their web-based checkout flow which avoids the native library entirely.

09 — Fix 7

Upload Debug Symbols

The debug symbols warning does not block your release, but Google strongly recommends uploading them for crash analysis in Play Console and Firebase Crashlytics.

Generate symbols during build

Ensure debugSymbolLevel = "FULL" is set in your release build type (already shown in Fix 2). Then build:

bash
flutter build appbundle --release \
  --obfuscate \
  --split-debug-info=./debug-symbols/

Upload to Play Console

  1. Go to App Bundle Explorer

    Play Console → Your App → Release → App Bundle Explorer → select your version

  2. Click Downloads tab

    Find the “Native Debug Symbols” option and click the upload button.

  3. Upload the symbols ZIP

    The file is located at: build/app/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib/

10 — Understanding

The Device Count Warning Explained

When you restrict abiFilters to 64-bit architectures only (arm64-v8a, x86_64), your app drops support for 32-bit ARM devices (armeabi-v7a). This triggers the “N devices no longer supported” warning in Play Console.

ABI Filter ConfigDevices Supported16 KB Compliance
arm64-v8a, x86_6464-bit only✅ Easier
arm64-v8a, armeabi-v7a, x86_6432-bit + 64-bit⚠️ Harder
💡 Should you keep 32-bit support?

32-bit ARM devices (armeabi-v7a) are mostly Android 8–10 era hardware. Google’s own data shows less than 1% of active Play Store devices are exclusively 32-bit as of 2025. Dropping them simplifies 16 KB compliance significantly and is the recommended path for new releases.

11 — Final Checklist

Complete Resolution Checklist

✅ Before submitting to Play Store — verify all of these

#CheckHow to verify
1NDK version is 28.2.13676358ndkVersion in build.gradle.kts
2useLegacyPackaging = false for jniLibs and dexpackaging block in build.gradle.kts
3abiFilters set to 64-bit onlydefaultConfig ndk block
4No .so files with 0x1000 alignment in AABRun check_alignment.py script
5Transitive ML Kit / CameraX versions force-resolved./gradlew app:dependencies
6Flutter plugins updated to 16 KB-safe versionspubspec.lock versions
7Debug symbols generated and uploadedPlay Console → App Bundle Explorer
8Full clean rebuild performedflutter clean + gradlew clean

Final build command

bash
flutter clean
cd android && ./gradlew clean && cd ..
flutter pub get

flutter build appbundle --release \
  --obfuscate \
  --split-debug-info=./debug-symbols/

# Re-check alignment after build
unzip -o build/app/outputs/bundle/release/app-release.aab \
  -d build/app/outputs/bundle/release/aab_extracted 2>/dev/null

python3 check_alignment.py
# Should show: ❌ 0 FAILING  ✅ N OK

Still Facing the 16 KB Error?

If you’ve followed all the steps above and the Play Store rejection persists, the issue may be in a closed-source SDK, a deeply nested transitive dependency, or a platform-specific build configuration. Our experts have resolved this issue across dozens of production Flutter apps.

Contact Our Experts →

We’ll diagnose your specific AAB and resolve it — researchthinker.com

© 2025 ResearchThinker.com · Flutter · Android · Mobile Development

Leave a Reply

Your email address will not be published. Required fields are marked *

web_horizontal
About Us Disclaimer Privacy Policy Terms & Conditions Contact Us

Copyright © 2023 ResearchThinker.com. All rights reserved.