前言
前两年我们追 Android 14/15 改了一遍 targetSdkVersion、铺了一遍 foreground service 类型、做完了 16KB page size 适配。2026 年 Q1,Android 16 正式推送后,邮件列表、Reddit 的 r/androiddev 和国内几家手机厂商的内测群基本同时刷出了下面这段话:
"又来了。"
今天我们不堆砌 changelog,按"会真实改变你代码"的优先级,挑 7 个改动讲清楚。
一、必须知道的 7 件事
上一篇文章里我们把卡顿监控收尾;这一篇把"系统级"的事补齐——它直接决定你的 App 还能不能上 Google Play。
二、16KB Page Size:从可选变成必选
Android 15 上 16KB page size 还是"64 位设备强烈建议",Android 16 直接放到兼容性框架里。Play Console 从 2026-03-01 起不接受 4KB-only 的 NDK 包。
排查你的库
# 用 NDK 自带的检查脚本
$ANDROID_HOME/ndk/*/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readelf -l libyour.so | grep LOAD
如果 LOAD segment 对齐是 0x1000(4KB),就必须重编。重编译时只需要 APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true,ndk-build 会自动生成兼容 16KB 的 layout。
容易踩的坑
第三方 .so 没源码(Unity 历史包、老版 Flutter 引擎)——联系厂商要新版;
.so内嵌的dlopen字符串里有硬编码路径,要重 build;启动时
System.loadLibrary路径被 ProGuard 误删,需要-keep。
三、Adaptive Layouts 2.0:折叠屏终于"像个产品"
Android 12 引入 WindowManager Jetpack;16 上 API 扩展到 WindowInfoTracker,可以拿设备铰链姿态、Hinge 角度、平板/桌面模式。
val tracker = WindowInfoTracker.getOrCreate(activity)
lifecycleScope.launch {
tracker.windowLayoutInfo(activity).collect { info ->
val hinge = info.displayFeatures
.filterIsInstance<FoldingFeature>()
.firstOrNull()
when (hinge?.state) {
FoldingFeature.State.HALF_OPENED -> showDualPane()
FoldingFeature.State.FLAT -> showSinglePane()
else -> Unit
}
}
}
比 12 那个版本好用的点:现在能区分"书本模式"和"笔记本模式"(铰链垂直接近 90° 时),UI 可以分别给"双手看书"和"键盘打字"两种布局。
四、Live Updates:通知能"动起来"
Android 16 把 Delivery Tracker API 推广到 SystemUI。它的定位不是普通 Notification,而是"行程追踪"这类高频小窗:
val notification = Notification.Builder(context, channelId)
.setContentTitle("订单配送中")
.setContentText("骑手正在距离你 800m")
.setSmallIcon(R.drawable.ic_delivery)
.setStyle(Notification.ProgressStyle()
.setProgress(40)
.setProgressIndeterminate(false))
.setLiveUpdates(true)
.build()
setLiveUpdates(true) 会触发 SystemUI 的"地图 + 进度条"组合 UI,不需要你自己画 RemoteViews。
注意:从 16 起,任何带定位的 Live Update 通知必须声明 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION。Google Play 审核脚本会扫到。
五、Privacy Sandbox 4:归因变了
Topics API 替代了基于 IDFA 的广告 ID。对接流程:
把
play-services-ads-identifier改成ads-identifier+topics两套包;申请 sandbox 入口:
val topics = TopicsManager.getTopics()在 EU 设备和未注册的设备上会抛TopicsException.NotConsentInfoAvailable;国内场景未启用,但 EMUI 14 / HyperOS 也接入了自家的"隐私主题",要单独适配。
这不是单纯改依赖——它直接影响广告归因,老老实实对接 Topics API 比天天担心被禁划算得多。
六、Background Activity 限制:跳转逻辑要改
16 上限制了"Activity 在后台超过 30 秒后被启动"必须满足下面三个之一:
来自前台通知的 PendingIntent;
来自前台 Service 的 startActivity;
来自 system_server 自身(闹钟、媒体控制等)。
实际场景:IM 推送点开会黑屏 1 秒再弹登录页?多数是因为你 PushService 还在但 Activity 已 detach。方案:
// 在 PushReceiver 里直接拉起,不用 startActivity
val launcher = LaunchActivity.makeLauncher(context, payload)
context.startActivity(launcher.intent) {
// 加上 ActivityLaunchOption 让系统知道这是"用户预期"的启动
showOverlaysAppsThatAreNotSystemPending = true
}
七、其他值得留意的改动
JobScheduler 配额:JobInfo.setPeriodic 最小周期从 15 分钟放宽到 10 分钟,但有配额——一小时内最多 18 个 job。
R8 6.x:默认开启类合并二阶段,proguard-rules 写错会让 BuildConfig 字段被错误折叠。
DEX 90:新格式让方法引用使用 32-bit 索引,包内方法数上限从 65535 升到 16M。要在 gradle.properties 里开启
android.enableDex90=true。ART GC 改进:分代 GC 改成默认,延迟更低但暂停更频繁。Stacks 工具里"GC 原因"多了
Concurrent Mark一类。
小结
Android 16 这一版主要在"合规"和"开发者被强制升级"上做文章,没有大到能称之为"革命"的功能。下一篇文章我们聊聊 Material 3 Expressive——它和这套系统级改动是搭配出现的。
如果你正打算 2026 Q3 的 release,这是必读清单;不读的话,应用商店一审就给你打回。
参考阅读
Android 16 平台行为变更(developer.android.com)
16KB page size 迁移白皮书
Adaptive Layouts 2.0 示例工程