Programar alarmes exatos não é permitido por padrão

精确闹钟适用于用户指定的通知,或是在确切时间需要执行的操作。

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 分钟。

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

在安排精确闹钟之前,应用必须至少检查自己是否具有相应权限。如果应用不具备此权限,则必须通过调用 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 操作请求执行此操作)。

预先授予

测试准则

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