Android 15适配方案及常见问题

谷歌发布Android 15后,国内的手机厂商迅速行动,开始了新系统的适配工作。小米、OPPO、vivo和联想等金标联盟成员联合发布了适配公告,督促APP开发者在2024年8月31日前完成适配工作,否则将面临搜索标签提示、应用降级、分机型屏蔽以及应用下架等处罚措施。

1.准备工作

Android 15 SDK 包含一些与一些较低版本不兼容的变更 Android Studio 版本。为了获得最佳的 Android 开发体验, 15 SDK,使用 Android Studio Koala 功能更新 |2024.1.2 或更高版本。
下载最新版编译器

安装 SDK

在 Android Studio 中,您可以按如下方式安装 Android 15 SDK:

  1. 点击工具 >SDK 管理器 ,然后点击 Show Package Details
  2. SDK Platforms 标签页中,展开 Android API 35 。 部分,然后选择 Android SDK Platform 35 软件包。
  3. SDK Tools 标签页中,展开 Android SDK Build-Tools 35 部分 然后选择最新的35.x.x版本。
  4. 点击 OK 安装 SDK
更新应用的 build 配置

如需访问 Android 15 API 并测试应用与 Android 15 的兼容性,请执行以下操作: 打开模块级 build.gradlebuild.gradle.kts 文件,并更新 将其替换为 Android 15 所对应的值。如何设置这些值的格式取决于 版本的 Android Gradle 插件 (AGP)

AGP 7.0.0 或更高版本

plain 复制代码
android {
    compileSdk 35
    ...
    defaultConfig {
        targetSdk 35
    }
}

下图是AGP版本所要求的Gradle、JDK、SDK Build Tools 最小版本,按需适配

2.可能存在的影响面有哪些

UI相关:主要页面状态栏是否正常和底部是否有遮挡。包括:原生页面;h5页面 ;flutter页面。(沉浸式和非沉浸式)

通知栏样式:极光推送是否通知栏样式是否正常。

存储相关:文件下载功能:版本更新功能是否正常。图库选择图片和视频是否正常。图片资源保持功能是否正常。

权限相关:机型测试权限是否有异常。

机型覆盖:安卓15 需要兼容 OPPO、VIVO、小米等。(登录官网-找云真机测试)\

对软件包停止状态的更改

软件包 FLAG_STOPPED 状态(用户可以通过长按应用图标并选择"强行停止"来参与 AOSP build)一直是为了让应用保持此状态,直到用户通过直接启动应用或间接与应用互动(通过 Sharesheet 或 widget、选择应用作为动态壁纸等)将应用从此状态明确移除。在 Android 15 中,将更新系统的行为,以符合这一预期行为。只能通过用户直接或间接操作将应用从停止状态中移除。

为了支持预期行为,除了现有限制之外,当应用在搭载 Android 15 的设备上进入停止状态时,系统还会取消所有待处理。当用户的操作将应用从停止状态中移除时,系统会向应用传递 ACTION_BOOT_COMPLETED 广播,让用户有机会重新注册任何待处理的 intent。

可以调用新的 ApplicationStartInfo.wasForceStopped() 方法来确认应用是否已置于停止状态

让部分应用支持私密空间所需的更改

私密空间是 Android 15 中的一项新功能,可让用户 在设备上创建一个单独的空间,以便将敏感应用拒之门外 增加了一层额外的身份验证。因为 由于私密空间的公开范围有限,因此某些类型的应用需要 需要完成一些额外步骤才能查看用户私有中的应用并与之互动 空间。

最低可安装TargetSDK级别为24

如果尝试安装一个针对较低API级别的应用程序会导致安装失败,并在Logcat中出现以下消息:

plain 复制代码
INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 24, but found 7

应用 STOPPED 状态的变化

当应用进入 STOPPED 状态时,系统会自动取消应用的所有 PendingIntent。这意味着任何未决的操作,包括但不限于定时任务和远程服务调用,都将被中断。

在此状态下,应用的小部件(widgets)也会被禁用,表现为灰色不可交互状态,直到应用再次启动。

用户通过直接或间接操作将应用从 STOPPED 状态唤醒时,系统会发送 ACTION_BOOT_COMPLETED 广播给应用。这允许应用重新注册其 PendingIntent 和恢复其他必要的后台活动。

应用可以通过 ApplicationStartInfo.wasForceStopped() 接口来检测自身是否曾处于 STOPPED 状态,以便采取相应的恢复措施。

