Android推送通知权限判断及跳转到权限设置界面(完善兼容8.0)

有时候产品要求增加一个推送通知的开关(有些还要求具体到哪些通知,比如广告类? 比如重大热点等?)。

我们首先想到的肯定就是再推送回调接口里面判断开启的状态,进而进行过滤!没错,如果对于关闭通知肯定没问题。但是对于开启通知有个问题?就是即使你开启了这个状态值,但是如果系统关闭了该应用的通知权限,那么你开启了其实也没有用对吧?

所以正常的逻辑是:

1. 如果关闭,则不用判断权限,直接关闭就行

2. 如果开启,首先判断是否有通知权限,如果有则走关闭逻辑就行;如果没有,则把开关状态重置回来,然后申请通知权限 - 通知权限开启后再次开启就没有问题了

**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);
    }

啊哈!!目前就是酱紫,这个应该有官方的吧,我找找看...有相关类的说明,但是具体的案例没有。不过有具体的一些个解释:

比如: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也就可以根据这个状态来做判断.8.0以下的话采用的是反射的方式 - 这个具体的大家可以研究一下。小白暂时不研究了,先做个记录和简单学习。

最后使用逻辑:Switch控件(selector_thumb, selector_track就是slector,里面就是一些个shape文件...)

      
   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);
            }
        });

剩下的你可以测测了哟...小宝贝...

你可能感兴趣的:(Android推送通知权限判断及跳转到权限设置界面(完善兼容8.0))