Android 12中PendingIntent.FLAG_UPDATE_CURRENT报错及相关疑问
Android 12+ AlarmManager 报错解决方案与疑问解答
问题背景
使用AlarmManager实现每日特定时间闹钟时,Android 12以下设备正常运行,但Android 12及以上设备触发报错,Firebase Crashlytics报错信息如下:
Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable
原实现代码
Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 15); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); Calendar cur = Calendar.getInstance(); if (cur.after(calendar)) { calendar.add(Calendar.DATE, 1); } Intent myIntent = new Intent(mCon, DailyReminder.class); int ALARM1_ID = 10000; PendingIntent pendingIntent= PendingIntent.getBroadcast(mCon, ALARM1_ID, myIntent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) mCon.getSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
找到的解决方案
PendingIntent pendingIntent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingIntent= PendingIntent.getBroadcast(mCon, ALARM1_ID, myIntent, PendingIntent.FLAG_IMMUTABLE); } else { pendingIntent = PendingIntent.getBroadcast(mCon, ALARM1_ID, myIntent, PendingIntent.FLAG_UPDATE_CURRENT); }
疑问解答
1. PendingIntent.FLAG_UPDATE_CURRENT 与 PendingIntent.FLAG_IMMUTABLE 的区别是什么?
- FLAG_UPDATE_CURRENT:核心作用是更新已存在的PendingIntent内的Intent内容。如果系统中已经存在匹配的PendingIntent(相同上下文、requestCode、Intent过滤规则),调用
getBroadcast时会把原PendingIntent里的Intent替换成新传入的,同时保留PendingIntent引用,确保后续触发时用的是最新的Intent数据。这是Android 12之前常用的标记,用来保证Intent携带的信息是最新的。 - FLAG_IMMUTABLE:Android 12(API 31)新增的安全标记,标记PendingIntent为不可变状态。一旦创建完成,该PendingIntent内的Intent内容无法被修改,第三方应用也不能篡改它。系统强烈推荐优先用这个标记,能降低恶意应用篡改Intent的安全风险。
注意:这两个标记可以组合使用(如PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE),既可以更新Intent内容,又能保证PendingIntent的不可变性,这也是Android 12+的更优写法。
2. 每次用户启动应用时调用该闹钟设置方法是否可行?会创建新闹钟还是更新已有闹钟?
完全可行,且不会创建新闹钟,而是更新已有的闹钟:
- 因为你用了固定的
ALARM1_ID(10000),且Intent的目标组件是DailyReminder.class,系统会根据上下文、requestCode和Intent的匹配规则判断是否存在已有的PendingIntent。如果存在,会复用该PendingIntent(若用了FLAG_UPDATE_CURRENT或组合标记,会同步更新Intent内容)。 - 调用
alarmManager.setRepeating时,系统会检测是否存在同ID的重复闹钟,若存在则直接更新闹钟的触发时间和重复规则,不会生成新的闹钟实例。 - 这种做法的好处是:确保每次应用启动时,闹钟都是激活状态(避免系统重启、应用被清理导致闹钟失效);如果后续允许用户修改闹钟时间,启动时调用也能同步更新到最新设置的时间。
内容的提问来源于stack exchange,提问作者Supun Ayeshmantha
相关产品推荐
相关产品推荐

