Android推送通知權限判斷及跳轉到權限設置界面(完善兼容8.0)

有時候產品要求增加一個推送通知的開關(有些還要求具體到哪些通知,比如廣告類? 比如重大熱點等?)。

我們首先想到的肯定就是再推送回調接口里面判斷開啟的狀態(tài),進而進行過濾!沒錯,如果對于關閉通知肯定沒問題。但是對于開啟通知有個問題?就是即使你開啟了這個狀態(tài)值,但是如果系統(tǒng)關閉了該應用的通知權限,那么你開啟了其實也沒有用對吧?

所以正常的邏輯是:

1. 如果關閉,則不用判斷權限,直接關閉就行

2. 如果開啟,首先判斷是否有通知權限,如果有則走關閉邏輯就行;如果沒有,則把開關狀態(tài)重置回來,然后申請通知權限 - 通知權限開啟后再次開啟就沒有問題了

**a> **直接給判斷權限的工具類:

    public class NotificationsUtils {
    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static boolean isNotificationEnabled(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ///< 8.0手機以上
            if (((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).getImportance() == NotificationManager.IMPORTANCE_NONE) {
                return false;
            }
        }

        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        ApplicationInfo appInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = appInfo.uid;

        Class appOpsClass = null;
        try {
            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 = (Integer) opPostNotificationValue.get(Integer.class);
            return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}

b> 跳轉到通知設置的界面(自己做了下完善和測試)

    /**
     * 通知權限申請
     * @param context
     */
    public static void requestNotify(Context context) {
        /**
         * 跳到通知欄設置界面
         * @param context
         */
        Intent localIntent = new Intent();
        ///< 直接跳轉到應用通知設置的代碼
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            localIntent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
            localIntent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
        }
        else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
            android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            localIntent.putExtra("app_package", context.getPackageName());
            localIntent.putExtra("app_uid", context.getApplicationInfo().uid);
        } else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
            localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            localIntent.addCategory(Intent.CATEGORY_DEFAULT);
            localIntent.setData(Uri.parse("package:" + context.getPackageName()));
        } else {
            ///< 4.4以下沒有從app跳轉到應用通知設置頁面的Action,可考慮跳轉到應用詳情頁面,
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (Build.VERSION.SDK_INT >= 9) {
                localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
            } else if (Build.VERSION.SDK_INT <= 8) {
                localIntent.setAction(Intent.ACTION_VIEW);
                localIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
                localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
            }
        }
        context.startActivity(localIntent);
    }

啊哈?。∧壳熬褪轻u紫,這個應該有官方的吧,我找找看...有相關類的說明,但是具體的案例沒有。不過有具體的一些個解釋:

比如:Settings | Android Developers

image

再比如判斷的方式:

ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED
Intent that is broadcast when a NotificationChannel is blocked 
(when NotificationChannel.getImportance() is IMPORTANCE_NONE) or 
unblocked (when NotificationChannel.getImportance() is anything other than IMPORTANCE_NONE).

意思就是說:當一個NotificationChannel 被阻塞時,這個getImportance()的值就是IMPORTANCE_NONE,其他情況則不是。所以8.0也就可以根據這個狀態(tài)來做判斷.8.0以下的話采用的是反射的方式 - 這個具體的大家可以研究一下。小白暫時不研究了,先做個記錄和簡單學習。

最后使用邏輯:Switch控件(selector_thumb, selector_track就是slector,里面就是一些個shape文件...)

   <Switch
            android:id="@+id/ass_pushSt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="true"
            android:switchMinWidth="40dp"
            android:text=""
            android:textOff=" "
            android:textOn="  "
            android:thumb="@drawable/selector_thumb"
            android:track="@drawable/selector_track"
            app:layout_constraintEnd_toEndOf="parent" />   
   pushSt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if (b){
                    if (!NotificationsUtils.isNotificationEnabled(MineSystemSettingActivity.this)){
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                pushSt.setChecked(false);
                            }
                        });
                        PermissionTool.requestNotify(MineSystemSettingActivity.this);
                        return;
                    }
                }
                UserInfoControlPresenter.setPushStatus(!b);
            }
        });

剩下的你可以測測了喲...小寶貝...

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容