PendingIntent

PendingIntent 则是对 Intent 的一种封装,它提供了在未来的某个不确定时间点执行 Intent 的能力,并且可以在不同的进程之间安全地传递。PendingIntent 主要有以下用途:

异步执行:允许在未来的某个时刻执行 Intent,即使是在应用不处于前台的情况下。

跨进程调用:可以安全地将 Intent 传递给其他应用或进程,因为 PendingIntent 保证了 Intent 的执行上下文和权限。

延迟绑定:在创建 PendingIntent 时不需要立即知道所有参数,可以在稍后的某个时间点再进行绑定和执行。

新的媒体处理前台服务类型

Android 15引入了一种新的前台服务类型,即mediaProcessing。

该系统允许一个应用的媒体处理服务在24小时内运行总共6个小时,之后系统会调用正在运行的服务的Service.onTimeout(int, int)方法(在Android 15中引入)。

要使用这种前台服务类型,需要在manifest中申明相关权限和foregroundServiceType属性:

plain 复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
        <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROCESSING" />
    .....
            <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true"
                android:foregroundServiceType="mediaProcessing"
                >
        </service>

    ......

Receiver 启动前台服务的限制

BOOT_COMPLETED 广播接收器启动前台服务有了新的限制,不得启动以下类型的前台服务:dataSync、camera、mediaPlayback、phoneCall、mediaProjection、microphonemicrophone(此限制自 Android 14 起生效)

如果BOOT_COMPLETED接收器尝试启动任何类型的前台服务,系统将抛出异常:ForegroundServiceStartNotAllowedException

plain 复制代码
fun onCreate(){ 
    StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) 
}

IntentFilter

在 Android 15 中,系统对 Intent 的安全性和精确性进行了显著增强,主要体现在两个关键方面:

a.精确匹配 Intent-Filters:当一个应用尝试通过 Intent 启动另一个应用中的组件(如 Activity)时,发送的 Intent 必须严格符合接收组件声明的 intent-filters。这意味着,Intent 中的属性(如 category、data 和 action)必须与接收方在清单文件(AndroidManifest.xml)中定义的 intent-filters 完全匹配,才能成功启动目标组件。这一改变确保了组件只能被预期的 Intent 所激活,增强了跨应用交互的安全性。

b.强制 Intent 包含 Action:所有用于启动 Activity 或 Service 的 Intent 现在都必须包含一个明确的 action 字段。如果没有指定 action,该 Intent 将不会匹配到任何 intent-filters,从而无法启动任何组件。这一要求进一步提高了 Intent 的意图清晰度和安全性,防止了因缺少行动指令而可能引发的意外行为或安全漏洞。

Edge-to-edge 模式

Edge-to-edge模式是Android 15引入的一种布局策略,旨在使应用界面充分利用整个屏幕空间,包括状态栏和导航栏区域。在该模式下,应用界面将扩展至屏幕边缘,且无法自定义状态栏背景颜色,导航栏的背景透明度默认设为80%。

特性

默认启用:针对Android 15设备,所有targetSdkVersion为35或更高的应用将默认启用Edge-to-edge模式。

布局影响:启用该模式可能会影响应用的布局设计,需要开发者进行相应的适配工作。

限制条件:在Edge-to-edge模式下,非浮动窗口的layoutInDisplayCutoutMode属性必须设置为LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,否则会抛出IllegalArgumentException。

API弃用:在Android 15平台上,之前用于设置系统栏颜色的API如setStatusBarColor和setNavigationBarColor将被弃用,即使调用,系统也会保持默认的沉浸式体验。

16K Page Size

Android 过去仅支持 4 KB 内存页面大小, 优化了系统内存性能,以针对 Android 设备通常具备的功能,页面大小以优化设备的性能。正在添加 支持 16 KB 页面大小的设备,可使您的应用在这些设备上运行 并有助于您的应用从相关的广告效果中获益 改进。如果不重新编译,应用可能无法在 16KB 设备上运行 在未来的 Android 版本中正式推出,CPU 运行时页面大小是全局设置,要么是 4K,要么是 16K,无法混用

  • 优点: 提升系统内存性能,缩短应用启动时间,降低功耗,加快相机启动速度等。
  • 缺点: 使用了 .so 动态库的应用需重新编译才能兼容,否则大概率崩溃。

升级 NDK 至 r27 或以上版本,并在 Application.mk 中配置

plain 复制代码
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true

对于 NDK r26 及以下版本,需在 Android.mk 中添加

