changjiashuai's blog

Runnig...

The future belongs to those who believe in the beauty of their dreams.


Android 6.0运行时权限理解

Android6.0运行时权限 思维导图

如果设备运行在5.1或者以下的设备,或者targetSdkVersion在22或以下,系统会在安装app的时候让用户授权权限。再说一遍,系统只会提示用户app需要的权限组,而不会提示某一个特定的权限。

  1. 检测权限

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M //6.0及以上


//current activity
int checkPermission = ContextCompat
	.checkSelfPermission(activity,Manifest.permission.WRITE_CALENDAR);
  1. 请求权限
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    //判断是否需要 向用户解释,为什么要申请该权限
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // 是否需要弹出一个解释申请该权限的提示给用户,如果为true,则可以弹

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                REQUEST_PERMISSIONS_READ_CONTACTS_CODE);

    }
}
  1. 处理请求权限结果
@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case REQUEST_PERMISSIONS_READ_CONTACTS_CODE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 授权成功
                ...
            } else {
					// 权限拒绝
					...
		 		 }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

SYSTEM_ALERT_WINDOW

if (!Settings.canDrawOverlays(this)) {
     Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
     startActivityForResult(intent,1);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1) {
        if (!Settings.canDrawOverlays(this)) {
            // SYSTEM_ALERT_WINDOW permission not granted...
            Toast.makeText(this,"not granted",Toast.LENGTH_SHORT);
        }
    }
}

WRITE_SETTINGs

if(!Settings.System.canWrite(this)){
     Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
             Uri.parse("package:" + getPackageName()));
     startActivityForResult(intent, REQUEST_CODE);
}


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE) {
       if (Settings.System.canWrite(this)) {
           //检查返回结果
          Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission granted", Toast.LENGTH_SHORT).show();
        } else {
          Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission not granted", Toast.LENGTH_SHORT).show();
        }
    }
}

自定义权限

为了执行自定义权限,你必须在你的manifest中声明一个或多个标签。

比如:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.myapp" >
    <permission android:name="com.app.myapp.permission.DEADLY_ACTIVITY"
        android:label="@string/permlab_deadlyActivity"
        android:description="@string/permdesc_deadlyActivity"
        android:permissionGroup="android.permission-group.COST_MONEY"
        android:protectionLevel="dangerous" />
    ...
</manifest>

<protectionLevel>属性是必须的,告诉系统当app申请该权限的时候,要怎样通知用户。

<permissionGroup>属性是可选的,可以帮助系统显示自定义属性属于哪个权限组,当通知用户弹出框的时候,当然你可以选择某一个自定义权限属于已知的权限组,也可以属于某一个自定义权限组,建议属于已知的权限组。

<android:label>相当于权限组的提示,要简短

<android:description>是某一个特定权限的描述,规则是两句话,第一句描述,第二句警告用户如果授权会发生什么后果。

比如,CALL_PHONE权限

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
   phone numbers without your intervention. Malicious applications may
   cause unexpected calls on your phone bill. Note that this does not
   allow the application to call emergency numbers.
</string>
  • targetSdkVersion如果是23以下,调用ActivityCompat.requestPermissions(),会弹出权限选择对话框,但是选择拒绝授权,onRequestPermissionsResult中的返回值却是PERMISSION_GRANTED,但选择同意授权,会把应用关闭重新开启当前activity,而不会调用onRequestPermissionsResult中的方法,所以不要在targetSdkVersion设置为23以下,又把complierSdkversion设置为23,这样会出现上述的问题。最好的方式是把targetSdkVersion也设置为23,就可以解决。一切完美运行。*

即:

  1. targetSdkVersion<23, 不要调用处理权限的代码,走老的权限模式。

1.  如果在targetSdkVersion<23时,调用了处理权限的代码。在Android M运行targetSdkVersion < 23的应用时,调用checkSelfPermission,不管用户是否取消授权,checkSelfPermission的返回值始终为PERMISSION_GRANTED的解决办法
		public boolean selfPermissionGranted(String permission) {
	        // For Android < Android M, self permissions are always granted.
	        boolean result = true;

	        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

	            if (targetSdkVersion >= Build.VERSION_CODES.M) {
	                // targetSdkVersion >= Android M, we can
	                // use Context#checkSelfPermission
	                result = context.checkSelfPermission(permission)
	                        == PackageManager.PERMISSION_GRANTED;
	            } else {
	                // targetSdkVersion < Android M, we have to use PermissionChecker
	                result = PermissionChecker.checkSelfPermission(context, permission)
	                        == PermissionChecker.PERMISSION_GRANTED;
	            }
	        }

	        return result;
	  }

  1. targetSdkVersion>=23,complierSdkVersion>=23, 必须调用处理权限的代码,来处理运行时权限,走新的权限模式。
最近的文章

Android文件存储使用

Android文件存储参考 思维导图可能遇到的问题 android系统自身自带有存储,另外也可以通过sd卡来扩充存储空间。前者好比pc中的硬盘,后者好移动硬盘。 前者空间较小,后者空间大,但后者不一定可用。 开发应用,处理本地数据存取时,可能会遇到这些问题: 需要判断sd卡是否可用: 占用过多机身内部存储,容易招致用户反感,优先将数据存放于sd卡; 应用数据存放路径,同其他应用应该保持一致,应用卸载时,清除数据: 2.1 标新立异在sd卡根目录建一个目录,招致用户反感 2.2 用户卸...…

AndroidFileSystem继续阅读
更早的文章

ProgressBar

CircleSeekbar an android circle seekbar libraryquick start1.Add root build.gradle repositories { // ... maven { url "https://jitpack.io" } }2.Add build.gradledependencies { compile 'com.github.feeeei:CircleSeekbar:v1.0.3' }3...…

AndroidProgressBar继续阅读