Android M runtime permission sample
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
app
gradle/wrapper
.gitignore
README.md
build.gradle
gradle.properties
gradlew
gradlew.bat
settings.gradle

README.md

RuntimePermissionSample

Android M runtime permission sample

2016.11.17更新:

如果已经了解运行时权限的基本使用,可以直接参考这篇文章:Android M 权限最佳实践


以下为Android 6.0 运行时权限相关要点

1.新的权限机制

6.0开始将权限分为两类。

一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等。此类权限在应用安装时就被授予(同6.0之前)。

另一类是Dangerous Permission,一般是涉及到用户隐私的,在app使用时需要用户进行授权,比如读取sdcard、访问通讯录等。此类权限是分组的:

image

同一组的任何一个权限被授权了,其他权限也自动被授权。

3.11更新:所有需要申请的权限还是必须在AndroidManifest中声明,否则,即使同组一个权限被授权了,一个未在AndroidManifest中声明的权限授权还是会失败。

2.关于targetSdkVersion需要注意的

  • 若targetSdkVersion低于23,将使用旧有规则:用户在安装的时候不得不接受所有权限,安装后app就有了那些权限。不过用户依然可以在设置中取消已经同意的授权。
  • 若targetSdkVersion高于23,如果app在使用一些敏感权限的时候没有做运行时权限的代码处理,app会直接crash。

3.相关API以及使用步骤

假设我们的app有添加联系人的功能:

  1. 在AndroidManifest文件中添加需要的权限android.permission.WRITE_CONTACTS

  2. 在添加联系人的代码之前,检查权限

    int hasWriteContactsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
    	//申请授权
    	...
    	return;
    }
    //添加联系人
    insertDummyContact();

    ContextCompat.checkSelfPermission:用于检测某个权限是否已经被授予,返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED

  3. 申请授权

    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_WRITE_CONTACTS);

    ActivityCompat.requestPermissions:第一个参数是Context;第二个参数是需要申请的权限的字符串数组,很明显这里可以一次申请多个;第三个参数为requestCode,主要用于回调的时候检测。

  4. 处理申请回调。不论用户同意还是拒绝,activity的onRequestPermissionsResult都会被回调来通知结果。

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
       	switch (requestCode) {
            case REQUEST_CODE_WRITE_CONTACTS:
                // Permission Granted
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    insertDummyContact();
                }
                // Permission Denied
                else {
                    Toast.makeText(MainActivity.this, "WRITE_CONTACTS permission denied", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults):第一个参数requestCode不用说;第二个参数为申请的权限,例如Manifest.permission.WRITE_CONTACTS;第三个参数为申请结果。如果此次回调是一次申请多个权限的情况,那第二个参数和第三个参数为对应关系。

    至此权限申请的步骤走通,不过还有个API需要提下: ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission):该方法只有在用户在上一次已经拒绝过你的这个权限申请时返回true;其余情况例如用户勾选了"不再显示"时均返回false。这个API的目的主要用于给用户一个申请权限的解释,我们可以弹个对话框告知用户为什么需要这个权限,点击确定时再去申请权限。加入此方法的申请权限代码如下:

    int hasWriteContactsPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS);
    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
    	//该方法只有在用户在上一次已经拒绝过你的这个权限申请返回true;勾选了"不再显示"时返回false
    	//你需要给用户一个解释,为什么要授权
    	if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_CONTACTS)) {
    		showConfirmDialog("please accept WRITE_CONTACTS permission request.",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                            	ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_WRITE_CONTACTS);
                            }});
        	return;
        }
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_WRITE_CONTACTS);
        return;
    }
    insertDummyContact();

    如果用户勾选了“不再显示”拒绝后,再次申请权限时,在onRequestPermissionsResult回调方法中走权限拒绝的方法,如果用户又想开启此权限的话,我们可以通过shouldShowRequestPermissionRationale返回值判断是否勾选“不再显示”,是的话在回调方法判断权限拒绝的代码块中弹一个对话框告知用户:在设置-应用-权限管理中去开启。

    case REQUEST_CODE_WRITE_CONTACTS:
    	// Permission Granted
    	if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    		insertDummyContact();
    	}
    	// Permission Denied
    	else {
    		//若用户在拒绝权限时勾选了"不再显示",显示对话框提示用户
    		if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_CONTACTS)) {
    			showConfirmDialog("WRITE_CONTACTS permission denied, please enable it in Settings-Apps.", null);
    			return;
    		}
    		Toast.makeText(MainActivity.this, "WRITE_CONTACTS permission denied", Toast.LENGTH_SHORT).show();
    	}
    break;

4.第三方开源库

前两个使用了注解

5.参考博客

Android M 新的运行时权限开发者需要知道的一切

Android 6.0 运行时权限处理