Android12版本鬧鐘服務崩潰問題

one發表於2023-12-06

原文地址: Android12版本鬧鐘服務崩潰問題 - Stars-One的雜貨小窩

公司專案app線上出現的崩潰記錄問題,崩潰日誌如下所示:

Caused by java.lang.SecurityException: Caller com.health.trackeranz needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms.

一看到是安全異常,估計就是高版本android系統加的限制了,原因就是沒正確適配新許可權導致的崩潰問題

先貼下已解決的程式碼:

//在第二天的0:00清理發出清理資料的廣播
val calendar: Calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.add(Calendar.DAY_OF_MONTH, 1)

//測試用的資料,鬧鐘定為60s後
//val calendar: Calendar = Calendar.getInstance()
//calendar.add(Calendar.SECOND, 60)

val alarmManager = application.getSystemService<AlarmManager>()

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager?.canScheduleExactAlarms()==false) {
	alarmManager.setExactAndAllowWhileIdle(
		AlarmManager.RTC_WAKEUP,
		calendar.getTimeInMillis(),
		pendingIntent
	)
} else {
	alarmManager?.setExact(
		AlarmManager.RTC_WAKEUP,
		calendar.getTimeInMillis(),
		pendingIntent
	)
}
LogUtils.d("鬧鐘已啟動,預定觸發時間:" + TimeUtils.date2String(calendar.time))

這裡程式碼注意alarmManager?.canScheduleExactAlarms()==false這個判斷,之前沒有新增次判斷,於是就有了上文提及的崩潰問題

復現的話很容易,去設定頁面裡,把應用的鬧鐘服務關閉就會出現了,如下圖所示

原因

首先,瞭解下alarmManager設定定時的3個方法:

  • setExactAndAllowWhileIdle(long triggerAtMillis, PendingIntent operation):這個方法用於設定精確的鬧鐘,即你可以指定鬧鐘觸發的特定時間。它會在裝置進入低功耗模式時仍然觸發鬧鐘。但是,如果你的應用程式在後臺執行並且裝置處於省電模式,則可能不會觸發鬧鐘。
  • setExact(long triggerAtMillis, PendingIntent operation):這個方法也用於設定精確的鬧鐘,與 setExactAndAllowWhileIdle 方法類似,允許你指定特定的觸發時間。但是,它不會在裝置處於低功耗模式時觸發鬧鐘。如果你的應用程式在後臺執行並且裝置處於省電模式,則鬧鐘可能會被延遲執行。
  • setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation):這個方法允許你設定具有彈性的觸發時間的鬧鐘,以適應裝置的省電模式。它提供了三種可能的觸發型別:ELAPSED_REALTIME_WAKEUPRTC_WAKEUPRTC。它會在裝置處於低功耗模式時仍然觸發鬧鐘。

需要注意的是,如果 targetSdkVersion >= 33,且在 Android14 裝置上沒有顯式申請該許可權,呼叫上面的3個方法,則會丟擲一個 SecurityException 異常

不過Android13新增android.permission.USE_EXACT_ALARM,用了模擬機的Android13版本測試,如果不寫android.permission.USE_EXACT_ALARM還是會出現上面的錯誤

所以最終做法,就是2個許可權android.permission.SCHEDULE_EXACT_ALARMandroid.permission.USE_EXACT_ALARM都申請才不會有問題,這裡推薦許可權申請框架可以使用getActivity/XXPermissions: Android 許可權請求框架,已適配 Android 14這個開源庫

應該是setExact方法的限制稍微鬆一些吧,上面的方法可以使用,不過實際沒有太高精度要求,只使用setExact應該也能達到效果

像上述的app,只是在第二日凌晨進行通知欄的資料更新(類似每日提醒那種感覺)

至於保活方面,高版本的Android限制太多,產品也沒有其他要求,就先這樣,只要app後臺沒被殺死,每日通知還是有的

不過看了其他文章,說到:

日曆或鬧鐘應用需要在應用停止執行時傳送日曆提醒、喚醒鬧鐘或提醒。這些應用可以請求 USE_EXACT_ALARM 常規許可權。系統將在安裝時授予 USE_EXACT_ALARM 許可權,擁有此許可權的應用將能夠像具有 SCHEDULE_EXACT_ALARM 許可權的應用一樣設定精確鬧鐘。

參考

相關文章