Android 8.0+通知欄(Notification)適配詳解,判斷通知權限是否打開,並跳轉至通知管理頁面

前不久因爲API26(Android 8.0)以上的設備無法顯示通知欄,所以網上查閱了比較多了資料,得出結論,API26以後引入了通知渠道這麼個東西,然後就寫了一篇問題對應的博文:Android 8.0通知欄(Notification)適配,在模擬上是完美運行,可是當我前兩天安裝到真機上測試時,咦?怎麼又無效了?然後我就想着,是不是通知權限沒打開?因爲模擬器上很多權限的控制和真機上差別很大,我打開設置一看,還真是!那麼本文就接着Android 8.0通知欄(Notification)適配作一個補充。

Android 10 真機測試效果:

在這裏插入圖片描述

判斷通知權限是否打開

一行代碼判斷

我們要打開通知 管理頁面 第一步當然是判斷 通知權限是否打開了? ,打開了我們就不需要跳轉到通知管理頁面了,沒打開我們才進行跳轉。

這裏我們用NotificationManagerCompat提供的 .areNotificationsEnabled() 方法來判斷通知權限是否打開,返回的是boolean值

NotificationManagerCompat.from(this).areNotificationsEnabled()

注意:這個方法只適用於API19(Android 4.4)以上,API19以下會直接返回true,當然我們不是特殊開發也可以忽略了,畢竟現在市場上低於 Android4.4 的手機恐怕不好找,而且貌似Android4.4以下的對權限這塊也沒有太嚴格~

areNotificationsEnabled() 的源碼(可忽略)

我們來看看 areNotificationsEnabled() 的源碼,源碼可以很清晰明朗地看到,API24以上直接調用 mNotificationManager.areNotificationsEnabled(); 方法,而 API19 -API 23 則是通過反射的方式來獲取,API 19 以下就直接返回 true 了

 /**
     * Returns whether notifications from the calling package are not blocked.
     */
    public boolean areNotificationsEnabled() {
        if (Build.VERSION.SDK_INT >= 24) {
            return mNotificationManager.areNotificationsEnabled();
        } else if (Build.VERSION.SDK_INT >= 19) {
            AppOpsManager appOps =
                    (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
            ApplicationInfo appInfo = mContext.getApplicationInfo();
            String pkg = mContext.getApplicationContext().getPackageName();
            int uid = appInfo.uid;
            try {
                Class<?> appOpsClass = Class.forName(AppOpsManager.class.getName());
                Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE,
                        Integer.TYPE, String.class);
                Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
                int value = (int) opPostNotificationValue.get(Integer.class);
                return ((int) checkOpNoThrowMethod.invoke(appOps, value, uid, pkg)
                        == AppOpsManager.MODE_ALLOWED);
            } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException
                    | InvocationTargetException | IllegalAccessException | RuntimeException e) {
                return true;
            }
        } else {
            return true;
        }
    }

跳轉到通知管理頁面

通知權限判斷完了當然是要根據判斷結果來進行跳轉了,上面我們可以知道 NotificationManagerCompat.from(this).areNotificationsEnabled() 是會返回 boolean 值的,true 代表權限已經打開,反之則沒有打開,這裏我們可以寫一個 if 語句根據返回結果來進行判斷,這裏直接給一個現成的方法吧

方法邏輯:
  • 首先判斷 通知權限是否打開
  • 如果判斷結果是:false(權限沒打開),再進行當前手機的 API 判斷
  • 通過判斷API,來調用不同的方法,實現跳轉到應用通知設置的頁面
private boolean intent(Context context) {//判斷應用的通知權限是否打開,返回Boolean值
        if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) {
            Intent localIntent = new Intent();
            //判斷API,跳轉到應用通知管理頁面
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0及以上
                localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
            } else (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//8.0以下
                localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
                localIntent.putExtra("app_package", context.getPackageName());
                localIntent.putExtra("app_uid", context.getApplicationInfo().uid);
            }
            context.startActivity(localIntent);
            return false;
        } 
        return true;
    }

補充

這裏補充一下 Android 8.0 +的 Notification通知欄消息 的使用,相對於以前也只是加了一個NotificationChannel通知渠道,想要詳細看的可以去我前一篇關於通知欄的博客:Android 8.0通知欄(Notification)適配

方法邏輯
  • 首先通過上面的 通知權限判斷 方法判斷通知權限是否打開
  • 打開了的話判斷當前手機的API,如果是在 26 (Android 8.0)以上則多實例化一個NotificationChannel對象,並傳入一個 ID(用戶不可見,要保證id的唯一性) 和一個 Name(用戶能看到) ,最後是一個通知的優先級,這裏我設置的 高(IMPORTANCE_HIGH)
  • 如果API 在 26 以下,我們則直接調用以前使用的方法即可,這樣就可以兼容上下API了
public void show(Context context, String title, String msg) {

    if (intent(context)) {
        NotificationManager manager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        Notification notification = null;
        if (Build.VERSION.SDK_INT >= 26) {//API26以上的方法
            NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
            notification = new Notification.Builder(context, "id")
                    .setContentTitle(title)
                    .setContentText(msg)
                    .setSmallIcon(R.mipmap.img_icon)
                    .build();
        } else {//API26以下
            notification = new Notification.Builder(context)
                    .setContentTitle(title)
                    .setContentText(msg)
                    .setSmallIcon(R.mipmap.img_icon)
                    .build();
        }
        manager.notify(1, notification);
    }

}

如果文章對你還算有點幫助,點個贊吧!

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章