Android16 应用代码新特性

Android16 应用代码新特性

文章目录

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() 兼容:

    kotlin 复制代码
    kotlin
    // Android 14 旧逻辑
    override fun onBackPressed() {
        super.onBackPressed() // 直接触发返回
    }
  • Android 15 :扩展至三键导航,但仍支持 onBackPressed() 降级;

  • Android 16:完全废弃onBackPressed() 和 KEYCODE_BACK

    强制使用新回调:

    kotlin 复制代码
    kotlin:
    // 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 个细分权限,需按需声明:

    xml 复制代码
    xml
    <!-- 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" /> <!-- 后台访问需额外声明 -->

    代码中请求权限时也需对应调整:

    kotlin 复制代码
    kotlin
    // 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 级:

    kotlin 复制代码
    kotlin
    // 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 内存页,旧应用需兼容:

    xml 复制代码
    xml
    <!-- Android 16 如需保留 4KB 页(不推荐) -->
    <application android:pageSizeCompat="4k" />

    代码中可判断设备支持类型:

    kotlin 复制代码
    kotlin
    // 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,必须显式声明:

    kotlin 复制代码
    kotlin
    // 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 不兼容:

    kotlin 复制代码
    kotlin
    // 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++ 绑定) 功能适配。

这个算是系统代码实现差异;另外说明。

本文的主要内容,算是应用代码功能使用差异。

相关推荐
浮尘笔记2 小时前
Go-Zero API Handler 自动化生成与参数验证集成
开发语言·后端·golang
Monkey-旭2 小时前
Android 注解完全指南:从基础概念到自定义实战
android·java·kotlin·注解·annotation
嘉里蓝海2 小时前
橙色风暴中的安全堡垒:嘉顺达蓝海的危运密码
安全
傻啦嘿哟2 小时前
用Requests+BeautifulSoup实现天气预报数据采集:从入门到实战
开发语言·chrome·python
嘉里蓝海2 小时前
橙色车队:嘉顺达蓝海的危险品运输安全史诗
安全
兆。2 小时前
python全栈-数据可视化
开发语言·python·信息可视化
Roye_ack2 小时前
【项目实战 Day5】springboot + vue 苍穹外卖系统(Redis + 店铺经营状态模块 完结)
java·spring boot·redis·学习·mybatis
@大迁世界2 小时前
JavaScript 2.0?当 Bun、Deno 与 Edge 运行时重写执行范式
开发语言·前端·javascript·ecmascript
JIngJaneIL3 小时前
记账本|基于SSM的家庭记账本小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·家庭记账本小程序