Android16 应用代码新特性
文章目录
- [Android16 应用代码新特性](#Android16 应用代码新特性)
-
-
- 一、系统行为强制变更(代码适配差异)
-
- [1. 全屏布局机制](#1. 全屏布局机制)
- [2. 预测返回导航](#2. 预测返回导航)
- 二、权限模型重构(代码声明差异)
-
- [1. 健康数据权限精细化](#1. 健康数据权限精细化)
- [2. 剪贴板访问权限](#2. 剪贴板访问权限)
- [三、API 接口重大变更(方法 / 类替换)](#三、API 接口重大变更(方法 / 类替换))
-
- [1. 生物识别认证分级](#1. 生物识别认证分级)
- [2. Nearby Share 传输升级](#2. Nearby Share 传输升级)
- [3. 内存管理优化](#3. 内存管理优化)
- [四、AI 与本地模型集成(新增 API)](#四、AI 与本地模型集成(新增 API))
- 五、广播与事件机制(安全性增强)
-
- [1. 动态广播导出状态强制声明](#1. 动态广播导出状态强制声明)
- [2. 有序广播废弃](#2. 有序广播废弃)
- 六、开发者工具链(依赖与语法变更)
-
- [1. Jetpack Compose 版本强制升级](#1. Jetpack Compose 版本强制升级)
- [2. 编译工具要求](#2. 编译工具要求)
- 七、总结:核心差异领域
-
Android16应用代码对比Android15、14有啥代码差异?
Android 16 相对于 Android 15 和 14,在系统行为、API 接口、权限模型、性能优化等方面存在多处代码级差异,这些差异直接影响应用的兼容性和功能实现。
以下从核心场景对比具体代码变化,有兴趣的看看:
一、系统行为强制变更(代码适配差异)
1. 全屏布局机制
-
Android 14/15:可通过windowOptOutEdgeToEdgeEnforcement
禁用全屏布局:xml
xml<!-- Android 14/15 可选配置 --> <style name="AppTheme"> <item name="windowOptOutEdgeToEdgeEnforcement">true</item> </style>
- Android 16:彻底移除该属性,所有应用默认强制全屏,需显式处理状态栏 / 导航栏遮挡:
kotlin/Java
kotlin:
// Android 16 必须添加的适配代码
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView)
windowInsetsController?.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// 布局中设置 padding 避免内容被遮挡
ViewCompat.setOnApplyWindowInsetsListener(yourView) { view, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
Java:
// Android 16 窗口布局适配
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.core.view.ViewCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.WindowInsetsCompat;
// 配置系统栏行为
WindowInsetsControllerCompat windowInsetsController = new WindowInsetsControllerCompat(
getWindow(),
getWindow().getDecorView()
);
windowInsetsController.setSystemBarsBehavior(
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
);
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
// 处理布局内边距
View rootView = findViewById(R.id.root_view);
ViewCompat.setOnApplyWindowInsetsListener(rootView, (view, insets) -> {
Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
view.setPadding(
bars.left,
bars.top,
bars.right,
bars.bottom
);
return insets;
});
2. 预测返回导航
-
Android 14:仅手势导航支持预测返回,可通过onBackPressed() 兼容:
kotlinkotlin // Android 14 旧逻辑 override fun onBackPressed() { super.onBackPressed() // 直接触发返回 }
-
Android 15 :扩展至三键导航,但仍支持
onBackPressed()
降级; -
Android 16:完全废弃onBackPressed() 和 KEYCODE_BACK
强制使用新回调:
kotlinkotlin: // Android 16 必须使用的新逻辑 onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { // 处理返回逻辑(如弹窗确认) if (shouldFinish) finish() else isEnabled = false // 交给父级处理 } }) Java: // Android 16 返回导航 import androidx.activity.OnBackPressedCallback; import androidx.lifecycle.LifecycleOwner; getOnBackPressedDispatcher().addCallback((LifecycleOwner) this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { if (canGoBack()) { finish(); // 处理返回 } else { showExitDialog(() -> setEnabled(false)); // 禁用回调,让系统处理 } } private boolean canGoBack() { // 判断是否可返回的逻辑 return false; } private void showExitDialog(Runnable onConfirm) { // 显示退出对话框,确认后调用 onConfirm onConfirm.run(); } });
在Android16 demo和手机上测试了一下,onBackPressed()回调还是可以在Activity监听,但是左滑退出没有回调了;
getOnBackPressedDispatcher().addCallback 左滑退出是有回调的,说明之前的onBackPressed()已经废弃了。
二、权限模型重构(代码声明差异)
1. 健康数据权限精细化
-
Android 14/15:通过BODY_SENSORS
统一申请健康传感器权限:
xml <!-- Android 14/15 权限声明 --> <uses-permission android:name="android.permission.BODY_SENSORS" />
-
Android 16:拆分为 12 个细分权限,需按需声明:
xmlxml <!-- Android 16 权限声明 --> <uses-permission android:name="android.permission.READ_HEART_RATE" /> <uses-permission android:name="android.permission.READ_BLOOD_PRESSURE" /> <uses-permission android:name="android.permission.READ_HEALTH_DATA_IN_BACKGROUND" /> <!-- 后台访问需额外声明 -->
代码中请求权限时也需对应调整:
kotlinkotlin // Android 16 权限请求 registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> if (permissions[Manifest.permission.READ_HEART_RATE] == true) { // 访问心率传感器 } }.launch(arrayOf(Manifest.permission.READ_HEART_RATE)) Java // Android 16 健康权限请求 import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import android.Manifest; import android.content.pm.PackageManager; // 注册权限请求回调 private final ActivityResultLauncher<String[]> requestHealthPermissions = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissions -> { if (permissions.getOrDefault(Manifest.permission.READ_HEART_RATE, false)) { startHeartRateMonitoring(); } }); // 发起权限请求 public void requestHeartRatePermission() { if (checkSelfPermission(Manifest.permission.READ_HEART_RATE) != PackageManager.PERMISSION_GRANTED) { requestHealthPermissions.launch(new String[]{ Manifest.permission.READ_HEART_RATE }); } else { startHeartRateMonitoring(); } } private void startHeartRateMonitoring() { // 开始心率监测 }
2. 剪贴板访问权限
-
Android 14/15:访问剪贴板无需特殊权限;
-
Android 16:必须申请READ_CLIPBOARD权限:
xml <!-- Android 16 新增权限 --> <uses-permission android:name="android.permission.READ_CLIPBOARD" />
代码中需先检查权限:
kotlin
// Android 16 剪贴板访问逻辑
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CLIPBOARD)
== PackageManager.PERMISSION_GRANTED) {
val clipboard = getSystemService(ClipboardManager::class.java)
val text = clipboard.primaryClip?.getItemAt(0)?.text
}Java
// Android 16 剪贴板访问
import android.content.ClipboardManager;
import android.content.pm.PackageManager;
import android.Manifest;
import androidx.core.content.ContextCompat;public String getClipboardText() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CLIPBOARD)
!= PackageManager.PERMISSION_GRANTED) {
// 未获得权限,请求权限或提示用户
return null;
}ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); if (clipboard != null && clipboard.getPrimaryClip() != null && clipboard.getPrimaryClip().getItemCount() > 0) { return clipboard.getPrimaryClip().getItemAt(0).getText().toString(); } return null;
}
三、API 接口重大变更(方法 / 类替换)
1. 生物识别认证分级
-
Android 14/15:通过 BIOMETRIC_STRONG
标识强认证:
kotlin
// Android 14/15 生物识别
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
.build() -
Android 16:引入 L1-L3 分级,支付场景强制 L3 级:
kotlinkotlin // Android 16 生物识别分级 val promptInfo = BiometricPrompt.PromptInfo.Builder() .setAuthenticationLevel(BiometricManager.Authenticators.BIOMETRIC_LEVEL_3) // L3 活体检测 .build() Java // Android 16 生物识别分级 import androidx.biometric.BiometricPrompt; import androidx.core.content.ContextCompat; import java.util.concurrent.Executor; private void showBiometricPrompt() { Executor executor = ContextCompat.getMainExecutor(this); BiometricPrompt biometricPrompt = new BiometricPrompt(this, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationSucceeded( BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); // 认证成功处理 } }); BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("确认支付") // 设置 L3 级认证(最高安全级) .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_LEVEL_3) .build(); biometricPrompt.authenticate(promptInfo); }
2. Nearby Share 传输升级
-
Android 14/15:使用旧版 API 单设备传输:
// Android 14/15 传输文件
Nearby.getShareClient(context)
.send(uri, deviceId)
.addOnSuccessListener { /* 处理成功 */ } -
Android 16:新增多设备并行传输 API(需 Wi-Fi 7 支持):
kotlin // Android 16 多设备传输 val transfer = Nearby.getShareClient(context) .createMultiDeviceTransfer(listOf(uri1, uri2), listOf(device1, device2)) transfer.start().addOnSuccessListener { /* 处理成功 */ }
3. 内存管理优化
-
Android 14/15:默认 4KB 内存页,无显式配置;
-
Android 16:支持 16KB 内存页,旧应用需兼容:
xmlxml <!-- Android 16 如需保留 4KB 页(不推荐) --> <application android:pageSizeCompat="4k" />
代码中可判断设备支持类型:
kotlinkotlin // Android 16 内存页适配 if (Build.VERSION.SDK_INT >= 36) { val pageSize = ActivityManager.getMemoryPageSize() if (pageSize == 16384) { // 16KB // 启用优化逻辑 } } Java // Android 16 内存页适配 import android.app.ActivityManager; import android.content.Context; import android.os.Build; import androidx.annotation.RequiresApi; @RequiresApi(api = Build.VERSION_CODES.JAVA16) private void adaptToMemoryPageSize() { ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); int pageSize = activityManager.getMemoryPageSize(); if (pageSize == 16384) { // 16KB 内存页 // 启用大内存块优化逻辑 optimizeForLargePages(); } else { // 兼容 4KB 内存页的逻辑 compatibilityWithSmallPages(); } } private void optimizeForLargePages() { // 针对 16KB 内存页的优化 } private void compatibilityWithSmallPages() { // 兼容 4KB 内存页的逻辑 }
四、AI 与本地模型集成(新增 API)
-
Android 14/15:无系统级本地大模型 API;
-
Android 16:新增 Gemini Nano 本地模型接口:
kotlin
// Android 16 调用本地 AI 生成图片描述
val gemini = GeminiSession.getInstance(context)
val image = ImageDecoder.decodeBitmap(...)
gemini.generateAltText(image)
.addOnSuccessListener { altText ->
// 用于无障碍标签或图片搜索
imageView.contentDescription = altText
}Java
// Android 16 本地 AI 集成
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.google.android.gms.gemini.GeminiSession;
import com.google.android.gms.tasks.OnSuccessListener;@RequiresApi(api = Build.VERSION_CODES.JAVA16) private void generateImageDescription(Uri imageUri) { try { // 解码图片 Bitmap image = ImageDecoder.decodeBitmap( ImageDecoder.createSource(getContentResolver(), imageUri) ); // 获取 Gemini 实例 GeminiSession gemini = GeminiSession.getInstance(getApplicationContext()); // 生成图片描述 gemini.generateAltText(image) .addOnSuccessListener(altText -> { // 设置无障碍描述 ImageView imageView = findViewById(R.id.image_view); imageView.setContentDescription(altText); }); } catch (Exception e) { e.printStackTrace(); } }
五、广播与事件机制(安全性增强)
1. 动态广播导出状态强制声明
-
Android 14:动态注册广播未指定导出状态时默认导出,无报错;
-
Android 15:未指定时抛出警告;
-
Android 16:未指定时直接抛出 IllegalArgumentException,必须显式声明:
kotlinkotlin // Android 16 动态广播注册(必须指定导出状态) registerReceiver( myReceiver, IntentFilter("com.example.ACTION"), Context.RECEIVER_EXPORTED // 或 RECEIVER_NOT_EXPORTED ) Java // Android 16 动态广播注册 import android.content.BroadcastReceiver; import android.content.IntentFilter; import android.content.Context; private void registerMyReceiver() { BroadcastReceiver myReceiver = new MyReceiver(); IntentFilter filter = new IntentFilter("com.example.ACTION"); // 必须显式指定导出状态 registerReceiver( myReceiver, filter, Context.RECEIVER_EXPORTED // 或 Context.RECEIVER_NOT_EXPORTED ); } private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 处理广播 } }
2. 有序广播废弃
-
Android 14/15 :仍可使用
sendOrderedBroadcast()
; -
Android 16:标记为废弃,建议改用WorkManager:
kotlin
// Android 16 替代有序广播的方案
WorkManager.getInstance(context)
.beginWith(FirstWorker::class.java)
.then(SecondWorker::class.java) // 按顺序执行
.enqueue()Java
/ Android 16 WorkManager 替代有序广播
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import java.util.Arrays;private void executeOrderedTasks() { // 第一步任务 OneTimeWorkRequest firstWork = new OneTimeWorkRequest.Builder(FirstWorker.class).build(); // 第二步任务(依赖第一步) OneTimeWorkRequest secondWork = new OneTimeWorkRequest.Builder(SecondWorker.class).build(); // 按顺序执行 WorkManager.getInstance(this) .beginWith(firstWork) .then(secondWork) .enqueue(); } // 定义 Worker 类
import androidx.work.Worker;
import androidx.work.WorkerParameters;public class FirstWorker extends Worker { public FirstWorker(Context context, WorkerParameters params) { super(context, params); } @Override public Result doWork() { // 执行第一步任务 return Result.success(); } } public class SecondWorker extends Worker { public SecondWorker(Context context, WorkerParameters params) { super(context, params); } @Override public Result doWork() { // 执行第二步任务 return Result.success(); } }
六、开发者工具链(依赖与语法变更)
1. Jetpack Compose 版本强制升级
-
Android 14/15:支持 Compose 1.x/2.x;
-
Android 16:强制使用 Compose 3.0,部分 API 不兼容:
kotlinkotlin // Android 14/15 旧列表组件 LazyColumn { items(dataList) { item -> Text(item) } } // Android 16 新列表组件(性能优化) LazyColumnV2 { items(dataList) { item -> Text(item) } }
2. 编译工具要求
-
Android 14/15:最低支持 AGP 7.0;
-
Android 16:最低要求 AGP 8.5,且必须使用 Java 17 编译:
gradle
// Android 16 模块级 build.gradle 配置
android {
compileSdk 36
buildToolsVersion "36.0.0"
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
七、总结:核心差异领域
维度 | Android 14/15 状态 | Android 16 变更点 |
---|---|---|
系统行为 | 可禁用全屏、支持旧返回逻辑 | 强制全屏、废弃 onBackPressed() |
权限模型 | 健康数据 / 剪贴板无细分权限 | 权限精细化、新增 READ_CLIPBOARD |
核心 API | 生物识别单级、单设备传输 | 生物识别分级、多设备传输 API |
性能优化 | 4KB 内存页、传统调度 | 16KB 内存页、Project Quantum 引擎 |
AI 集成 | 无系统级本地模型 | 新增 Gemini Nano 接口 |
开发工具 | 支持旧版 Compose/AGP | 强制 Compose 3.0、AGP 8.5、Java 17 |
适配时需重点关注权限声明更新 、系统行为强制变更 和废弃 API 迁移,
建议结合官方迁移工具(如 Android Studio 的 lint 检查)批量定位代码差异点。
总的来说感觉变更Android16后,需要适配的实际代码很少,
因为很多功能基本没啥用过,比如AI集成,性能优化,生物识别等,都是不常用的;
返回按键那个功能是要适配一下的,毕竟之前的回调方法没用了,要用新的api方法了。
Android16还有另外的差异吗,肯定是有的,比如系统HIDL在Android16不支持了!那咋搞?
要用AIDL。 Android11新增了可以绑定底层的AIDL (C++ 绑定) 功能适配。
这个算是系统代码实现差异;另外说明。
本文的主要内容,算是应用代码功能使用差异。