精确闹钟适用于用户指定的通知,或是在确切时间需要执行的操作。
SCHEDULE_EXACT_ALARM
是 Android 12 中引入的可让应用安排精确闹钟的权限,不再预先授予以 Android 13 和更高版本为目标平台的最新安装应用(默认情况下,设置为“拒绝”)。如果用户通过备份和恢复操作将应用数据转移到搭载 Android 14 的设备,则该权限仍然会被拒绝。如果
现有应用已拥有此权限,那么系统会在设备
升级到 Android 14。
需要 SCHEDULE_EXACT_ALARM
权限才能通过以下 API 启动精确闹钟,否则系统会抛出 SecurityException
:
SCHEDULE_EXACT_ALARM
权限的现有最佳实践仍然适用,其中包括:
- 在安排精确闹钟之前,请使用
canScheduleExactAlarms()
检查权限。 - 请将应用设置为监听并正确响应前台广播
AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
,当用户授予权限时系统会发送该广播。
受影响的应用
如果设备搭载 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 向用户请求此权限。
这与请求特殊权限的标准工作流相同:
- 应用应调用
AlarmManager.canScheduleExactAlarms()
以确认它具有适当的权限。 如果应用不具备此权限,请调用包含
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
以及应用软件包名称的 intent,要求用户授予权限。在应用的
onResume()
方法中检查用户的决定。监听用户授予权限时系统发送的
AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
广播。如果用户向您的应用授予了相应权限,您的应用就可以设置精确闹钟。如果用户拒绝授予该权限,请优雅降级应用体验,使应用在未获得受该权限保护的信息时也能向用户提供功能。
以下代码段演示了如何检查是否具有 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 操作请求执行此操作)。
预先授予
- 系统将为
SYSTEM_WELLBEING
角色持有者预先授予SCHEDULE_EXACT_ALARM
。
测试准则
要测试此更改,请在系统设置的特殊应用权限页面停用闹钟和提醒权限(设置 > 应用 > 特殊应用权限 > 闹钟和提醒),并观察应用的行为。