最近将 Android 项目的 targetSdk 的版本号由 30 升到了 31,在真机(系统版本>=12)上运行的过程中报出了如下错误:
java.lang.IllegalArgumentException: <...your package examp...>: 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, e.g. if it needs to be used with inline replies or bubbles.
查看报错日志,最后定位到一处报错的代码:
PendingIntent pi_pr = PendingIntent.getBroadcast(this, 101, intent_pre, 0);
笔者定义了一个 PendingIntent,最终生成一个Notification. 报错是因为上面的方法,第四个参数(int flags)传了一个 0 值。
以下是对SDK文档对参数 flags 的解释:
flags – May be FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, FLAG_IMMUTABLE or any of the flags as supported by Intent.fillIn() to control which unspecified parts of the intent that can be supplied when the actual send happens.
通常这个值为上面注释里面提到的这些值<FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, FLAG_IMMUTABLE>,这里笔者传入 0 表示不使用 flags 进行创建PendingIntent时的控制。
以下节选的是部分 SDK 文档对 flags 值的解释:
Starting with Build.VERSION_CODES.S, it will be required to explicitly specify the mutability of PendingIntents on creation with either (@link #FLAG_IMMUTABLE} or FLAG_MUTABLE. It is strongly recommended to use FLAG_IMMUTABLE when creating a PendingIntent. FLAG_MUTABLE should only be used when some functionality relies on modifying the underlying intent, e.g. any PendingIntent that needs to be used with inline reply or bubbles.
上面这段话的意思是说,从版本Build.VERSION_CODES.S(31)开始,flags 值必须显式的声明为 FLAG_IMMUTABLE 或 FLAG_MUTABLE,但是通常是建议设置为 FLAG_IMMUTABLE。
所以从报错提示信息以及上面注释内容,可以得到的解决方案是:
方式一:将该值设置为:FLAG_IMMUTABLE 即可。
PendingIntent pi_pr = PendingIntent.getBroadcast(this, 101, intent_pre, PendingIntent.FLAG_IMMUTABLE);
如果你想保留之前旧版本的实现,可以对版本进行判断然后分别处理:
PendingIntent pendingIntent;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
pendingIntent = PendingIntent.getActivity(this, 100, intent, PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getActivity(this, 100, intent, PendingIntent.FLAG_ONE_SHOT);
}
方式二:将项目的 targetSdk 降到 31 以下。
其他参考内容:
1. Android中PendingIntent的使用
https://blog.csdn.net/xiaokangss/article/details/133364589
2. 构造PendingIntent时第四个参数flags的设置以及在Notification中的不同作用
https://blog.csdn.net/piglite/article/details/46581789