美文网首页代码片段安卓开发Android开发
Android 6.0 运行时权限简洁封装

Android 6.0 运行时权限简洁封装

作者: wo叫天然呆 | 来源:发表于2017-01-02 21:00 被阅读2704次

    Android 6.0 运行时权限简洁封装

    本文原创,转载请注明出处。欢迎关注我的 简书

    前言:

    9月份跳槽到一家创业公司,终于知道为什么干我们这一行的容易猝死...
    连续加班一个月,赶出了第一个项目,APP上线后发现权限忘记加了,又马上更新了个版本上去,后续又是新项目,又是功能迭代的,想说梳理下权限这块代码,也没时间动工,趁元旦在家,整理了下相关代码,写了这篇文章,希望对大家有所帮助。

    2017.01.03 对跳转设置返回做了进一步的完善,修改点如下:
    1.新增SETTINGS_REQUEST_CODE,mPermissionsList 参数
    2.showPermissionSettingDialog方法修改
    3.重写onActivityResult

    参考资料如下:

    Android Runtime Permissions
    Android 6.0 运行时权限处理完全解析
    MeloDev的Android 6.0 运行时权限简洁封装

    MeloDev的这篇文章跟我的想法不谋而合,不一样的地方是在于我加了个必要权限判断,开发中我们会发现,有些权限是必须获取到的,不然会影响到一部分的功能,如SD卡权限,当然,如果用户不允许开通此类权限,APP理论上来说还是要允许用户继续使用的,但是我们要在很多地方加入权限判断,很是麻烦,所以干脆流氓一点吧,添加一个必要权限判断,如果必要权限被拒绝了,先弹窗,告知用户去个人中心手动开启,如果不然,直接退出APP....

    整个世界都清净了!!!


    好了,现在来看看如何封装:

    我将运行时权限封装到 BaseActivity 中,BaseActivity 继承AppCompatActivity。
    注解都写得很详细了,直接上代码。

    回调接口:

    /**
     * Created by caihan on 2017/1/1.
     * 权限申请接口
     */
    
    public interface PermissionsResultListener {
        void onPermissionGranted();
    
        void onPermissionDenied();
    }
    

    BaseActivity里的权限代码:

    /**
     * Created by caihan on 2017/1/1.
     */
    public abstract class BaseActivity extends AppCompatActivity{
        private static final String TAG = "BaseActivity";
        protected Context mContext;
    
        // For Android 6.0
        private PermissionsResultListener mListener;
        //申请标记值
        public static final int REQUEST_CODE_ASK_PERMISSIONS = 100;
        //手动开启权限requestCode
        public static final int SETTINGS_REQUEST_CODE = 200;
        //拒绝权限后是否关闭界面或APP
        private boolean mNeedFinish = false;
        //界面传递过来的权限列表,用于二次申请
        private ArrayList<String> mPermissionsList = new ArrayList<>();
        //必要全选,如果这几个权限没通过的话,就无法使用APP
        protected static final ArrayList<String> FORCE_REQUIRE_PERMISSIONS = new ArrayList<String>() {
            {
                add(Manifest.permission.INTERNET);
                add(Manifest.permission.READ_EXTERNAL_STORAGE);
                add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                add(Manifest.permission.ACCESS_FINE_LOCATION);
                add(Manifest.permission.ACCESS_COARSE_LOCATION);
            }
        };
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            if (intent != null) {
                setIntent(intent);
                mContext = this;
            }
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //没actionbar
            supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
            //取消横屏
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            //输入法弹出的时候不顶起布局
            //如果我们不设置"adjust..."的属性,对于没有滚动控件的布局来说,采用的是adjustPan方式,
            // 而对于有滚动控件的布局,则是采用的adjustResize方式。
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
                    WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    //        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |
    //                WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
            mContext = this;
        }
    
        /**
         * 权限允许或拒绝对话框
         *
         * @param permissions 需要申请的权限
         * @param needFinish  如果必须的权限没有允许的话,是否需要finish当前 Activity
         * @param callback    回调对象
         */
        protected void requestPermission(final ArrayList<String> permissions, final boolean needFinish,
                                         final PermissionsResultListener callback) {
            if (permissions == null || permissions.size() == 0) {
                return;
            }
            mNeedFinish = needFinish;
            mListener = callback;
            mPermissionsList = permissions;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                //获取未通过的权限列表
                ArrayList<String> newPermissions = checkEachSelfPermission(permissions);
                if (newPermissions.size() > 0) {// 是否有未通过的权限
                    requestEachPermissions(newPermissions.toArray(new String[newPermissions.size()]));
                } else {// 权限已经都申请通过了
                    if (mListener != null) {
                        mListener.onPermissionGranted();
                    }
                }
            } else {
                if (mListener != null) {
                    mListener.onPermissionGranted();
                }
            }
        }
    
        /**
         * 申请权限前判断是否需要声明
         *
         * @param permissions
         */
        private void requestEachPermissions(String[] permissions) {
            if (shouldShowRequestPermissionRationale(permissions)) {// 需要再次声明
                showRationaleDialog(permissions);
            } else {
                ActivityCompat.requestPermissions(BaseActivity.this, permissions,
                        REQUEST_CODE_ASK_PERMISSIONS);
            }
        }
    
        /**
         * 弹出声明的 Dialog
         *
         * @param permissions
         */
        private void showRationaleDialog(final String[] permissions) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("提示")
                    .setMessage("为了应用可以正常使用,请您点击确认申请权限。")
                    .setPositiveButton("确认",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    ActivityCompat.requestPermissions(BaseActivity.this, permissions,
                                            REQUEST_CODE_ASK_PERMISSIONS);
                                }
                            })
                    .setNegativeButton("取消",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                    if (mNeedFinish) finish();
                                }
                            })
                    .setCancelable(false)
                    .show();
        }
    
        /**
         * 检察每个权限是否申请
         *
         * @param permissions
         * @return newPermissions.size > 0 表示有权限需要申请
         */
        private ArrayList<String> checkEachSelfPermission(ArrayList<String> permissions) {
            ArrayList<String> newPermissions = new ArrayList<String>();
            for (String permission : permissions) {
                if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                    newPermissions.add(permission);
                }
            }
            return newPermissions;
        }
    
        /**
         * 再次申请权限时,是否需要声明
         *
         * @param permissions
         * @return
         */
        private boolean shouldShowRequestPermissionRationale(String[] permissions) {
            for (String permission : permissions) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
                    return true;
                }
            }
            return false;
        }
    
        /**
         * 申请权限结果的回调
         *
         * @param requestCode
         * @param permissions
         * @param grantResults
         */
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                               @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == REQUEST_CODE_ASK_PERMISSIONS && permissions != null) {
                // 获取被拒绝的权限列表
                ArrayList<String> deniedPermissions = new ArrayList<>();
                for (String permission : permissions) {
                    if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                        deniedPermissions.add(permission);
                    }
                }
                // 判断被拒绝的权限中是否有包含必须具备的权限
                ArrayList<String> forceRequirePermissionsDenied =
                        checkForceRequirePermissionDenied(FORCE_REQUIRE_PERMISSIONS, deniedPermissions);
                if (forceRequirePermissionsDenied != null && forceRequirePermissionsDenied.size() > 0) {
                    // 必备的权限被拒绝,
                    if (mNeedFinish) {
                        showPermissionSettingDialog();
                    } else {
                        if (mListener != null) {
                            mListener.onPermissionDenied();
                        }
                    }
                } else {
                    // 不存在必备的权限被拒绝,可以进首页
                    if (mListener != null) {
                        mListener.onPermissionGranted();
                    }
                }
            }
        }
    
        /**
         * 检查回调结果
         *
         * @param grantResults
         * @return
         */
        private boolean checkEachPermissionsGranted(int[] grantResults) {
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
            return true;
        }
    
        private ArrayList<String> checkForceRequirePermissionDenied(
                ArrayList<String> forceRequirePermissions, ArrayList<String> deniedPermissions) {
            ArrayList<String> forceRequirePermissionsDenied = new ArrayList<>();
            if (forceRequirePermissions != null && forceRequirePermissions.size() > 0
                    && deniedPermissions != null && deniedPermissions.size() > 0) {
                for (String forceRequire : forceRequirePermissions) {
                    if (deniedPermissions.contains(forceRequire)) {
                        forceRequirePermissionsDenied.add(forceRequire);
                    }
                }
            }
            return forceRequirePermissionsDenied;
        }
    
        /**
         * 手动开启权限弹窗
         */
        private void showPermissionSettingDialog() {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("提示")
                    .setMessage("必要的权限被拒绝")
                    .setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            AppUtils.getAppDetailsSettings(BaseActivity.this, SETTINGS_REQUEST_CODE);
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            dialogInterface.dismiss();
                            if (mNeedFinish) AppUtils.restart(BaseActivity.this);
                        }
                    })
                    .setCancelable(false)
                    .show();
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            //如果需要跳转系统设置页后返回自动再次检查和执行业务 如果不需要则不需要重写onActivityResult
            if (requestCode == SETTINGS_REQUEST_CODE) {
                requestPermission(mPermissionsList, mNeedFinish, mListener);
            }
        }
    
    }
    

    跳转应用设置和关闭APP进程的代码:

        /**
         * 获取App具体设置
         *
         * @param context 上下文
         */
        public static void getAppDetailsSettings(Context context, int requestCode) {
            getAppDetailsSettings(context, context.getPackageName(), requestCode);
        }
    
        /**
         * 获取App具体设置
         *
         * @param context     上下文
         * @param packageName 包名
         */
        public static void getAppDetailsSettings(Context context, String packageName, int requestCode) {
            if (StringUtils.isSpace(packageName)) return;
            ((AppCompatActivity) context).startActivityForResult(
                    IntentUtils.getAppDetailsSettingsIntent(packageName), requestCode);
        }
    
        /**
         * 获取App具体设置的意图
         *
         * @param packageName 包名
         * @return intent
         */
        public static Intent getAppDetailsSettingsIntent(String packageName) {
            Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
            intent.setData(Uri.parse("package:" + packageName));
            return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
    
        /**
         * 通过任务管理器杀死进程
         * 需添加权限 {@code <uses-permission android:name="android.permission.RESTART_PACKAGES"/>}</p>
         *
         * @param context
         */
        public static void restart(Context context) {
            int currentVersion = android.os.Build.VERSION.SDK_INT;
            if (currentVersion > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
                Intent startMain = new Intent(Intent.ACTION_MAIN);
                startMain.addCategory(Intent.CATEGORY_HOME);
                startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(startMain);
                System.exit(0);
            } else {// android2.1
                ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
                am.restartPackage(context.getPackageName());
            }
        }
    

    界面上调用代码:
    这里我直接传了必要权限数列过去,因此如果有任何一个权限没通过,都会退出APP,
    如果你打算分场合请求权限的话,可以修改下我的代码,必要和非必要权限都从界面传递过来就可以了。

            requestPermission(FORCE_REQUIRE_PERMISSIONS, true, new PermissionsResultListener() {
                @Override
                public void onPermissionGranted() {
                    ToastUtils.showShortToast("已申请权限");
                }
    
                @Override
                public void onPermissionDenied() {
                    ToastUtils.showShortToast("拒绝申请权限");
                }
            });
    
    

    代码相对来说比较简单,我就不上传到GitHub了,如果大家有更好的封装方式的话,可以交流下。

    相关文章

      网友评论

      • 叁分钟热血:麻烦问一下,StringUtils.isSpace 和IntentUtils.getAppDetailsSettingsIntent 这两个Utils的方法,做了哪些操作?
        叁分钟热血:@wo叫天然呆 好的,谢啦
        wo叫天然呆:@YT_卓安 http://www.jianshu.com/p/72494773aace 我引入了这个工具类,你可以自己到里面看看具体方法
      • itchenqi188:学习了
      • 冥冥丶:IntentUtils 是啥意思。
        冥冥丶:@wo叫天然呆 大神啊。。佩服 ,,搞定了。。那个类名取消了
        wo叫天然呆:@冥冥中 只是一个类名
      • MeloDev:直接大段地复制我的代码吗:worried:
        wo叫天然呆:既然你已经写完了,我这边又何必重复造轮子呢..直接把你的搬过来用,加上我自己的理解就行啦
      • uncochen:存储这种基础不授权就应该退出,跟我的想法一致
      • _deadline:不授权就退出有点暴力
        _deadline: @wo叫天然呆 万恶的老板,哈哈
        wo叫天然呆:@_deadline 确实是,不过这个要看老板的意思了,老板高兴就好:joy:
      • wo叫天然呆:2017.01.03 对跳转设置返回做了进一步的完善,修改点如下:
        1.新增SETTINGS_REQUEST_CODE,mPermissionsList 参数
        2.showPermissionSettingDialog方法修改
        3.重写onActivityResult

      本文标题:Android 6.0 运行时权限简洁封装

      本文链接:https://www.haomeiwen.com/subject/aqtgvttx.html