在版本 S 中创建通知时 Android 应用程序崩溃
我已经在我的应用程序中使用通知有一段时间了,一切都工作正常,直到我最近瞄准了 android 12。现在,当我在 android 12 上收到通知时,我的应用程序崩溃了。但在低于 android 12 的设备上一切工作正常。这是我到目前为止所尝试过的。
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String CHANNEL_ID = "1";
private static final String CHANNEL_NAME = "Notifications";
@Override
public void onReceive(Context context, Intent intent) {
// For android 8 and above
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(context.getString(R.string.notifications));
channel.enableLights(true);
channel.enableVibration(true);
channel.setLightColor(Color.RED);
channel.setShowBadge(true);
channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC); //Show notification on lock screen
NotificationManager manager = context.getSystemService(NotificationManager.class);
assert manager != null;
manager.createNotificationChannel(channel);
}
Cursor cursor = new DatabaseHelper(context).generateNotification();
if (cursor.moveToFirst()) {
// Create an Intent for the activity you want to start
Intent newIntent = new Intent(context, MainActivity.class);
newIntent.putExtra(Constants.STRING_EXTRA_INCOMING_ACTIVITY, Constants.ACTIVITY_NOTIFICATION);
newIntent.putExtra(Constants.STRING_EXTRA_QUOTE, cursor.getString(1));
// on back pressed go back to main activity
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(newIntent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Build Notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setColor(Color.parseColor("#ffa000"))
.setContentTitle(context.getString(R.string.notifications))
.setContentText(Html.fromHtml(cursor.getString(1)))//builds the title from columns of the selected row
.setContentIntent(pendingIntent) // On Notification Click Goto DetailActivity
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(1, mBuilder.build());
} else {
Toast.makeText(context, "Unable To Generate Notification", Toast.LENGTH_LONG).show();
}
cursor.close();
}
}
这是在我的 MainActivity 中显示通知的代码
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,
0, intent, PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 10);
if (now.after(calendar)) {
calendar.add(Calendar.DATE, 1);
}
if (alarms != null) {
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
这是我在 firebase 上收到的崩溃报告
Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.example.app.receiver.AlarmReceiver: java.lang.IllegalArgumentException: com.example.app: 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.
at android.app.ActivityThread.handleReceiver(ActivityThread.java:4766)
at android.app.ActivityThread.access$1800(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2288)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8611)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
Caused by java.lang.IllegalArgumentException: com.example.app: 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.
at android.app.PendingIntent.checkFlags(PendingIntent.java:382)
at android.app.PendingIntent.getActivitiesAsUser(PendingIntent.java:616)
at android.app.PendingIntent.getActivities(PendingIntent.java:598)
at androidx.core.app.TaskStackBuilder.getPendingIntent(TaskStackBuilder.java:341)
at androidx.core.app.TaskStackBuilder.getPendingIntent(TaskStackBuilder.java:312)
at com.example.app.receiver.AlarmReceiver.onReceive(AlarmReceiver.java:58)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:4757)
at android.app.ActivityThread.access$1800(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2288)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8611)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
I have been using notifications in my app for a while now and everything was working fine until i recently targeted android 12. Now my app is crashing when i get notifications on android 12. But everything is working fine on below android 12 devices. Here is what i have tried so far.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String CHANNEL_ID = "1";
private static final String CHANNEL_NAME = "Notifications";
@Override
public void onReceive(Context context, Intent intent) {
// For android 8 and above
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(context.getString(R.string.notifications));
channel.enableLights(true);
channel.enableVibration(true);
channel.setLightColor(Color.RED);
channel.setShowBadge(true);
channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC); //Show notification on lock screen
NotificationManager manager = context.getSystemService(NotificationManager.class);
assert manager != null;
manager.createNotificationChannel(channel);
}
Cursor cursor = new DatabaseHelper(context).generateNotification();
if (cursor.moveToFirst()) {
// Create an Intent for the activity you want to start
Intent newIntent = new Intent(context, MainActivity.class);
newIntent.putExtra(Constants.STRING_EXTRA_INCOMING_ACTIVITY, Constants.ACTIVITY_NOTIFICATION);
newIntent.putExtra(Constants.STRING_EXTRA_QUOTE, cursor.getString(1));
// on back pressed go back to main activity
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(newIntent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Build Notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setColor(Color.parseColor("#ffa000"))
.setContentTitle(context.getString(R.string.notifications))
.setContentText(Html.fromHtml(cursor.getString(1)))//builds the title from columns of the selected row
.setContentIntent(pendingIntent) // On Notification Click Goto DetailActivity
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(1, mBuilder.build());
} else {
Toast.makeText(context, "Unable To Generate Notification", Toast.LENGTH_LONG).show();
}
cursor.close();
}
}
And here is the code to show notifications in my MainActivity
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,
0, intent, PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 10);
if (now.after(calendar)) {
calendar.add(Calendar.DATE, 1);
}
if (alarms != null) {
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
And here are the crash reports I'm getting on firebase
Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.example.app.receiver.AlarmReceiver: java.lang.IllegalArgumentException: com.example.app: 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.
at android.app.ActivityThread.handleReceiver(ActivityThread.java:4766)
at android.app.ActivityThread.access$1800(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2288)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8611)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
Caused by java.lang.IllegalArgumentException: com.example.app: 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.
at android.app.PendingIntent.checkFlags(PendingIntent.java:382)
at android.app.PendingIntent.getActivitiesAsUser(PendingIntent.java:616)
at android.app.PendingIntent.getActivities(PendingIntent.java:598)
at androidx.core.app.TaskStackBuilder.getPendingIntent(TaskStackBuilder.java:341)
at androidx.core.app.TaskStackBuilder.getPendingIntent(TaskStackBuilder.java:312)
at com.example.app.receiver.AlarmReceiver.onReceive(AlarmReceiver.java:58)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:4757)
at android.app.ActivityThread.access$1800(ActivityThread.java:310)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2288)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8611)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据官方文档“如果您的应用面向 Android 12,则必须指定您的应用创建的每个 PendingIntent 对象的可变性。此附加要求可提高应用的安全性。”
我们正在构建一个标准类型的 Intent 将打开我们的应用程序,然后简单地将其包装在 PendingIntent 中,然后将其添加到我们的通知中。在这种情况下,由于我们知道我们想要执行一个确切的操作,因此我们构造了一个不能执行的 PendingIntent由我们通过使用名为 FLAG_IMMUTABLE 的标志传递给它的应用程序进行修改。
As per the official doc "If your app targets Android 12, you must specify the mutability of each PendingIntent object that your app creates. This additional requirement improves your app's security."
we’re constructing a standard type of Intent that will open our app, and then simply wrapping that in a PendingIntent before adding it to our notification.In this case, since we have an exact action we know we want to perform, we construct a PendingIntent that cannot be modified by the app we pass it to by utilizing a flag called FLAG_IMMUTABLE.