Android 14 Behavior Changes:精確鬧鐘行為變更

Carter Chen
9 min readOct 14, 2023

--

隨著搭載 Android 14 的 Google 親兒子 Pixel 8 上市,各家廠商的作業系統也即將陸續開始推送 Android 14 更新了。

Android 14 不但為用戶帶來了許多酷炫的新功能與特性,也為開發者帶來了許多開發上的……樂趣 🙄:Behavior Changes。

其中系統預設拒絕排定精確鬧鐘(schedule exact alarms are denied by default)是我認為是滿重大的一個變化,本文也將著重探討這個議題。

與精確鬧鐘有關的 keywords

很多時候我們需要去安排精確鬧鐘來觸發任務,例如:

  • 在指定的時間發送提醒(日曆)
  • 在活動的前幾分鐘來提示使用者注意一下(蝦皮購物活動、高鐵到站通知)

這些場合都需要設定精確的鬧鐘。如果你需要安排 task 需要在精準的時間點觸發,那你對以下的關鍵字或是 API 應該不陌生:

一切的根源,都從 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

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_ALARMcanScheduleExactAlarms() 都是在 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 官方,或是身為開發者的我們,無非都是希望我們所有的努力都可以為用戶提供更出色的使用體驗,只要用戶用得開心,那一切都是值得的了 ❤️

--

--

No responses yet