一、获取Android 13
1、小米手机升级Android13
如果您已错过小米社区发布的关于MIUI基于Android 13的升级公开招募,可前往开发者内测申请权限,或请您联系自己公司商务或运营同学,联系我们,我们会为您开通有关权限并指导升级。
目前支持升级Android 13的MIUI开发版的机型有(有序更新中):
小米:小米12、小米12 Pro(高通平台)
Redmi: K50G(电竞版)、K40S、Note 11T Pro/Pro+
2、Google原生机升级Android 13
开发者持有Pixel系列的机器可以直接ota升级,或者下载镜像升级,具体见链接:
https://developer.android.com/about/versions/13/download
3、Android 模拟器
在 Android Studio 中,您可以按如下方式安装 Android 13 SDK:
- 依次点击 Tools > SDK Manager。
- 在“SDK Platforms”标签页中,选择 Android 13。
- 在 SDK Tools 标签页中,选择 Android SDK Build-Tools 33。
点击OK安装 SDK。
如需访问 Android 13 API 并测试您的应用与 Android 13 的兼容性,请打开模块级build.gradle或build.gradle.kts文件,并使用 Android 13 所对应的值对它们进行更新:如何设置这些值的格式取决于您所使用的 Android Gradle 插件 (AGP) 版本。
注意:如果您尚未准备好完全支持 Android 13,您仍然可以使用可调试的应用、Android 13 设备和兼容性框架来执行应用兼容性测试,而无需更改应用以使其与预览版 SDK 兼容或以此为目标平台。
二、新功能和API
1、照片选择器
Android 13 包含对新照片选择器工具的支持。此工具为用户提供了一种安全的内置媒体文件选择方式,让其无需向应用授予对整个媒体库的访问权限。
注意
:即将发布的 Google Play 系统更新预计会包含与照片选择器有关的新功能。在一项此类更新中,该库将增加对以 Android 11(API 级别 30)或更高版本为目标平台的应用(不包括 Android Go 设备)的支持。

