通知运行时权限

Android 13(API 级别 33)及更高版本支持一项用于发送非豁免(包括前台服务 (FGS))应用通知的运行时权限POST_NOTIFICATIONS。此项变更旨在帮助用户专注于对自己最重要的通知。

我们强烈建议您尽快将目标 API 版本设为 Android 13 或更高版本,以利用此功能带来的额外控制力和灵活性。如果您继续将目标 API 版本设为 12L(API 级别 32)或更低,在根据应用功能上下文请求权限时,您将失去一定的灵活性。

声明权限

如需在您的应用中请求新的通知权限,请将应用更新为以 Android 13 为目标平台,并完成类似于请求其他运行时权限的过程,具体如下文所示。

您需要在应用清单文件中声明的权限如下代码段所示

<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

应用功能取决于用户在权限对话框中的选择

在此对话框中,用户可以执行以下操作

以下各节描述了应用将如何根据用户的操作表现出相应的行为。

用户选择“允许”

如果用户选择了允许选项,您的应用可以执行以下操作

用户选择“不允许”

如果用户选择了不允许选项,除非符合豁免条件,否则您的应用将无法发送通知。除了少数特定角色外,所有通知渠道都将被屏蔽。这类似于用户在系统设置中手动关闭应用所有通知时的行为。

警告:如果您的应用目标版本为 12L 或更低,并且用户点按了不允许(哪怕只有一次),系统在发生以下情况之前不会再次提示用户:

  • 用户卸载并重新安装您的应用。
  • 您将应用更新为目标版本为 Android 13 或更高版本。

用户从对话框中滑开

如果用户从对话框中滑开(即他们既没有选择允许也没有选择不允许),通知权限的状态将保持不变。

对新安装应用的影响

如果用户在运行 Android 13 或更高版本的设备上安装您的应用,该应用的通知默认处于关闭状态。您的应用必须先请求新权限并等待用户授予该权限后,才能发送通知。

权限对话框出现的时间取决于您应用的目标 SDK 版本

  • 如果您的应用以 Android 13 或更高版本为目标平台,则可以完全控制权限对话框的显示时间。请利用这个机会向用户解释应用为何需要此权限,并鼓励他们授予该权限。
  • 如果您的应用以 12L(API 级别 32)或更低版本为目标平台,则系统会在您创建通知渠道后应用首次启动 Activity 时,或者在应用启动 Activity 并随后创建其第一个通知渠道时显示权限对话框。这通常发生在应用启动时。在单 Activity 应用(如大多数 Compose 应用)中,系统会在 MainActivity 启动时显示该对话框。

对现有应用更新的影响

为了最大限度地减少与通知权限相关的干扰,当用户将设备升级到 Android 13 或更高版本时,系统会自动为所有符合条件的应用预先授予该权限。换言之,这些应用可以继续向用户发送通知,而用户不会看到运行时权限提示。

权限预授予的资格

要使应用有资格获得自动预授予,它必须拥有现有的通知渠道,并且未在运行 12L 或更低版本的设备上被用户明确禁用通知。

如果用户在运行 12L 或更低版本的设备上为您的应用禁用了通知,那么在设备升级到 Android 13 或更高版本后,该拒绝状态将持续存在。

豁免

本节包含不受通知权限行为更改影响的通知和应用集合。在 Android 13(API 级别 33)或更高版本上,如果用户拒绝了通知权限,他们仍然会在任务管理器中看到与前台服务相关的通知,但不会在通知抽屉中看到它们。

媒体会话

媒体会话相关的通知不受此行为更改的影响。

配置为自行管理电话的应用

如果您的应用配置为自行管理电话,则无需 POST_NOTIFICATIONS 权限即可发送使用 Notification.CallStyle 通知样式的通知。

如果应用执行了以下所有操作,系统会将其视为已配置为自行管理电话

  1. 声明了 MANAGE_OWN_CALLS 权限。
  2. 实现了 ConnectionService 接口。
  3. 通过调用 registerPhoneAccount() 向设备的电信提供商进行了注册。

