Google is requiring all new submissions to playstore have 16kb page size support/alignment. This is I assume for new devices anyways so is what we should all be doing and aiming towards. If you have an android native project, just using newer SDKs should do it. If you’re compiling some C code for android to bundle, using NDK 28 or later “should” take care of it for you.

However at Open Privacy we build Cwtch in a combination of Go lang for the protocol library and Flutter and Dart for the UI. One would think Go also being a Google project would seamlessly support this, but that is not so much the case, in part because gomobile is still an ‘x’ project and not official, and that is what Open Privacy has been using to package our Go library for Android.

However, all the pieces are there, just took a little collecting to assemble.

I grabed the latest gomobile, (gomobile@v0.0.0-20250911085028-6912353760cf), and NDK 28.1.13356709 to start. Gomobile is flexible on what NDK it works with, so for now it’s minSDK is still 16, however NDK 28 needs to target 21 and above, so a crucial step was adding -androidapi 21 to the gomobile bind compiler call. The other required piece AFAICT was adding env CGO_LDFLAGS="-O2 -s -w -Wl,-z,max-page-size=16384". The -O2 was just maintaining what go env said the default CGO_LDFLAGS had. -s should strip sumbol table info, which probably happens later anyways, but was suggested and didn’t seem like a bad idea. -w “inbibits warning messages” so take your pick. The important part is -Wl,-z,max-page-size=16384. -Wl passes linker options, the ‘-z’ appears to be a strictness add to linking causing errors on symbols it can’t find to link to at linktime rather than later at runtime. And finally -max-page-size=16384 is the important option -Wl passes to the linker telling it to make bigger 16kb pages. The result should look something like:

env CGO_LDFLAGS="-O2 -s -w -Wl,-z,max-page-size=16384" gomobile bind -androidapi 21 ...

To confirm, you can unzip your .aar and use llvm-objdump. For example:

> unzip cwtch.aar
> llvm-objdump -p jni/arm64-v8a/libgojni.so | grep LOAD
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**14
    LOAD off    0x0000000000169db0 vaddr 0x000000000016ddb0 paddr 0x000000000016ddb0 align 2**14
    LOAD off    0x000000000050bd20 vaddr 0x0000000000513d20 paddr 0x0000000000513d20 align 2**14
    LOAD off    0x0000000000770e70 vaddr 0x000000000077ce70 paddr 0x000000000077ce70 align 2**14

What you are looking for is the align to be 2**14 which is 2^14 which is 16384, or 16kb alignment. By default we usually get 2**12 which is 4096 or just 4kb page size alignment.

If you use Docker for your CI and builds Open Privacy managers the container openpriv/go-cross-compiler which with the new 2025.09 tag comes preloaded with Go 1.25, Android SDK 35, NDK 28, gomobile, arm8 gcc cross compiler, and mingw for compiling to Windows. The Dockerfile is in Open Privacy’s gitlab for inspection and personal adaptation. You can inspect our final build commands in the Cwtch autobindings Makefile and you can see the simple invocation and use in autobinding’s .drone.yml CI file. (Note the gomobile init is now deprecated and unneeded as it’s done in container build and will be deleted from our CI steps shortly after publication).