Android15适配16kb
Android15适配16kb
1.前言:
之前把其中一个关于遥控器控制的App上架到了Googleplay,并且升级到了Android15,但是由于项目是在ott盒子和TV设置上使用的,而且项目的功能很简单,就2个页面,没有涉及到16kb,只是把Android12文件读写、蓝牙权限、gms升级了一下,这次是新的Ai应用里面用到了mmkv进行数据存储,而Google明确规定需要适配16kb.
**自2025 年 11 月 1 日**起,所有提交到 Google Play 且使用原生 C/C++ 代码(面向 Android 15 及以上设备)的新应用和应用更新都必须支持 16 KB 的页面大小。这是确保您的应用在最新 Android 硬件上发挥最佳性能的关键一步。无需原生 C/C++ 代码或依赖项,仅使用 Kotlin 和 Java 编程语言的应用已经兼容,但如果您使用的是原生代码,现在是时候采取行动了。
Starting November 1st, 2025, all new apps and updates to existing apps submitted to Google Play and targeting Android 15+ devices must support 16 KB page sizes on 64-bit devices.
Google开始正式强制Android适配16 KB Page Size,这是一个关键的技术要求,确保您的用户能够在新设备上获得性能提升,并为平台未来在新硬件上的改进性能做好准备。如果不重新编译以支持16 KB页面,您的应用在这些设备变得更广泛普及时可能无法在这些设备上正常运行。官方数据显示,配置为使用16 KB页面大小的设备,平均会使用略多一些的内存,但系统和应用的性能也会得到各种提升。
2.概念:
什么是16K页面对齐?告别4K时代
在计算机操作系统中,内存以固定大小的“页面”为单位进行管理。长久以来,安卓系统一直沿用4KB作为标准的页面大小。所谓“页面对齐”,就是确保内存中的数据块(尤其是应用的可执行文件和库)从能被页面大小整除的地址开始存放。
随着硬件的飞速发展,现代智能手机配备了越来越大的内存(RAM),4KB的页面大小在管理庞大内存时逐渐显得力不从心,导致了性能瓶颈。为了突破这一限制,安卓系统从安卓15开始引入了对16KB页面的支持,并将在安卓16及更高版本中将其作为一项强制性的技术要求,特别是对于搭载大内存的设备。这意味着,应用和系统进程将以16KB为单位进行内存的分配和管理。
3.性能提示预览:
Google 测试显示,16 KB 页面可以带来:
- 应用启动速度提升:3% 到 30% 不等
- 电池续航改善:平均提升 4.5%
- 相机启动加速:4.5% 到 6.6% 的提升
- 系统启动加速:约 8% 的提升
4.未适配16kb前的截图:
5.适配详细步骤:
- 对开发者的要求与详细适配指南
- 升级Gradle插件版本
- 验证所有原生so的对齐
- 处理第三方sdkso对齐
- 启动测试环境充分验证各种机型和设备
5.1 升级您的构建工具链
这是最基础也是最关键的一步,现代化的构建工具会自动处理大部分对齐工作。
-
Android Gradle 插件 (AGP): 必须将AGP版本升级至 8.5.1或更高。新版本的AGP内置了对16KB对齐的支持,它会在打包APK时自动确保
.so
文件以正确的对齐方式存储。 -
Android NDK:
推荐使用
NDK r28或更高版本
。您需要通过在链接器(Linker)标志中添加特定参数来指示编译器生成16K对齐的ELF文件。
-
对于CMake (在
build.gradle.kts
或build.gradle
中):android {...defaultConfig {...externalNativeBuild {cmake {// -Wl, 后面是传递给链接器的参数cppFlags += "-Wl,-z,max-page-size=16384" }}} }
-
对于ndk-build (在
Android.mk
中):LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
-
5.2:验证所有原生库(.so)的对齐
您需要手动验证应用中所有的原生库(包括您自己编写和第三方提供的)是否都已正确对齐。
-
使用
readelf
工具:readelf
是分析ELF文件的标准工具,位于Android NDK的工具链中。您可以使用以下命令来检查
.so
文件的对齐情况。
# 先通过类似如下命令找到 NDK 中的 readelf find sdk/ndk/28.2.13676358/ -name *readelf* # 检查对齐的命令如下 sdk/ndk/28.2.13676358/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-readelf.exe -l <your-so-file.so> | grep "LOAD.*10000" # 可以通过 find ./ *.so 找到当前项目使用的所有 so
-
如何解读结果:
- 正确对齐: 如果命令有输出,并且输出中
p_align
的值为0x10000
(即65536,16KB的十六进制表示),则表示该库已正确对齐。 - 未正确对齐: 如果
p_align
的值是0x1000
(4KB) 或其他非0x10000
的值,则说明该库未适配16K对齐。
- 正确对齐: 如果命令有输出,并且输出中
5.3.Gradle插件版本升级:
6.mmkv适配:
由于项目中只使用的mmkv库,所以只需要升级这一个版本即可.
未升级前的版本:
升级后的版本:
[versions]
agp = "8.9.3"
#Detekt
detekt = "1.23.3"
#KSP
compiler = "8.9.10"
ksp = "2.1.10-1.0.31"
kotlin = "2.1.10"
coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.1"
material = "1.12.0"
activity = "1.10.1"
constraintlayout = "2.2.1"
coze-api = "0.3.3"
rxjava = "2.2.21"
rxandroid = "2.1.1"
glide = '4.16.0'
glideCompose = "1.0.0-beta01"
gson = "2.13.1"
okhttp = "5.1.0"
logging-interceptor = "5.1.0"
okhttputils = "2.6.2"
utilcodex = "1.31.1"
multidex = "2.0.1"
startup = "1.2.0"
lottie = "6.6.7"
baseRecyclerViewAdapterHelper = "3.0.4"
mmkv = "2.2.3"
rxpermissions = "0.9.3"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
coze = { group = "com.coze", name = "coze-api", version.ref = "coze-api" }
rxjava2 = {group = "io.reactivex.rxjava2", name = "rxjava",version.ref = "rxjava"}
rxandroid = {group = "io.reactivex.rxjava2", name = "rxandroid",version.ref = "rxandroid"}
glide = { module = "com.github.bumptech.glide:ksp", version.ref = "glide" }
glide-compose = { group = "com.github.bumptech.glide", name = "compose", version.ref = "glideCompose" }
glide-compiler = { group = "com.github.bumptech.glide",name = "compiler", version.ref = "glide" }
gson = {group = "com.google.code.gson", name = "gson",version.ref = "gson"}
okhttp = {group = "com.squareup.okhttp3", name = "okhttp",version.ref = "okhttp"}
okhttputils = {group = "com.zhy", name = "okhttputils",version.ref = "okhttputils"}
logging-interceptor = {group = "com.squareup.okhttp3", name = "logging-interceptor",version.ref = "logging-interceptor"}
utilcodex = {group = "com.blankj",name = "utilcodex",version.ref = "utilcodex"}
multidex = {group = "androidx.multidex",name = "multidex",version.ref = "multidex"}
startup = {group = "androidx.startup",name = "startup-runtime",version.ref = "startup"}
lottie = {group = "com.airbnb.android",name = "lottie",version.ref = "lottie"}
baseRecyclerViewAdapterHelper = {group = "com.github.CymChad",name = "BaseRecyclerViewAdapterHelper",version.ref = "baseRecyclerViewAdapterHelper"}
mmkv = {group = "com.tencent",name = "mmkv",version.ref = "mmkv"}
rxpermissions = {group = "com.tbruyelle.rxpermissions2",name = "rxpermissions",version.ref = "rxpermissions"}[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
7.适配16kb后的截图:
8.其他第三方SDK和预编译库适配
应用中未对齐的库通常来自第三方SDK。
- 联系提供商: 一旦发现未对齐的第三方库,应立即联系其提供商,要求他们提供支持16K页面对齐的新版本。由于这是Google Play的强制要求,主流SDK提供商通常会积极跟进。
- 检查更新日志: 关注您所使用的所有原生SDK的官方更新日志和发布说明,确认哪个版本开始支持16K对齐。
9.模拟器测试效果截图:
10.手机测试效果:
Android15的手机也能正常使用,可以证明适配是没问题的,其他的第三方sdk参考类似的步骤
11.总结:
- 由于我只要这个库有so,所以需要修改的地方不是很多。
- 升级Gradle插件版本
- 验证所有原生so的对齐
- 处理第三方sdkso对齐
- 启动测试环境充分验证各种机型和设备