公司專案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_WAKEUP
、RTC_WAKEUP
或RTC
。它會在裝置處於低功耗模式時仍然觸發鬧鐘。
需要注意的是,如果 targetSdkVersion >= 33,且在 Android14 裝置上沒有顯式申請該許可權,呼叫上面的3個方法,則會丟擲一個 SecurityException
異常
不過Android13新增android.permission.USE_EXACT_ALARM
,用了模擬機的Android13版本測試,如果不寫android.permission.USE_EXACT_ALARM
還是會出現上面的錯誤
所以最終做法,就是2個許可權android.permission.SCHEDULE_EXACT_ALARM
和android.permission.USE_EXACT_ALARM
都申請才不會有問題,這裡推薦許可權申請框架可以使用getActivity/XXPermissions: Android 許可權請求框架,已適配 Android 14這個開源庫
應該是setExact方法的限制稍微鬆一些吧,上面的方法可以使用,不過實際沒有太高精度要求,只使用setExact應該也能達到效果
像上述的app,只是在第二日凌晨進行通知欄的資料更新(類似每日提醒那種感覺)
至於保活方面,高版本的Android限制太多,產品也沒有其他要求,就先這樣,只要app後臺沒被殺死,每日通知還是有的
不過看了其他文章,說到:
日曆或鬧鐘應用需要在應用停止執行時傳送日曆提醒、喚醒鬧鐘或提醒。這些應用可以請求
USE_EXACT_ALARM
常規許可權。系統將在安裝時授予USE_EXACT_ALARM
許可權,擁有此許可權的應用將能夠像具有 SCHEDULE_EXACT_ALARM 許可權的應用一樣設定精確鬧鐘。