Android运行时权限流程梳理

2,425 阅读3分钟

运行时权限的由来

  1. 旧有的权限机制:略;
  2. 新的机制:略;

三个核心方法

  1. checkSelfPermission

    1. 作用:检测用户是否授予了App权限。此方法只会检测危险权限,普通权限不会进行检测即便开发者将普通权限写进待申请权限的数组requestPermissions。如下MODIFY_AUDIO_SETTINGS是普通权限,此方法会跳过;

      private String[] requestPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.READ_SMS};
      
    2. 使用方法:

      1. context:第一个参数,上下文,做Android的朋友应该都知道;

      2. permission:危险权限;

      3. 多个危险权限时我是这么使用的,permissionsList是用来存储用户未授予的权限List集合;

        for (String requestPermission : requestPermissions) {
             if (ActivityCompat.checkSelfPermission(this, requestPermission) == PackageManager.PERMISSION_DENIED) {
                  permissionsList.add(requestPermission);
              }
        }
        
  2. requestPermissions

    1. 作用:请求权限。把用户未授予的危险权限在这里发起请求授予;

    2. 使用方法

      1. activity:申请权限所在的Activity;

      2. permissions:需要授权的危险权限集,即上面的permissionsList

      3. requestCode:略;

      4. 代码示例(permissionsList转为数组)

        ActivityCompat.requestPermissions(this, permissionsList.toArray(strings), 1);
        
  3. shouldShowRequestPermissionRationale

    1. 返回值:返回值类型为布尔值。当用户Allow了权限,就什么都不说了此方法没啥用了;当用户Deny了权限时返回true值;当用户Deny & don't ask again时返回false;
    2. 作用:当用户Deny & don't ask again时通过在App里面已经无法再次让用户授予权限了,但是如果此权限又是必须的,那么还可以在返回值为false里面再挣扎一下弹出弹窗让用户去App info里面设置,弹窗里面可以解释一下为什么需要此权限,增加用户同意的概率;

回调方法及参数意义

  1. onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    1. 作用:requestPermissions请求之后在这里处理结果;
    2. requestCode:请求码,和requestPermissions里面的一致即可;
    3. permissionsrequestPermissions请求的权限,无论同意或者拒绝的都在里面,和permissionsList里面的内容意义;
    4. grantResults:请求的所有权限结果,同意(0),拒绝(-1);

危险权限处理流程

  1. 当执行某项功能时先判断需要的危险权限checkSelfPermission
  2. 把未授予的再拿去请求requestPermissions
  3. 当用户点击了Deny & don't ask again时根据需要使用shouldShowRequestPermissionRationale的返回值进行处理;

我的示例代码

public class SecondActivity extends AppCompatActivity {

    //需要的危险权限
    private String[] requestPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.READ_SMS};
    //存放用户还未同意的危险权限,程序需要的是数组,但是集合操作更方便,下面使用时转为数组即可
    private List<String> permissionsList = new ArrayList<>();
    private AlertDialog alertDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        //一定要清空,不然用户反复拒绝几次之后,里面会重复添加
        permissionsList.clear();
        for (String requestPermission : requestPermissions) {
            if (ActivityCompat.checkSelfPermission(SecondActivity.this, requestPermission) == PackageManager.PERMISSION_DENIED) {
                permissionsList.add(requestPermission);
            }
        }
        //如果还有未赋予权限的,在这里请求
        if (!permissionsList.isEmpty()) {
            String[] strings = new String[permissionsList.size()];
            ActivityCompat.requestPermissions(SecondActivity.this, permissionsList.toArray(strings), 1);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                    //拒绝时返回true,拒绝且不再询问时返回false
                    if (ActivityCompat.shouldShowRequestPermissionRationale(SecondActivity.this, permissions[i])) {
                        //TODO do nothing
                    } else {
                        //如果时必须的权限,提醒去设置里面开启,程序自己已经无法处理了,如果无所谓则不需要处理
                        //TODO 可以做个弹窗,引导用户去App info里面打开权限
                    }
                }
            }
        }
    }
}