Android 14 Behavior Changes:精確鬧鐘行為變更
隨著搭載 Android 14 的 Google 親兒子 Pixel 8 上市,各家廠商的作業系統也即將陸續開始推送 Android 14 更新了。
Android 14 不但為用戶帶來了許多酷炫的新功能與特性,也為開發者帶來了許多開發上的……樂趣 🙄:Behavior Changes。
其中系統預設拒絕排定精確鬧鐘(schedule exact alarms are denied by default)是我認為是滿重大的一個變化,本文也將著重探討這個議題。
與精確鬧鐘有關的 keywords
很多時候我們需要去安排精確鬧鐘來觸發任務,例如:
- 在指定的時間發送提醒(日曆)
- 在活動的前幾分鐘來提示使用者注意一下(蝦皮購物活動、高鐵到站通知)
這些場合都需要設定精確的鬧鐘。如果你需要安排 task 需要在精準的時間點觸發,那你對以下的關鍵字或是 API 應該不陌生:
- AlarmManager API —
setExact()
- AlarmManager API —
setExactAndAllowWhileIdle()
- AlarmManager API —
setAlarmClock()
- AlarmManager API —
canScheduleExactAlarms()
- AlarmManager Constant —
ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
- Android Permission —
SCHEDULE_EXACT_ALARM
一切的根源,都從 Android 12(Android S)開始
Android 12 首次引進了 SCHEDULE_EXACT_ALARM
這個 permission。在 Android 12 以後,凡是你想設定精確鬧鐘,你都必須要在 AndroidManifest.xml
加入這行:
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
否則,在你在呼叫 setExact()
的時候,系統會直接送你一個 SecurityException ^_^
所以在 Android 12 最懶的解法,便是加入 SCHEDULE_EXACT_ALARM
這個 permission。而由於系統預設 allow 這個 permission 的關係,只要有好好祈禱,使用者基本上不會知道、也不會去把 exact alarm 的 permission 關閉,精確鬧鐘的功能基本上就可以好好滴運作下去!
(阿如果被關閉了也沒有關係,後面我們會來分享處理這個情境的 best practice!)
那 Android 14 以後呢?
Android 官方宣布在幾種狀況下,exact alarm 的 permission 會預設關閉:
- APP 的
targetSdkVersion
為 Android 13 (API 級別 33) 或以上。 AndroidManifest.xml
中有宣告SCHEDULE_EXACT_ALARM
這個 permission。- 不屬於豁免或預先授權情境。
- 不是日曆或鬧鐘時鐘應用程式。(只要加入
USE_EXACT_ALARM
這個權限並且通過審查就可以豁免,但前提是要能過得了審查)
BUT,官方也宣布,如果你想要在 Google Play 上架,自 2023 年 8 月 31 日起,APP 的 targetSdkVersion
必須指定 Android 13 (API 級別 33) 或以上。
那不就是要強迫大家適配 Android 14 的意思嗎?
沒錯!那些有用到精確鬧鐘的開發者,一個都不能少~~~
如果你想知道你的 APP 有沒有遭殃,可以用下面的 cheat sheet 來速查:
排定精確鬧鐘的最佳實踐
啊啊啊啊啊那我是誰?我在哪?我要做什麼?
其實也不用那麼擔心,好在我們的爸爸是 Google 爸爸,爸爸還是幫我們指引了明燈,提供了一個 Best Practice:
- 在呼叫
alarmManager.setExact(…)
之前,可先透過canScheduleExactAlarms()
檢查權限。
val alarmManager: AlarmManager = context.getSystemService<AlarmManager>()!!
when {
alarmManager.canScheduleExactAlarms() -> {
alarmManager.setExact(...)
}
else -> {
...
}
}
- 如果 APP 一開始沒有取得權限,可以透過發起帶有
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
這個 Action 的 Intent 來開啟啟用權限頁面。
startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
- 記得事先註冊
ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED
這個廣播,如果有收到這個 Action,就表示SCHEDULE_EXACT_ALARM
的權限被用戶啟用了。接下來我們就可以處理相關 UI 或 Dialog 的顯示或隱藏。
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED) {
...
}
}
}
替代方案:第三方套件 AlarmScheduler
畢竟 SCHEDULE_EXACT_ALARM
和 canScheduleExactAlarms()
都是在 Android 12 以後才加入的東西,如果我們正在 maintain 一個 production APP,使用者一定會橫跨 Android 14 / 13 / 12 / 11 甚至是更早的好幾個版本。在進行 Android 開發時,要進行多個版本的適配總是最令人頭痛的事 😫
如果想要省下向前相容的麻煩,或許可以試試我們開發的 open source library :AlarmScheduler 🤩🤩🤩
dependencies {
implementation 'com.carterchen247:alarm-scheduler:x.x.x'
}
AlarmScheduler 的目標是在精確鬧鐘的設定上,為開發者提供最好的開發體驗。AlarmScheduler 提供了易用的 API,同時也考慮到向前相容與 Android 各版本的適配。
安排精確鬧鐘
透過簡單的 AlarmScheduler.schedule(config)
,就可以安排你的第一個精確鬧鐘:
val config = AlarmConfig(
triggerTime = Date().time + 10000L,
type = 1
) {
dataPayload("reminder" to "have a meeting")
}
AlarmScheduler.schedule(config)
定義鬧鐘任務類型
透過自訂的 AlarmTask
介面,可以指定不同的鬧鐘任務。鬧鐘觸發時,會呼叫 onAlarmFires
這個 callback:
class DemoAlarmTask : AlarmTask {
companion object {
const val TYPE = 1
}
override fun onAlarmFires(alarmId: Int, dataPayload: DataPayload) {
// trigger here
}
}
錯誤處理機制
AlarmScheduler.schedule(config)
也可以多帶一個 callback,讓我們能根據 schedule 的結果做出對應的處理:
AlarmScheduler.schedule(config) { result ->
when (result) {
is ScheduleResult.Success -> {
// do your stuff
}
is ScheduleResult.Failure -> {
// handle error
when (result) {
ScheduleResult.Failure.CannotScheduleExactAlarm -> {
// ...
}
is ScheduleResult.Failure.Error -> {
// ...
}
}
}
}
}
精確鬧鐘權限頁面跳轉封裝
Android 12 以上,跳轉精確鬧鐘權限頁面的邏輯,已經封裝成 extension function 了:
fun Activity.openExactAlarmSettingPage() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
startActivity(
Intent(
Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM,
Uri.parse("package:$packageName")
)
)
}
}
精確鬧鐘權限用戶同意事件監聽
透過 AlarmSchedulerEventObserver
,可以偵測用戶是否同意了精確鬧鐘權限,讓我們可以進行後續的 UI 與 Dialog 顯示 / 隱藏:
AlarmSchedulerEventObserver { event ->
if (event is ScheduleExactAlarmPermissionGrantedEvent) {
// do your stuff
}
}
結語
大概就是這樣!本文大致的介紹了一下 Android 14 在精確鬧鐘上的行為變更,還有相關的注意事項與解決方案。
雖然 Google 爸爸每年都會發出副本挑戰,但身為 native APP 開發者,這可說是一個必經的試煉呢 😜
相信不管是 Android 官方,或是身為開發者的我們,無非都是希望我們所有的努力都可以為用戶提供更出色的使用體驗,只要用戶用得開心,那一切都是值得的了 ❤️