fix(android): guard setExactAndAllowWhileIdle with canScheduleExactAlarms() check
SecurityException crash on Android 12+ when SCHEDULE_EXACT_ALARM special access not user-granted. Now checks canScheduleExactAlarms() and falls back to setAndAllowWhileIdle() (inexact, no special permission needed). Both schedule() and cancel() wrapped in try/catch to prevent future alarm crashes.
This commit is contained in:
1 parent
281a782b93
commit
fa8b101b34
1 file changed
+31
-12
@@ -4,6 +4,7 @@ import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import android.util.Log
|
||||
|
||||
@@ -13,21 +14,39 @@ object AlarmScheduler {
|
||||
private const val INTERVAL_MS = 2 * 60 * 1000L // 2 minutes
|
||||
|
||||
fun schedule(context: Context) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val pi = buildPendingIntent(context)
|
||||
alarmManager.cancel(pi)
|
||||
alarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + INTERVAL_MS,
|
||||
pi
|
||||
)
|
||||
Log.d(TAG, "scheduled: next check in ${INTERVAL_MS / 1000}s")
|
||||
try {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
val pi = buildPendingIntent(context)
|
||||
alarmManager.cancel(pi)
|
||||
val triggerAt = SystemClock.elapsedRealtime() + INTERVAL_MS
|
||||
|
||||
val canExact = Build.VERSION.SDK_INT < Build.VERSION_CODES.S ||
|
||||
alarmManager.canScheduleExactAlarms()
|
||||
|
||||
if (canExact) {
|
||||
alarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt, pi
|
||||
)
|
||||
Log.d(TAG, "scheduled (exact): next check in ${INTERVAL_MS / 1000}s")
|
||||
} else {
|
||||
alarmManager.setAndAllowWhileIdle(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt, pi
|
||||
)
|
||||
Log.d(TAG, "scheduled (inexact): next check in ${INTERVAL_MS / 1000}s")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "schedule failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun cancel(context: Context) {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.cancel(buildPendingIntent(context))
|
||||
Log.d(TAG, "cancelled")
|
||||
try {
|
||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
alarmManager.cancel(buildPendingIntent(context))
|
||||
Log.d(TAG, "cancelled")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "cancel failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPendingIntent(context: Context): PendingIntent {
|
||||
|
||||
Reference in new issue
Block a user