且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Android 9.0 NotificationManager.notify() 抛出 java.lang.SecurityException

更新时间:2022-01-26 22:03:21

与其说是解决方案,不如说是一个漫长而复杂的解决方法.

Not so much a solution as a long complicated workaround.

首先,我捕获通知抛出的 SecurityException 并设置共享首选项标志

First, I catch the SecurityException that is thrown by the notification and set a shared preference flag

try {
  myNM.notify(NOTIFICATION_ALERT, n);
} catch (SecurityException ex) {
  Log.e(ex);
  ManagePreferences.setNotifyAbort(true);
  return;
}

当应用程序启动时,它会检查这个标志并设置它,提示用户授予 READ_EXTERNAL_PERMISSION.不包括代码,因为它是将权限与不同首选项设置相关联的复杂系统的一部分,仅在授予所需权限时才允许某些设置,如果未授予权限,则更改它.

When the app starts up it checks this flag and it is set, prompts the user to grant the READ_EXTERNAL_PERMISSION. Not including the code because it is part of a complicated system that ties permissions to different preference settings, only allowing certain settings if a required permission is granted and changing it if the permission is not granted.

这有帮助,但我们仍然意味着用户不会在第一次需要生成警报时收到通知.为了解决这个问题,我们在启动初始化中添加了一些东西,以检查是否可能存在问题,如果存在,则生成常规通知并立即取消它.

That helps, but we still means the user will not get notified the first time an alert needs to be generated. To address that, we add something to are startup initialization that checks to see if there might be a problem, and if there is, generates a regular notification and immediately cancels it.

if (audioAlert && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
  if (! ManagePreferences.notifyCheckAbort() &&
      ! PermissionManager.isGranted(context, PermissionManager.READ_EXTERNAL_STORAGE)) {
    Log.v("Checking Notification Security");
    ManagePreferences.setNotifyCheckAbort(true);
    ManageNotification.show(context, null, false, false);
    NotificationManager myNM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    assert myNM != null;
    myNM.cancel(NOTIFICATION_ALERT);
  }
}

越来越近了.但是,如果在用户升级到 Android 9 之后但在打开应用程序之前发生警报通知,我们仍然会错过警报通知.为了解决这个问题,我编写了一个广播接收器,用于侦听 android.intent.action.MY_PACKAGE_REPLACED 和 android.intent.action.BOOT_COMPLETED 每次我的应用程序升级或 Android 系统升级时都会调用它们.这个接收器没有做任何特别的事情.但它存在的事实意味着我的应用程序启动并通过初始化逻辑.它检测到用户需要 READ_EXTERNAL_STORAGE 权限并提示他们.

Getting closer. But we still miss an alert notification if it happens after the user upgrades to Android 9 but before they open the app. To address that, I wrote a broadcast receiver that listens for android.intent.action.MY_PACKAGE_REPLACED and android.intent.action.BOOT_COMPLETED which gets called every time my app is upgraded, or the Android system is upgraded. This receiver does not do anything special. But the fact that it exists means that my app gets started up and goes through the initialization logic. Which detects that the user needs the READ_EXTERNAL_STORAGE permission and prompts them for it.