1.1、选择媒体
照片选择器提供了一个可浏览、可搜索的界面,其中按日期(从最近到最早)顺序向用户呈现其媒体库中的文件。您可以指定用户只能看到照片或只能看到视频,并且默认情况下,允许的媒体选择量上限设置为 1。
1.2、定义分享限制
应用可以声明android.provider.extra.PICK_IMAGES_MAX的值,该值表示在向用户显示时照片选择器中显示的媒体文件数量上限。例如,如果您提示用户为其帐号选择要求的个人资料照片,请将一张照片设置为分享要求上限。
注意
:如果您选择的上限为 1 张,照片选择器会以半屏模式打开。
如需在单选模式下启动照片选择器,请执行以下操作:
// Launches photo picker in single-select mode.
// This means that the user can select one photo or video.
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
startActivityForResult(intent, PHOTO_PICKER_REQUEST_CODE);
1.3、选择多张照片或多个视频
如果应用的用例需要用户选择多张照片或多个视频,您可以使用EXTRA_PICK_IMAGES_MAX extra 指定照片选择器中应显示照片的数量上限,如以下代码段中所示:
// Launches photo picker in multi-select mode.
// This means that user can select multiple photos/videos, up to the limit
// specified by the app in the extra (10 in this example).
final int maxNumPhotosAndVideos = 10;
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxNumPhotosAndVideos);
startActivityForResult(intent, PHOTO_PICKER_MULTI_SELECT_REQUEST_CODE);
请注意,可指定为文件数量上限的最大数字存在平台限制。如需访问此限制,请调用MediaStore#getPickImagesMaxLimit()。
1.4、处理照片选择器结果
照片选择器启动后,使用新的ACTION_PICK_IMAGES intent 来处理结果。该选择器会返回一组 URI:
// onActivityResult() handles callbacks from the photo picker.
@Override
protected void onActivityResult(
int requestCode, int resultCode, final Intent data) {
if (resultCode != Activity.RESULT_OK) {
// Handle error
return;
}
switch(requestCode) {
case REQUEST_PHOTO_PICKER_SINGLE_SELECT:
// Get photo picker response for single select.
Uri currentUri = data.getData();
// Do stuff with the photo/video URI.
return;
case REQUEST_PHOTO_PICKER_MULTI_SELECT:
// Get photo picker response for multi select
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
Uri currentUri = data.getClipData().getItemAt(i).getUri();
// Do stuff with each photo/video URI.
}
return;
}
}
默认情况下,照片选择器会既显示照片又显示视频。您还可以在 setType() 方法中设置 MIME 类型,以便按“仅显示照片”或“仅显示视频”进行过滤。例如,如需在照片选择器中仅显示视频,请将video/*传入setType():
// Launches photo picker for videos only in single select mode.
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.setType("video/*");
startActivityForResult(intent, );
// Apps can also change the mimeType to allow users to select
// images only - intent.setType("images/*");
// or a specific mimeType - intent.setType("image/gif");
注意:您的应用不能持续访问从此 intent 返回的 URI。当应用的进程结束后,该应用将无法访问 URI。
2、应用内语言选择器
在许多情况下,多语言用户会将其系统语言设置为某一种语言(例如英语),但又想为特定应用选择其他语言(例如荷兰语、中文或印地语)。为了帮助应用为这些用户提供更好的体验,Android 13 针对支持多种语言的应用引入了以下新功能:
使用自定义应用内语言选择器的应用应当使用这些新 API,以确保无论用户通过何种方式选择其语言偏好设置,都能获得一致的用户体验。这些新的 API 还有助于减少样板代码的编写。
为了向后兼容以前的 Android 版本,我们还会从Appcompat 1.6.0-alpha01开始在 AndroidX 中提供这些 API。
- 允许用户为每个应用选择首选语言的系统设置
不支持多种语言的应用不受这些变更的影响。
2.1、API 实现
对于当前未使用自定义应用内语言选择器的应用,无需执行任何其他操作。
对于具有或想要使用应用内语言选择器的应用,请使用这些新 API(而非应用的自定义逻辑)来处理相关设置和获取用户对应用的首选语言设置。
使用 AndroidX 支持库来实现
为了向后兼容以前的 Android 版本,建议使用 AndroidX 支持库来实现应用内语言选择器。使用Appcompat 1.6.0-alpha01或更高版本中提供的setApplicationLocales()方法。
例如,如需设置用户的首选语言,您需要让用户在语言选择器中选择语言区域,然后在系统中设置该值:
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("xx-YY");
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale);
使用 Android 框架 API 来实现
您还可以通过setApplicationLocales()和getApplicationLocales()方法,使用 Android 框架 API 来实现应用内语言选择器。
例如,如需设置用户的首选语言,您需要让用户在语言选择器中选择语言区域,然后在系统中设置该值:
// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its localem
Context.getSystemService(LocaleManager.class).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language
如需获取用户当前的首选语言以显示在语言选择器中,您的应用可以从系统中取回该值:
// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales = mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user
2.2、面向用户的系统设置
用户可以通过新的系统设置为每个应用选择首选语言。他们可以通过以下两种方式访问这些设置:
- 通过系统设置访问
设置 > 系统 > 语言和输入法 > 应用语言 >(选择应用)
- 通过应用设置访问
设置 > 应用 >(选择一款应用)> 语言
已知问题
在测试应用时,有一些已知问题需要注意。
- 可用语言列表中可能不包含您的应用支持的语言。
- 如果您的应用使用拆分 APK,当应用语言区域发生变化时,系统不会自动下载这些 APK。
- 现在的界面只是一个初步版本,在后续版本中会不断更改。
2.3、DEMO演示

3、可由开发者降级的权限
从 Android 13 开始,应用可以撤消先前由系统或用户授予的运行时权限。此 API 可以帮助应用保护用户的隐私。
如需撤消特定运行时权限,请将该权限的名称传入revokeSelfPermissionOnKill()。如需同时撤消一组运行时权限,请将这组权限的名称传入revokeSelfPermissionsOnKill()。撤消是异步发生的,会终止与应用的 UID 相关联的所有进程。
系统只有在安全的情况下才会触发撤消操作。具体而言,当有应用组件仍在前台运行,或者有另一个应用正在访问您应用的组件(如 content provider)时,不会发生撤消。如果您想立即撤消权限,可以调用exit()。但是,对exit()进行此类调用可能会导致当前正在访问您应用的其他应用出现未定义的行为或崩溃。
注意
:为了让系统设置表明您的应用不会访问特定
权限。在这种情况下,调用
revokeSelfPermissionsOnKill()
会很有帮助。
4、可编程的着色器
Android 13 添加了对可编程RuntimeShader对象的支持,其行为是使用 Android 图形着色语言 (AGSL) 定义的。AGSL 与 GLSL 共用大部分语法,但可用于 Android 渲染引擎中以自定义 Android 画布中的绘制行为以及过滤 View 内容。Android 在内部使用这些着色器来实现涟漪效果、模糊以及拉伸滚动,并且 Android 13 让您能为应用制作类似的高级效果。改写自此GLSL 着色器的 AGSL 动画着色器:

基于可编程着色器实现的一个简单的绘制效果如下:

5、更快断字
断字让分行的文本更易于阅读,并且有助于使界面更具自适应性。在 Android 13 中,我们将断字性能优化了多达 200%,因此您现在可以在TextView中启用断字功能,这几乎不影响渲染性能。如需启用更快断字功能,请在setHyphenationFrequency()中使用新的fullFast或normalFast频率。
5.1、API变化
Android 13在已有断字模式基础上新增两种Fast模式:fullFast和normalFast,在原有基础上测量更快。
5.2、使用建议
在布局中添加属性android:hyphenationFrequency:
<!--少量快速断字模式-->
<TextView android:hyphenationFrequency="fullFast"/>
<!--标准快速断字模式-->
<TextView android:hyphenationFrequency="normalFast"/>
代码中直接设置:
//标准快速断字模式
mTextView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL_FAST)
//少量快速断字模式
mTextView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL_FAST)
三、影响应用的行为变更
1、行为变更:所有应用
1.1、前台服务 (FGS) 任务管理器
无论应用采用何种目标 SDK 版本,Android 13 都允许用户从抽屉式通知栏中停止前台服务。这项新功能称为前台服务 (FGS) 任务管理器,它会显示当前正在运行前台服务的应用列表。此列表的标签为使用中的应用。每个应用旁边都有一个停止按钮。
下图说明了搭载 Android 13 的设备上的 FGS 任务管理器的工作流程:

1.1.1 用户操作会停止您的整个应用
当用户在 FGS 任务管理器中按您应用旁边的停止按钮时,系统会停止您的整个应用,而不仅仅是正在运行的前台服务。
比较“向上滑动”用户操作和“强行停止”用户操作的行为:
请参见下表中 FGS 任务管理器与现有功能的比较:从最近用过屏幕“向上滑动”和“强行停止”出现异常的应用。

用户从 FGS 任务管理器停止应用时,不会发送任何回调。
当用户按停止按钮时,系统不会向您的应用发送任何回调。当应用启动备份时,建议您检查一下现有ApplicationExitInfoAPI 中的新REASON_USER_REQUESTED原因,这可能会很有帮助。
1.1.2 与长时间运行的前台服务相关的系统提示
如果系统检测到您的应用长时间运行某项前台服务(在 24 小时的时间段内至少运行 20 小时),便会发送通知邀请用户与 FGS 任务管理器互动。详细了解就长时间运行的前台服务提醒用户的新系统通知。
1.1.3 豁免
系统会针对特定类型的应用提供几种级别的豁免,下面几部分将介绍这些豁免。
豁免针对的是应用而不是进程。如果系统豁免了应用中的一个进程,则该应用中的所有其他进程也会被豁免。
注意
:即使是设备上预装的应用,也必须至少满足下面一个部分中的条件才能获得豁免。
a. 完全不会显示在 FGS 任务管理器中
以下应用可以运行前台服务,而完全不会显示在任务管理器中:
- 系统级应用
- 安全应用,即具有ROLE_EMERGENCY 角色的应用
- 处于演示模式的设备上的应用
b. 免于被用户停止当以下类型的应用运行前台服务时,它们会显示在 FGS 任务管理器中,但应用名称旁边没有可以供用户按的停止按钮:
- 设备所有者应用
- 资料所有者应用
- 常驻应用
- 具有ROLE_DIALER 角色的应用
1.1.4 测试
如需测试应用在用户停止应用的过程中和之后的行为是否符合预期,请在终端窗口中运行以下 adb 命令:
adb shell cmd activity stop-app PACKAGE_NAME
1.2、使用 JobScheduler 改进预提取作业处理
利用 JobScheduler,应用可使用JobInfo.Builder.setPrefetch()将特定作业标记为“预提取”作业,这意味着,理想情况下这些作业应该在应用下一次启动前提前一点运行,以提升用户体验。过去,JobScheduler 仅使用该信号让预提取作业有机会使用免费或多余的数据。
在 Android 13 中,系统现在会尝试确定应用下次启动的时间,并根据该估算值运行预提取作业。应用应尝试使用预提取作业来完成他们想要在下次应用启动前完成的任何工作。
1.2.1 代码示例
JobScheduler mJobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder mBuilder = new JobInfo.Builder(mJobId++, new ComponentName(this,MyJobService.class));
mBuilder.setPrefetch(true) //赋值为true
mJobScheduler.schedule(mBuilder.build());
1.3、电池资源利用率
Android 13 引入了以下省电措施:
- 更新了有关系统何时将您的应用放入“受限”应用待机模式存储分区的规则。
- 对于您的应用在以下情况下可以执行的操作制定了新限制:用户因您应用的后台电池用量过高而将其置于“受限”状态。
- 新增了系统通知,用于就后台电池用量过高和长时间运行的前台服务向用户发出警告。
1.3.1 关于应用何时会进入“受限”应用待机模式存储分区的规则更新
除非您的应用符合豁免条件,否则当您的应用出现以下任何行为时,系统就会将其放入受限存储分区:
- 用户有 8 天没有与您的应用互动。如果用户与另一个绑定到您应用的服务的应用互动,系统也会将您的应用视为“使用过”。
注意
:设备处于关闭状态的时间不会计入互动限制。
在衡量应用对设备电池续航时间的影响时,系统会考虑应用在几个不同方面执行的操作,包括:
- 作业(包括加急作业)
- 广播接收器
- 后台服务
- 系统是否已缓存应用的进程
用户互动可让您的应用退出“受限”存储分区:
当用户与您的应用互动时(包括通过以下几种方式互动),系统会将应用从受限存储分区中移出,并放入另一个应用待机模式存储分区:
- 用户点按您的应用发送的通知。
注意
:如果用户在不点按通知的情况下滑开通知,系统
不会
将该操作视为与您的应用“互动”。
- 用户在属于您应用的 widget 中执行操作。
- 用户通过按媒体按钮影响您应用的前台服务。
- 用户在与 Android Automotive OS 互动时连接到您的应用(您的应用在此过程中使用了前台服务或CONNECTION_TYPE_PROJECTION)。
- 您的应用在画中画 (PiP) 模式下可见。
- 您的应用是屏幕上当前运行的应用之一。(主要适用于大屏设备。)
1.3.2 关于受限后台电池用量的新限制
注意
:只有在您的应用以 Android 13 为目标平台时,此变更才会生效。
使用现有 Android 版本的用户能够调整应用在后台运行时可以执行的工作量。系统设置中的电池用量页面上会显示以下选项:
- 无限制:允许后台工作,这可能会消耗更多电量。
- 优化(默认):根据用户与应用互动的方式,优化应用执行后台工作的能力。
- 受限:更注重延长设备的电池续航时间,而不是实现应用的全面功能。对于应用可以在后台执行的操作施加了更多限制。
注意
:如果用户在将您的应用置于“受限”状态之后启动了该应用,系统会暂时将该应用视为处于“优化”状态。当用户停止与您的应用互动并开始与另一个应用互动时,系统会将您的应用重新置于“受限”状态。
自 Android 9(API 级别 28)起,处于“受限”状态的应用具有以下限制:
- 无法启动前台服务
- 现有的前台服务会从前台移除
- 不会触发闹钟
- 不会执行作业
当您的应用以 Android 13 为目标平台时,除非应用因其他原因启动,否则系统不会传送以下任何广播:
- BOOT_COMPLETED
- LOCKED_BOOT_COMPLETED
1.3.3 与后台电池用量过高相关的系统通知
Android 13 引入了一个新的系统通知,当您的应用在 24 小时内消耗了大量设备电池电量时,就会显示该通知。这个新通知会针对搭载 Android 13 的设备上的所有应用显示,无论应用采用何种目标 SDK 版本都不例外。
注意
:如果系统在应用显示与前台服务相关的通知时检测到应用的电池用量较高,系统会等到用户关闭通知,或前台服务完成,并且仅在您的应用继续消耗大量设备电池电量时才会显示该通知。
在衡量应用对设备电池续航时间的影响时,系统会考虑应用在几个不同方面执行的操作,包括:
如果针对您的应用显示了此通知,则至少在 24 小时后,才会再次在同一设备上显示该通知。
1.3.4 与长时间运行的前台服务相关的系统通知
如果系统检测到您的应用长时间运行某项前台服务(在 24 小时的时间段内至少运行 20 小时),便会发送通知邀请用户与前台服务 (FGS) 任务管理器互动。该通知包含以下内容:
APP is running in the background for a long time. Tap to review.
注意
:如果系统针对您的应用显示了此通知,则至少在 30 天后才会再次显示类似通知。如果前台服务的类型为
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK或FOREGROUND_SERVICE_TYPE_LOCATION
,系统将不会显示此通知。
此外,如果您的应用在 24 小时内运行超过 4 小时的前台服务属于FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK或FOREGROUND_SERVICE_TYPE_LOCATION
类型,则系统不会针对您的应用启动的任何前台服务发送长时间运行通知。
1.3.5 豁免
存在以下情况的应用不会受到 Android 13 中引入的任何省电措施的影响:
在以下情况下,您的应用可以免于进入“受限”应用待机模式存储分区,并可以绕过“8 天无活动”触发器:
- 具有活跃的 widget
- 至少被授予下列其中一种权限: SCHEDULE_EXACT_ALARM
- ACCESS_BACKGROUND_LOCATION
在以下情况下,您的应用可以不受 Android 13 中引入的大多数省电措施的影响,但系统仍然会发送针对长时间运行的前台服务通知:
- 具有进行中的活跃MediaSession
- 被授予ACCESS_FINE_LOCATION 权限
1.3.6 测试
以下几个部分将介绍几种测试 Android 13 中引入的省电措施会对应用产生何种影响的方式。
禁止在后台使用
如需禁止您的应用在后台运行,请在终端窗口中运行以下命令:
adb shell cmd appops set PACKAGE_NAME RUN_ANY_IN_BACKGROUND deny
将应用放入受限存储分区
如需强制系统将您的应用放入受限存储分区,请在终端窗口中运行以下命令:
adb shell am set-standby-bucket PACKAGE_NAME restricted
2、行为变更:以Android 13为目标平台的应用
2.1、通知运行时权限
Android 13 中引入了新的运行时权限,用于从应用发送非豁免通知:POST_NOTIFICATIONS。此更改有助于用户专注于最重要的通知。
强烈建议您尽快以 Android 13 为目标平台,以获享此功能提供的额外控制和灵活性。如果您继续以 12L(API 级别 32)或更低版本为目标平台,您将失去在应用功能环境中请求权限
的机会。
应用的影响总结如下:
Target SDK | 应用 | 权限弹窗 | 临时授权 |
Android 13 pre | 新安装 | 创建第一个通知渠道时 | 无 |
现有 | 首次启动Activity | 一直有效,直到权限弹窗中明确选择 | |
Android 13 | 新安装 | 应用自行控制 | 无 |
现有 | 应用自行控制 | 首次启动Activity为止 |
2.1.1 使用新权限
如需向应用请求新的通知权限,请将应用更新为以 Android 13 为目标平台,并完成与请求其他运行时权限类似的流程,如以下几个部分所述。需要在应用的清单文件中声明的权限会显示在以下代码段中:
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application ...>
...
</application>
</manifest>
3.2.1.2 应用功能取决于用户在权限对话框中所做的选择

在此对话框中,用户可执行以下操作:
注意
:如果用户点按
不允许
,即使仅点按一次,系统也不会再次提示用户,除非他们卸载并重新安装您的应用。
下面几个部分介绍了根据用户操作的不同,应用会有哪些不同的行为表现。
a. 用户选择“允许”如果用户选择允许选项,您的应用可以执行以下操作:
- 发送通知。可以使用所有通知渠道。
- 发送与前台服务相关的通知。这些通知会显示在抽屉式通知栏中。
b. 用户选择“不允许”如果用户选择不允许选项,您的应用将无法发送通知。除了几个特定角色之外,所有通知渠道都会被屏蔽。这类似于用户在系统设置中手动关闭应用的所有通知后发生的行为。
c. 用户滑开对话框
如果用户滑开对话框(即他们既没有选择允许,也没有选择不允许),会发生以下行为:
- 如果您的应用符合获得临时通知授权的条件,系统会保留临时授权。
- 如果您的应用没有临时授权,则将无法发送通知。
2.1.3 对新安装的应用的影响
如果用户在搭载 Android 13 的设备上安装您的应用,应用的通知默认处于关闭状态。在您请求新的权限且用户向您的应用授予该权限之前,您的应用都将无法发送通知。
权限对话框的显示时间取决于应用的目标 SDK 版本:
- 如果您的应用以 Android 13 或更高版本为目标平台,应用将可以完全自行控制权限对话框的显示时间。您可以借此机会向用户说明应用需要此权限的原因,进而鼓励他们授予该权限。
- 如果您的应用以 12L(API 级别 32)或更低版本为目标平台,系统会在您创建第一个通知渠道时显示权限对话框。这通常是在应用启动时。
2.1.4 对现有应用更新的影响
注意
:请考虑下面这种情形,即应用安装在搭载 12L 或更低版本的旧设备上,用户在该设备上允许接收通知,但想淘汰该设备。用户现在使用的是搭载 Android 13 的新设备,并通过备份和恢复功能恢复了应用。
在这种情况下,系统会将您的应用视为“现有应用”,因此该应用会获得发送通知的临时权限。
为最大限度地减少与新通知权限相关的中断,系统会自动向系统升级到 Android 13 之前用户设备上已安装的所有符合条件的应用临时授予新通知权限。此临时授权的持续时间取决于应用的目标 SDK 版本:
- 如果应用以 Android 13 或更高版本为目标平台,则临时授权将持续到应用首次启动 activity 为止。
您的应用可以完全自行控制权限对话框的显示时间。您可以借此机会向用户说明应用需要此权限的原因,进而鼓励他们授予该权限。
- 如果您的应用以 12L 或更低版本为目标平台,则临时授权将一直有效,直到用户在通知权限运行时对话框中明确选择一个选项。也就是说,如果用户在未做出选择的情况下关闭了权限提示,系统会保留应用的临时授权。
2.1.5 获得临时授权的资格要求
您的应用要获得临时授权必须满足以下条件:应用必须已具有通知渠道,并且用户未在搭载 12L 或更低版本的设备上明确停用应用的通知。
如果用户在搭载 12L 或更低版本的设备上停用了应用的通知,当设备升级到 Android 13 或更高版本后,该停用会继续有效。
2.1.6 豁免
与媒体会话有关的通知不受此行为变更的影响。
2.1.7 最佳做法
本部分将介绍几种在应用中最有效地使用新通知权限的方式。
a. 更新应用的目标 SDK 版本
为了让应用更灵活地显示权限对话框,请将应用更新为以 Android 13 为目标平台。
b. 等待一段时间再显示通知权限提示
等到用户熟悉您的应用之后,再请求他们授予任何权限。
新用户可能想要探索您的应用,并切身体会每项通知请求可以带来的好处。您可以通过用户操作触发权限提示。下面列举了几个适合显示通知权限提示的时机:
- 用户点按“提醒铃铛”按钮时。
- 用户选择关注他人的社交媒体帐号时。
- 用户提交外卖订单时。
下图显示了请求通知权限的建议工作流程。或者,您也可以设置一个请求以在应用启动时显示,但仅在应用第 3 次或第 4 次启动后才显示。

c. 在上下文中请求权限
在应用内请求通知权限时,请在正确的上下文中请求,以便用户明确了解通知的用途以及应该选择接收通知的原因。例如,电子邮件应用可能包含为每封新邮件发送通知的选项,或仅为用户是唯一收件人的邮件发送通知的选项。
借此机会明确向用户表明您的意图,有助于鼓励用户向您的应用授予通知权限。
d. 检查您的应用能否发送通知
用户必须为您的应用启用通知,您的应用才能发送通知。要确认用户是否已启用通知,请调用areNotificationsEnabled()。
e. 以负责任的方式使用权限
获得发送通知的许可后,请负责任地使用该权限。用户可以查看您的应用每天发送的通知数量,并且可以随时撤消该权限。
2.2、针对附近 Wi-Fi 设备的新运行时权限
Android 13 引入了NEARBY_WIFI_DEVICES
运行时权限,该权限属于NEARBY_DEVICES权限组,适用于会管理设备与附近 Wi-Fi 接入点连接情况的应用。借助此权限,您可以更轻松地说明应用为何访问附近的 Wi-Fi 设备;在以前的 Android 版本中,这类应用需要声明ACCESS_FINE_LOCATION权限。
如果您的应用以 Android 13 为目标平台并调用多个不同的 Wi-Fi API,则必须从用户处获得这项新权限。
如果您的应用尝试在未获得适当权限的情况下调用 Wi-Fi API,则会发生SecurityException。
2.2.1 受影响的用例
这项新权限会影响几个不同的 Wi-Fi 用例,包括以下用例:
- 查找或连接到附近的设备,如打印机或媒体投射设备。通过该工作流,您的应用可以完成以下类型的任务: 通过带外方式(例如通过 BLE)接收 AP 信息。
- 使用仅限本地使用的热点,通过 Wi-Fi 感知和连接功能发现并连接到设备。
- 通过 Wi-Fi 直连发现和连接到设备。
- 发起与已知 SSID(例如汽车或智能家居设备)的连接。
- 开启仅限本地使用的热点。
- 连接到附近的 Wi-Fi 感知设备。
2.2.2 该权限属于“附近的设备”权限组
NEARBY_WIFI_DEVICES权限是
附近的设备
权限组的一部分。此权限组在 Android 12(API 级别 31)中添加,还包含与蓝牙和超宽带相关的权限。如果您的应用请求此权限组中的多项权限,用户会看到一个运行时对话框,其中会请求用户批准您的应用访问附近的设备。在系统设置中,用户必须以组的形式启用和停用附近的设备权限;例如,针对给定应用,用户无法既停用其 Wi-Fi 访问权限,但又保持启用其蓝牙使用权限。
2.2.3 坚定地声明您的应用不会推导物理位置
在以 Android 13 为目标平台时,请考虑您的应用是否会通过 Wi-Fi API 推导物理位置;如果不会,则应坚定声明此情况。如需做出此声明,请在应用的清单文件usesPermissionFlags属性设为neverForLocation,如以下代码段所示。此过程类似于您声明绝不会将蓝牙设备信息用于获取位置信息时的过程:
<manifest ...>
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
android:usesPermissionFlags="neverForLocation" />
<application ...>
...
</application>
</manifest>
2.2.4 保持后向兼容性
由于NEARBY_WIFI_DEVICES权限仅适用于 Android 13 或更高版本,因此您应保留对ACCESS_FINE_LOCATION的所有声明,以便在您的应用中提供向后兼容性。不过,只要您坚定声明应用不会使用 Wi-Fi API 推导物理位置信息,就可以将此权限的最高 SDK 版本设为32,如下以下代码段所示:
<manifest ...>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="32" />
<application ...>
...
</application>
</manifest>
2.2.5 某些 API 仍需要位置信息权限
有几个 Wi-Fi API 仍然需要ACCESS_FINE_LOCATION权限才能获取位置信息,就像它们在 12L 及更低版本上的一样。示例包括WifiManager类中的以下方法:
2.2.6 检查需要新权限的 API
如果您的应用以 Android 13 或更高版本为目标平台,您必须声明NEARBY_WIFI_DEVICES权限才能调用以下任何 Wi-Fi API:
- WifiManager startLocalOnlyHotspot()
- WifiAwareManager attach()
- WifiAwareSession publish()
- subscribe()
- WifiP2pManager addLocalService()
- connect()
- createGroup()
- discoverPeers()
- discoverServices()
- requestDeviceInfo()
- requestGroupInfo()
- requestPeers()
- WifiRttManager startRanging()
2.3、在后台使用身体传感器需要新的权限
Android 13 中引入了“在使用时”访问身体传感器(例如心率、体温和血氧饱和度)的概念。此访问模式与Android 10(API 级别 29)系统为位置信息引入的模式非常相似。
如果您的应用以 Android 13 为目标平台,并且在后台运行时需要访问身体传感器信息,那么除了现有的BODY_SENSORS权限外,您还必须声明新的BODY_SENSORS_BACKGROUND权限。
注意
:这是受到“硬性限制”的权限,除非设备的安装程序针对您的应用将该权限列入了许可名单,否则您的应用将无法获得此权限。如需了解详情,请参阅有关受限权限的指南。
2.4、intent 过滤器会屏蔽不匹配的 intent
当您的应用向以 Android 13 或更高版本为目标平台的其他应用的导出组件发送 intent 时,仅当该 intent 与接收应用中的<intent-filter>元素匹配时,系统才会传送该 intent。换言之,系统会屏蔽所有不匹配的 intent,但以下情况除外:
- 发送给其他应用的未声明任何 intent 过滤器的组件的 intent。
- 发送给您应用中的其他组件的 intent。
- 由系统发送的 intent。
- 由具有根级特权的用户发送的 intent。
2.5、更安全地导出上下文注册的接收器
为了帮助提高运行时接收器的安全性,Android 13 允许您指定您应用中的特定广播接收器是否应被导出以及是否对设备上的其他应用可见。如果导出广播接收器,其他应用将可以向您的应用发送不受保护的广播。此导出配置在以 Android 13 或更高版本为目标平台的应用中可用,有助于防止一个主要的应用漏洞来源。
在以前的 Android 版本中,设备上的任何应用都可以向动态注册的接收器发送不受保护的广播,除非该接收器受签名权限的保护。
要实现此安全增强措施,请执行以下操作:
a. 启用DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED兼容性框架更改。
b. 在应用的每个广播接收器中,明确指明其他应用是否可以向其发送广播,如以下代码段所示:
// This broadcast receiver should be able to receive broadcasts from other apps.
// This option causes the same behavior as setting the broadcast receiver's
// "exported" attribute to true in your app's manifest.
context.registerReceiver(sharedBroadcastReceiver, intentFilter,
RECEIVER_EXPORTED);
// For app safety reasons, this private broadcast receiver should **NOT**
// be able to receive broadcasts from other apps.
context.registerReceiver(privateBroadcastReceiver, intentFilter,
RECEIVER_NOT_EXPORTED);
注意
:如果启用了
DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED
兼容性框架更改,则
必须
为每个广播接收器指定
RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED。否则,当您尝试注册广播接收器时,系统会抛出SecurityException
。
为了帮助检测这种情况,Android Studio 将会采用一个 lint 规则,而即将发布的ContextCompat将会检查接收器配置是否正确。
四、迁移指南
每次发布新的 Android 版本时,我们都会推出一些全新的功能并引入一些行为变更,目的就在于提高 Android 的实用性、安全性和性能。在许多情况下,您的应用都可以直接使用并完全按预期运行;而在其他的一些情况下,您可能需要对应用进行更新以适应这些平台变更。
源代码发布到 AOSP(Android 开源平台)后,用户随之就可能开始使用新平台。因此,应用必须做好准备,让用户能够正常使用,最好还能利用新的功能和 API 发挥新平台的最大优势。
典型的迁移包含两个阶段,这两个阶段可以同时进行:
- 确保应用兼容性(在 Android 13 最终发布前)
- 针对新平台的功能和 API 调整应用(最终发布后尽快进行)
1、确保与 Android 13 兼容
您必须测试现有应用在 Android 13 上的运行情况,以确保更新到最新版 Android 的用户获得良好的体验。有些平台变更可能会影响应用的行为方式,因此,必须尽早进行全面测试并对应用进行任何必要的调整。
您通常可以调整应用并发布更新,而无需更改应用的targetSdkVersion。同样,您应该也不需要使用新的 API 或更改应用的compileSdkVersion,但是这一点可能要取决于应用的构建方式及其所使用的平台功能。
在开始测试之前,请务必熟悉行为变更:所有应用。即使您不更改应用的targetSdkVersion,这些变更也可能会影响您的应用。

请务必查看并测试受限非SDK接口的使用。您应使用应用公共 SDK 或 NDK 等效项替换应用使用的任何受限接口。留意突出显示这些访问权限的 logcat 警告,并使用StrictMode方法
detectNonSdkApiUsage()以编程方式捕获它们。最后,请务必完整
测试应用中的库和SDK
,确保它们在 Android 13 上按预期运行,并遵循隐私权、性能、用户体验、数据处理和权限方面的最佳做法。如果您遇到问题,请尝试更新到最新版本的 SDK,或联系 SDK 开发者寻求帮助。
当您完成测试并进行更新后,我们建议您立即发布兼容的应用。这样可以尽早让您的用户测试应用,并帮助用户顺利过渡到 Android 13。
2、更新应用的目标平台并使用新 API 进行构建
发布应用的兼容版本后,下一步是通过更新targetSdkVersion并利用 Android 13 的新 API 和功能来添加对 Android 13 的全面支持。准备就绪后,您即可开始进行这些更新,请注意以新平台为目标平台方面的Google Play 要求。
当您计划全面支持 Android 13 时,请查看行为变更:以Android 13为目标平台的应用。这些针对性的行为变更可能会导致需要解决的功能问题。在某些情况下,这些变更需要进行大量开发工作,因此我们建议您尽早了解并解决这些问题。为帮助确定影响您的应用的具体行为变更,请使用兼容性切换开关来测试已启用所选变更的应用。
以下是全面支持 Android 13 的步骤。

a. 获取 SDK,更改目标平台,使用新 API 进行构建
如需开始针对 Android 13 全面支持进行测试,请使用最新预览版的 Android Studio 下载 Android 13 SDK,以及所需的任何其他工具。接下来,更新应用的targetSdkVersion和compileSdkVersion,然后重新编译应用。如需了解详情,请参阅SDK 设置指南。
b. 测试 Android 13 应用
编译应用并将其安装到搭载 Android 13 的设备上后,请开始测试,以确保应用能够在 Android 13 上正常运行。某些行为变更仅在您的应用以新平台为目标平台时才适用,因此您需要在开始之前阅读本文的行为变更。
与基本兼容性测试一样,完成所有流程和功能以查找问题。将测试重点放在以Android 13为目标平台的行为变更上。您还可以根据核心应用质量指南和测试最佳做法检查您的应用。请务必查看并测试可能适用的受限非SDK接口的使用。留意突出显示这些访问权限的 logcat 警告,并使用 StrictMode 方法detectNonSdkApiUsage()以编程方式捕获它们。最后,请务必完整测试应用中的库和 SDK,确保它们在 Android 13 上按预期运行,并遵循隐私权、性能、用户体验、数据处理和权限方面的最佳做法。如果您遇到问题,请尝试更新到最新版本的 SDK,或联系 SDK 开发者寻求帮助。
c. 使用应用兼容性切换开关进行测试
Android 13 包含兼容性切换开关,可让您更轻松地在您的应用中测试针对性的行为变更。对于可调试的应用,切换开关可让您:
- 在不实际更改应用的 targetSdkVersion 的情况下测试针对性的变更。您可以使用切换开关强制启用特定的针对性行为变更,以评估对现有应用的影响。
- 仅针对特定变更进行测试。您可以使用切换开关停用除要测试的变更之外的所有针对性变更,而不必一次处理所有针对性变更。
- 通过 adb 管理切换开关。您可以使用 adb 命令在自动测试环境中启用和停用可切换的变更。
- 使用标准变更 ID 更快地进行调试。每个可切换的变更都具有唯一 ID 和名称,可用于在日志输出中快速调试根本原因。
在您准备更改应用的目标平台时,或者在您积极开发以便支持 Android 13 时,切换开关将十分有用。如需了解详情,请参阅兼容性框架变更 (Android 13)。
五、重点适配问题
为了解当前应用对Android 13 版本的适配情况,以便更好推进MIUI Android 13适配工作,我们已在内部进行了自动化兼容性测试。我们选取了小米应用商店Top的各类应用,对每个应用进行下载、安装、启动、monkey测试、遍历测试、卸载,并在整个过程中检测是否有FC/ANR问题发生。根据测试结果,我们强烈建议您关注以下问题。若您的应用存在以下情况,请尽快适配。
1、Native Crash问题
移动安全联盟msa的SDK崩溃问题,特征:linker64
04-24 18:24:19.863 8983 8983 F DEBUG : Cmdline: xxx
04-24 18:24:19.863 8983 8983 F DEBUG : pid: 8470, tid: 8470, name: xxx >>> xxx <<<
04-24 18:24:19.863 8983 8983 F DEBUG : uid: 10195
04-24 18:24:19.864 8983 8983 F DEBUG : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
04-24 18:24:19.864 8983 8983 F DEBUG : pac_enabled_keys: 0000000000000000
04-24 18:24:19.864 8983 8983 F DEBUG : signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x000000704a6bd764
04-24 18:24:19.864 8983 8983 F DEBUG : x0 00000031b8a0a445 x1 0000007fdc63abc8 x2 0000000000000000 x3 0000007fdc63abb8
04-24 18:24:19.864 8983 8983 F DEBUG : x4 0000007049d551d0 x5 0000000000000000 x6 fefefefefefefeff x7 7f7f7f7f7f7f7f7f
04-24 18:24:19.864 8983 8983 F DEBUG : x8 0000000000428290 x9 000000704857c2e4 x10 0000000000000070 x11 0000000000000000
04-24 18:24:19.864 8983 8983 F DEBUG : x12 000000704cac0950 x13 f43ca3815c475fbd x14 0000000000000006 x15 ffffffffffffffff
04-24 18:24:19.865 8983 8983 F DEBUG : x16 0000000000000001 x17 000000704cbaa880 x18 0000006c8f0bdf90 x19 000000704b984018
04-24 18:24:19.865 8983 8983 F DEBUG : x20 0000007fdc63abc8 x21 00000031b8a0a445 x22 00000000b8a0a445 x23 0000000000000000
04-24 18:24:19.865 8983 8983 F DEBUG : x24 0000000000000000 x25 000000704b8abdd0 x26 000000704cbdd3a8 x27 000000704cbdf000
04-24 18:24:19.865 8983 8983 F DEBUG : x28 0000000000000000 x29 0000007fdc63aac0
04-24 18:24:19.866 8983 8983 F DEBUG : lr 000000704cb05130 sp 0000007fdc63aac0 pc 000000704cb0515c pst 0000000060001000
04-24 18:24:19.866 8983 8983 F DEBUG : backtrace:
04-24 18:24:19.866 8983 8983 F DEBUG : #00 pc 000000000005215c /apex/com.android.runtime/bin/linker64 (__dl__ZNK6soinfo10gnu_lookupER10SymbolNamePK12version_info+112) (BuildId: 5349b396f749a8df4f77c0798d1b2185)
04-24 18:24:19.866 8983 8983 F DEBUG : #01 pc 0000000000043d04 /apex/com.android.runtime/bin/linker64 (__dl__ZL24dlsym_handle_lookup_implP19android_namespace_tP6soinfoS2_PS2_R10SymbolNamePK12version_info+408) (BuildId: 5349b396f749a8df4f77c0798d1b2185)
04-24 18:24:19.867 8983 8983 F DEBUG : #02 pc 000000000003d834 /apex/com.android.runtime/bin/linker64 (__dl__Z8do_dlsymPvPKcS1_PKvPS_+904) (BuildId: 5349b396f749a8df4f77c0798d1b2185)
04-24 18:24:19.867 8983 8983 F DEBUG : #03 pc 0000000000038300 /apex/com.android.runtime/bin/linker64 (__dl__Z10dlsym_implPvPKcS1_PKv+92) (BuildId: 5349b396f749a8df4f77c0798d1b2185)
04-24 18:24:19.867 8983 8983 F DEBUG : #04 pc 0000000000001070 /apex/com.android.runtime/lib64/bionic/libdl.so (dlsym+20) (BuildId: 72dd43ea80dff185706bb3bdfcfaf051)
04-24 18:24:19.867 8983 8983 F DEBUG : #05 pc 000000000045ae84 /apex/com.android.art/lib64/libart.so (art::SharedLibrary::FindSymbolWithoutNativeBridge(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+72) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.867 8983 8983 F DEBUG : #06 pc 00000000004591d8 /apex/com.android.art/lib64/libart.so (art::JavaVMExt::FindCodeForNativeMethod(art::ArtMethod*)+1532) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.867 8983 8983 F DEBUG : #07 pc 00000000006da6bc /apex/com.android.art/lib64/libart.so (artFindNativeMethodRunnable+328) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.867 8983 8983 F DEBUG : #08 pc 00000000006da9d8 /apex/com.android.art/lib64/libart.so (artFindNativeMethod+592) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.867 8983 8983 F DEBUG : #09 pc 000000000020f5f8 /apex/com.android.art/lib64/libart.so (art_jni_dlsym_lookup_stub+72) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #10 pc 000000000021a154 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+148) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #11 pc 000000000021076c /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+556) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #12 pc 000000000027a364 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+188) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #13 pc 0000000000610d30 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+464) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #14 pc 000000000046dfb0 /apex/com.android.art/lib64/libart.so (art::JNI<false>::CallBooleanMethodA(_JNIEnv*, _jobject*, _jmethodID*, jvalue const*)+600) (BuildId: a479d08d252964da32f296b9ff5cf3ce)
04-24 18:24:19.868 8983 8983 F DEBUG : #15 pc 00000000000323a4 <anonymous:6cfd9a9000>
如您使用了此SDK,请联系SDK提供方。
六、开发者支持
如您在适配过程中遇到问题,辛苦联系客服,与我们取得联系,我们的兼容性工程师团队会尽快为您解决。