Android 14应用更新后AlarmManager权限(SCHEDULE_EXACT_ALARM)异常求助
修复Android 14下BootCompletedReceiver中AlarmManager.setExact的SecurityException问题
问题核心
升级到Android 14后,在BootCompletedReceiver.onReceive中调用AlarmManager.setExact触发SecurityException,异常明确提示:Caller com.eup.faztaa needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms。这是因为Android 14对精确闹钟的权限管控进一步收紧。
异常信息
Exception : java.lang.SecurityException Remote stack trace at com.android.server.alarm.AlarmManagerService$5.set (AlarmManagerService.java:3240) at android.app.IAlarmManager$Stub.onTransact (IAlarmManager.java:262) at android.os.Binder.execTransactInternal (Binder.java:1405) at android.os.Binder.execTransact (Binder.java:1341) Caused by java.lang.SecurityException: Caller com.eup.faztaa needs to hold android.permission.SCHEDULE_EXACT_ALARM or android.permission.USE_EXACT_ALARM to set exact alarms. at android.os.Parcel.createExceptionOrNull (Parcel.java:3071) at android.os.Parcel.createException (Parcel.java:3055) at android.os.Parcel.readException (Parcel.java:3038) at android.os.Parcel.readException (Parcel.java:2980) at android.app.IAlarmManager$Stub$Proxy.set (IAlarmManager.java:487) at android.app.AlarmManager.setImpl (AlarmManager.java:1110) at android.app.AlarmManager.setImpl (AlarmManager.java:1070) at android.app.AlarmManager.setExact (AlarmManager.java:834) at com.eup.faztaa.receiver.BootCompletedReceiver.onReceive at android.app.ActivityThread.handleReceiver (ActivityThread.java:4975) Caused by android.os.RemoteException: Remote stack trace: at com.android.server.alarm.AlarmManagerService$5.set (AlarmManagerService.java:3240) at android.app.IAlarmManager$Stub.onTransact (IAlarmManager.java:262) at android.os.Binder.execTransactInternal (Binder.java:1405) at android.os.Binder.execTransact (Binder.java:1341)
修复方案
1. 声明权限(二选一)
在AndroidManifest.xml中添加对应权限:
- 大部分普通应用使用
SCHEDULE_EXACT_ALARM(需要用户手动授权):
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
- 仅闹钟、日历等核心时间类应用可申请
USE_EXACT_ALARM(需Google Play审核通过):
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
2. 检查并请求用户授权(针对SCHEDULE_EXACT_ALARM)
由于SCHEDULE_EXACT_ALARM是特殊权限,无法通过常规权限请求弹窗获取,需跳转到系统设置让用户开启:
// 在需要设置精确闹钟的地方先检查权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); if (!alarmManager.canScheduleExactAlarms()) { // 跳转到系统设置开启权限 Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM); intent.setData(Uri.parse("package:" + getPackageName())); // 若在Receiver中调用,需添加FLAG_ACTIVITY_NEW_TASK intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return; } } // 权限已开启,正常设置精确闹钟 alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
3. 替代方案:使用非精确闹钟(无需权限)
如果业务场景不需要毫秒级精确触发,建议改用非精确闹钟API,Android 14无需额外权限即可使用:
// 使用setAndAllowWhileIdle(低电量时也能触发,非精确) alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); // 或者使用重复非精确闹钟 alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, AlarmManager.INTERVAL_DAY, pendingIntent);
4. BootCompletedReceiver适配
在BootCompletedReceiver.onReceive中,先判断Android版本并检查权限,再执行闹钟设置逻辑,避免崩溃:
@Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); if (!alarmManager.canScheduleExactAlarms()) { Log.w("BootReceiver", "精确闹钟权限未授予,无法设置闹钟"); return; } } // 权限校验通过,设置闹钟 setExactAlarm(context); } } private void setExactAlarm(Context context) { long triggerAtMillis = System.currentTimeMillis() + 1000 * 60; // 1分钟后触发 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, YourAlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); }
内容的提问来源于stack exchange,提问作者Minh Tiến Đào
相关产品推荐
相关产品推荐

