默认情况下拒绝安排精确闹钟

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

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

需要 SCHEDULE_EXACT_ALARM 权限才能通过以下 API 启动精确闹钟,否则将抛出 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 权限,并且权限授予过程需要用户执行额外的步骤,因此强烈建议开发人员评估其用例,并确定精确闹钟对于其用例是否有意义。

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

在应用的生命周期内安排重复工作

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

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

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

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

  1. 应用应调用 AlarmManager.canScheduleExactAlarms() 以确认它具有相应的权限。
  2. 如果应用没有该权限,则调用一个意图,该意图包含 ACTION_REQUEST_SCHEDULE_EXACT_ALARM 以及应用的包名,以请求用户授予权限。

    在应用的 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 意图操作 请求此操作)。

预授权

测试指南

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