plain 复制代码
LOCAL_LDFLAGS += "-Wl,-z,max-page-size=16384"

升级 AGP 至 8.3 或以上版本。

在 16 KB 的环境中测试您的应用

1.设置 Android 15 SDK(上文已提到升级方案)
2.设置以下测试环境:

使用基于 16 KB 的 Android 15 系统设置 Android 模拟器 图片

  1. 基于 16 KB 的 Android 15 模拟器系统映像 Android Studio Jellyfish |2023.3.1 或更高版本。不过,为了最好 使用 Android 15 Beta 版时的体验,请下载最新的 预览版。请注意,您可以保留现有的 Android Studio 版本 因为您可以同时安装多个版本
  2. 在 Android Studio 中,依次点击 Tools > SDK Manager
  3. SDK Platforms 标签页中,选中 Show Package Details ,然后展开 Android VanillaIceCream Preview 部分,然后选择 以下模拟器系统映像,具体取决于您要创建的虚拟设备 创建:
3.启动测试设备,然后运行以下命令来验证 它使用的是 16 KB 的环境:
plain 复制代码
adb shell getconf PAGE_SIZE

该命令应返回值 16384

4.对于任何共享库,请确认共享库的ELF 细分 使用 16 KB ELF 对齐进行正确对齐。可以使用此脚本 有关此流程的帮助:
plain 复制代码
#!/bin/bash

# usage: alignment.sh path to search for *.so files

dir="$1"

RED="\e[31m"
GREEN="\e[32m"
ENDCOLOR="\e[0m"

matches="$(find $dir -name "*.so" -type f)"
IFS=$'\n'
for match in $matches; do
  res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)"
  if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; then
    echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
  else
    echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
  fi
done
a. 将脚本保存到一个文件中,例如 alignment.sh
b. 解压缩应用的 APK 文件:
plain 复制代码

unzip APK_NAME.apk -d /tmp/my_apk_out

复制代码
c. 在 /tmp/my_apk_out 中的提取文件上运行脚本 目录:
plain 复制代码

alignment.sh /tmp/my_apk_out | grep "arm64-v8a"

go 复制代码
该脚本会针对所有参数输出 `ALIGNED` 或 `UNALIGNED`, `arm64-v8a` 个共享库。
d. 如果任何 arm64-v8a 共享库为 UNALIGNED,您需要 更新这些库的包装,然后重新编译您的 应用,然后按照本部分中的步骤重新测试。
5.运行以下 zipalign命令,其中 APK_NAME 是 应用的 APK 文件
plain 复制代码
zipalign -c -P 16 -v 4 APK_NAME.apk
6. 全面测试您的应用,重点关注可能会受到 更改引用特定页面大小的代码实例。

即使您的应用是 16 KB 对齐的,如果将 会假定设备使用的是特定的页面大小。为了避免这种情况 请完成以下步骤:

  1. 移除所有引用 PAGE_SIZE的硬编码依赖项 常量或实例,它假定设备的页面 大小为 4 KB (4096)。请改用 getpagesize()sysconf(_SC_PAGESIZE)
  2. 查看是否使用了 mmap() 和其他需要页面对齐的 API 参数,并在必要时替换为替代参数。

在某些情况下,如果您的应用将 PAGE_SIZE 作为一个不方便使用的值, 与底层页面大小相关联,那么这不会导致应用中断 当在 16 KB 模式下使用时。不过,如果将该值传递给内核, 对于不带 MAP_FIXEDmmap,内核仍会使用整个页面, 会浪费一些内存因此,当大小为 16 KB 时,未定义 PAGE_SIZE。 模式在 NDK r27 及更高版本中启用。

如果您的应用以这种方式使用 PAGE_SIZE,并且从未将此值直接传递给 则不使用 PAGE_SIZE,而是创建一个具有新变量的新变量 表明相应信息已用于其他用途,并不反映真实情况 内存页。

作者:洞窝-王有为

相关推荐
dalancon19 分钟前
VSYNC 信号流程分析 (Android 14)
android
dalancon28 分钟前
VSYNC 信号完整流程2
android
dalancon30 分钟前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013842 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android2 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才3 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶3 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
汪海游龙4 小时前
开源项目 Trending AI 招募 Google Play 内测人员(12 名)
android·github
qq_283720055 小时前
MySQL技巧(四): EXPLAIN 关键参数详细解释
android·adb
没有了遇见5 小时前
Android 架构之网络框架多域名配置<三>
android