默认拒绝精确闹钟

精确闹钟用于用户意图的通知或需要在精确时间发生的动作。

SCHEDULE_EXACT_ALARM 权限于 Android 12 中引入,用于应用调度精确闹钟,但现在**不再预先授予大多数以 Android 13 及更高版本为目标的新安装应用**(将默认设置为拒绝)。如果用户通过备份和恢复操作将应用数据传输到运行 Android 14 的设备,该权限仍将被拒绝。如果现有应用已拥有此权限,则在设备升级到 Android 14 时将预先授予该权限。

通过以下 API 启动精确闹钟需要 SCHEDULE_EXACT_ALARM 权限,否则将抛出 SecurityException

SCHEDULE_EXACT_ALARM 权限的现有最佳实践仍然适用,包括以下几点:

受影响的应用

如果设备运行 Android 14 或更高版本,此更改将影响具有以下特征的新安装应用:

  • 面向 Android 13(API 级别 33)或更高版本。
  • 在清单中声明 SCHEDULE_EXACT_ALARM 权限。
  • 不属于豁免预授予场景。
  • **不是**日历或闹钟应用。

日历和闹钟应用应声明 USE_EXACT_ALARM

日历或闹钟应用需要在应用不再运行时发送日历提醒、唤醒闹钟或警报。这些应用可以请求 USE_EXACT_ALARM 普通权限。USE_EXACT_ALARM 权限将在安装时授予,拥有此权限的应用将能够像拥有 SCHEDULE_EXACT_ALARM 权限的应用一样调度精确闹钟。

可能不需要精确闹钟的用例

由于 SCHEDULE_EXACT_ALARM 权限现在默认被拒绝,并且权限授予过程需要用户执行额外的步骤,因此强烈建议开发者评估其用例并确定精确闹钟是否仍然适合其用例。

以下列表显示了可能不需要精确闹钟的常见工作流程:

在应用生命周期内调度重复工作
set() 方法在任务需要考虑实时约束时非常有用,例如明天下午 2:00 或 30 分钟后触发。否则,建议改用 postAtTime()postDelayed() 方法。
调度后台工作,例如更新应用和上传日志
WorkManager 提供了一种调度时间敏感型定期工作的方法。您可以提供重复间隔和弹性间隔(最少 15 分钟)来定义工作的细粒度运行时。
系统处于空闲状态时需要闹钟在大致时间触发
使用非精确闹钟。具体来说,调用 setAndAllowWhileIdle()
用户指定应在特定时间后发生的动作
使用非精确闹钟。具体来说,调用 set()
用户指定可在时间窗口内发生的动作
使用非精确闹钟。具体来说,调用 setWindow()。请注意,允许的最小窗口长度为 10 分钟。

继续使用精确闹钟的迁移步骤

应用至少必须在调度精确闹钟之前检查是否具有该权限。如果应用没有该权限,则必须通过调用 Intent 向用户请求。

这与请求特殊权限的标准工作流程相同:

  1. 应用应调用 AlarmManager.canScheduleExactAlarms() 以确认其具有适当的权限。
  2. 如果应用没有该权限,则调用包含 ACTION_REQUEST_SCHEDULE_EXACT_ALARM 以及应用软件包名称的 Intent,以要求用户授予权限。

    在应用的 onResume() 方法中检查用户的决定

  3. 监听在用户授予权限时发送的 AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 广播。

  4. 如果用户授予了您的应用权限,您的应用可以设置精确闹钟。如果用户拒绝了权限,则优雅降级您的应用体验,以便在没有受该权限保护的信息的情况下为用户提供功能。

以下代码段演示了如何检查 SCHEDULE_EXACT_ALARM 权限:

val alarmManager: AlarmManager = context.getSystemService<AlarmManager>()!!
when {
   // If permission is granted, proceed with scheduling exact alarms.
   alarmManager.canScheduleExactAlarms() -> {
       alarmManager.setExact(...)
   }
   else -> {
       // Ask users to go to exact alarm page in system settings.
       startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
   }
}

onResume() 中检查权限并处理用户决定的示例代码

override fun onResume() {
     
   if (alarmManager.canScheduleExactAlarms()) {
       // Set exact alarms.
       alarmManager.setExact(...)
   }
   else {
       // Permission not yet approved. Display user notice and revert to a fallback  
       // approach.
       alarmManager.setWindow(...)
   }
}

权限拒绝时的优雅降级

有些用户会拒绝授予权限。在这种情况下,我们建议应用优雅地降级体验,并通过识别其用例,努力提供最佳的备用用户体验。

豁免

以下类型的应用始终允许调用 setExact()setExactAndAllowWhileIdle() 方法:

  • 使用平台证书签名的应用。
  • 特权应用。
  • 在电池优化白名单上的应用(如果您的应用符合要求,您可以使用 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS intent 操作请求此权限)。

预授予

测试指南

要测试此更改,请在系统设置的“特殊应用权限”页面(**设置 > 应用 > 特殊应用权限 > 闹钟和提醒**)中禁用您应用的“闹钟和提醒”权限,并观察您应用的行为。