关于Android动态权限的一些疑问

Android 6.0开始,对敏感权限需要动态申请,首先我们需要引入android.support.v4的兼容包,然后使用ActivityCompat这个类来处理权限。

比如最常用的

ActivityCompat.checkSelfPermission(...)
ActivityCompat.requestPermissions(...)
ActivityCompat.shouldShowRequestPermissionRationale(...)

第一个是检查某个权限是否授权
第二个是申请权限
第三个是判断是否需要合理显示授权对话框。具体含义参考文末。

Activity也有这些方法,为什么要使用ActivityCompat来检查权限和申请权限?

有两个原因
第一,如果应用的minSdkVersion小于23,那么IDE会提示你这些方法在6.0以下不存在,编译会不通过。
第二,ActivityCompat处理了一些兼容性判断,比如requestPermissions的实现里加了判断api 23。

Android 23以下如何检查权限呢?

一种方法是使用ActivityCompat或ContextCompat,调用checkSelfPermission方法。
另一种方法使用Activity提供的方法:checkPermission(String permission, int pid, int uid),需要传入当前进程id和uid。

checkSelfPermission方法其实也是调用checkPermission(String permission, int pid, int uid)。

动态权限示例代码:

package com.devnn.testdemo;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.widget.Toast;

public class MainActivity extends Activity {
    String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{permission}, 100);
        }else{
            Toast.makeText(this, "已有读SDK卡权限", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==100){
            if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
            }else if(ActivityCompat.shouldShowRequestPermissionRationale(this,permission)==false){
                Toast.makeText(this, "拒绝并勾选了不再提醒,不会弹了,需要引导用户去设置页", Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(this, "拒绝了授权,下次还会再弹", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

记得先要在AndroidManifest.xml里声明权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

在弹出系统的权限对话框前,弹出自已的对话框,用来说明权限用途,会更加友好一点。直接使用Materia风格的Dialog。

    public void showPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this, android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth);
        builder.setMessage("需要读SD卡权限,用来获取照片\n需要获取手机状态权限,用来获取设备号\n需要获取联系人权限,用来...");
        builder.setTitle("权限说明");
        builder.setCancelable(true);
        builder.setPositiveButton("申请", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, 100);
            }
        });
        builder.show();
    }

对话框效果:
关于Android动态权限的一些疑问_第1张图片

只有危险权限(或叫敏感权限)才需要申请,而且危险权限组中的某一个权限授权了,组内其它权限也被同时授权。

危险权限组:
关于Android动态权限的一些疑问_第2张图片

关于 ActivityCompat.shouldShowRequestPermissionRationale(...)方法的含义,有必要说明。从字面意思理解,即是否需要合理显示申请权限对话框,那么什么时候显示才是合理的呢?我们发现以下规律。

在第一次申请权限时,它返回了false
用户选择拒绝并没有勾选不再提醒时,它返回true
而用户选择拒绝并勾选不再提醒(永久拒绝),它返回了false

因此这个方法并不能用来判断是否需要显示自已的权限说明对话框。它只能在权限回调里用来判断是否要引导用户到设置页打开权限。

你可能感兴趣的:(Android动态权限,Android)