测试您的应用

您可以在应用首次在运行 Android 13 或更高版本的设备上使用时,评估通知权限如何影响您的应用。以下几组 Android 调试桥 (ADB) 命令允许您模拟最常见的用户选择顺序和设备升级,而无需重置测试设备:

  • 应用在运行 Android 13 或更高版本的设备上新安装

    adb shell pm revoke PACKAGE_NAME android.permission.POST_NOTIFICATIONS
    adb shell pm clear-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-set
    adb shell pm clear-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-fixed
  • 用户在运行 12L 或更低版本的设备上安装应用时保持通知处于启用状态,然后设备升级到 Android 13 或更高版本

    adb shell pm grant PACKAGE_NAME android.permission.POST_NOTIFICATIONS
    adb shell pm set-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-set
    adb shell pm clear-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-fixed
  • 用户在运行 12L 或更低版本的设备上安装应用时手动禁用通知,然后设备升级到 Android 13 或更高版本

    adb shell pm revoke PACKAGE_NAME android.permission.POST_NOTIFICATIONS
    adb shell pm set-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-set
    adb shell pm clear-permission-flags PACKAGE_NAME \
      android.permission.POST_NOTIFICATIONS user-fixed

最佳实践

本节介绍了在您的应用中以最有效的方式使用新通知权限的几种方法。

更新应用的目标 SDK 版本

为了让您的应用在权限对话框何时出现方面拥有更大的灵活性,请将应用的目标版本更新为 Android 13 或更高版本。

延迟显示通知权限提示

在要求用户授予任何权限之前,请让他们先熟悉您的应用。

新用户可能希望先探索应用,并亲身体验每个单独通知请求的好处。您可以从用户操作中触发权限提示。以下列表显示了适合显示通知权限提示的几个时机示例:

  • 用户点按了“提醒铃铛”按钮。
  • 用户选择关注某人的社交媒体账号。
  • 用户提交了外卖订单。

图 1 显示了请求通知权限的推荐工作流程。除非 shouldShowRequestPermissionRationale() 返回 true,否则您的应用无需显示中间的屏幕(标题为“获取通知!”的屏幕)。在 Compose 中,您可以通过访问 LocalContext.current 并将其转换为 Activity 来获取当前的 Activity

或者,您也可以设置在用户有机会熟悉您的应用后再显示请求。例如,您可以等到用户第三次或第四次启动您的应用时再请求。

After the user signs in, they're presented with an
   invitation to get notified of trip updates. After the user presses the
   I'm in button, the app requests the new permission, which causes the system
   dialog to appear
图 1. 请求通知权限的推荐用户驱动工作流程。只有在 shouldShowRequestPermissionRationale() 返回 true 时,才需要中间的屏幕。

在 Compose 中请求权限

如需在 Compose UI 中请求权限,请结合 ActivityResultContracts.RequestPermission() 协定使用 rememberLauncherForActivityResult() API。

以下代码段展示了如何响应用户交互来请求通知权限:

Kotlin

val context = LocalContext.current
val permissionLauncher = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted ->
    if (isGranted) {
        // Permission granted, you can now send notifications.
    } else {
        // Permission denied, handle accordingly.
    }
}

// ... in your UI ...
Button(onClick = {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
    }
}) {
    Text("Enable Notifications")
}

在上下文中请求权限

在应用内请求通知权限时,请在正确的上下文中进行,以便明确说明通知的用途以及用户为何应该选择加入。例如,电子邮件应用可以包含发送所有新邮件通知的选项,或者仅针对用户作为唯一收件人的邮件发送通知的选项。

利用这个机会提高您意图的透明度,用户将更有可能向您的应用授予通知权限。

检查您的应用是否可以发送通知

在应用发送通知之前,请先确认用户是否已为您的应用启用了通知。为此,请调用 areNotificationsEnabled()

负责任地使用权限

获得发送通知的批准后,请务必负责任地使用该权限。用户可以看到您的应用每天发送的通知数量,并且他们可以随时撤销该权限