Android运行时权限,6.0—9.0多版本,多终端(手机,TV盒子)130行代码一劳永逸

Android在API 23之后开启了危险权限动态申请的机制,具体有哪些权限这里不做赘述,只拿笔者在手机和TV端开发中用到的权限例举,示例Demo并没有依赖任何的第三方库,纯Android代码,大约130行左右。
Android运行时权限,6.0—9.0多版本,多终端(手机,TV盒子)130行代码一劳永逸_第1张图片

1.新建一个用于检查权限的Activity,定义申请权限数组和请求码,在onCreate中进行权限检查,将没有授权的权限添加到待申请列表。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        ArrayList<String> needGetList = null;
        for (String permission : mPermissions) {
//            检查是否已经授权
            if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_DENIED) {
                if (needGetList == null){
                    needGetList = new ArrayList<>();
                }
                //没有授权,添加到待申请列表
                needGetList.add(permission);
            }
        }
        
        // 进行申请动作
        actionPermission(needGetList, needGetList == null ? true : false);

    }

2.根据待申请集合和结果进行申请动作

    private void actionPermission(ArrayList<String> needGetList, boolean result){
        //  有需要申请的权限
        if (needGetList != null && needGetList.size() > 0){
            System.out.println(needGetList.toString());

            String[] arrays = new String[needGetList.size()];
            for (int i = 0; i < needGetList.size(); i++) {
                arrays[i] = needGetList.get(i);
            }
            ActivityCompat.requestPermissions(this, arrays, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
        }else {
            if (result){
                // 授权成功
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(this, "授权失败,您可之后到系统应用管理页面进行手动授权", Toast.LENGTH_SHORT).show();
            }
            startActivity(new Intent(this, HomeActivity.class));
            finish();
        }
    }

3.重写onRequestPermissionsResult方法获取申请的结果

返回的permissions是所有发起申请的权限,grantResults是对应的申请结果,下标是一一对应的。判断grantResults的结果是不是PackageManager.PERMISSION_DENIED(被拒绝),如果有被拒绝的权限弹出对话框提示,如果没有则关闭页面。

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
                ArrayList<String> denied = new ArrayList<>();
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] == PackageManager.PERMISSION_DENIED){
                        denied.add(permissions[i]);
                    }
                }
                if (denied.size() > 0 ){
                // 有未申请到得权限 需要弹框提醒
                    showRationaleDialog(denied);
                }else {
//                    申请到所有权限  跳转页面
                    actionPermission(null, true);
                }

            }
        }
    }

4.弹出对话框提示用户是否继续授权

点击继续授权跳转到系统应用管理中本应用的详情页面进行开启,点击取消提示用户授权失败并关闭页面(如遇必须权限可以提示用户不授权无法使用)
注:手机端打开详情页面没有问题,但部分TV盒子将应用详情给砍掉了,会打开失败。

    /**
     * 弹出提示语
     *
     */
    private void showRationaleDialog(final ArrayList<String> denied) {

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        TextView mMsg = new TextView(this);
        mMsg.setText("您还有权限未授权完毕,将导致应用无法正常使用,是否跳转到系统设置界面继续授权?");
        mMsg.setGravity(Gravity.CENTER_HORIZONTAL);
        mMsg.setTextSize(18);
        builder.setView(mMsg);
        builder.setCancelable(false);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                try{
//                    打开系统 本应用的详情页面
                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    intent.setData(Uri.fromParts("package", BeforeActivity.this.getPackageName(), null));
                    BeforeActivity.this.startActivity(intent);
                }catch (Exception e){
                    Log.e(TAG, "打开当前本应用设置界面失败: " + e.getMessage());
                    try{
//                        打开系统已安装应用页面
                        BeforeActivity.this.startActivity(new Intent(Settings.ACTION_APPLICATION_SETTINGS));
                    }catch (Exception e2){
                        Log.e(TAG, "打开应用设置界面失败: " + e.getMessage());
                        Toast.makeText(BeforeActivity.this, "打开应用设置界面失败", Toast.LENGTH_SHORT).show();
//                        如果都打开失败  提示用户手动之后手动开启权限  并关闭页面
                        actionPermission(null, false);
                    }
                }
                toAppDetail = true;
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
                actionPermission(null, false);
            }
        });
        Dialog tipDialog = builder.create();
        tipDialog.setCanceledOnTouchOutside(false);
        tipDialog.show();

    }

5.从系统的应用详情页返回后

这里用的是重写onStart方法根据标志位来做的判断,页面重新可见后再次检查权限是否已经都可用,权限都可用就关闭页面,如果依然有未开启的权限则提示用户。

    @Override
    protected void onStart() {
        super.onStart();
        if (toAppDetail){
            toAppDetail = false;
            for (String permission : mPermissions) {
//            检查是否已经授权
                if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_DENIED) {
                    actionPermission(null, false);
                    return;
                }
            }
            actionPermission(null, true);
        }
    }

整体流程就是这样,经过测试目前在华为、荣耀、小米、vivo手机上都可以实现权限的动态申请,另外TV端在小米、天猫、当贝部分盒子上也可以实现动态获取。
Demo详情地址:https://github.com/TheTangEmperor/permissiondemo.git

你可能感兴趣的:(android,android,移动开发,app,java,android,studio)