一、Android权限介绍:

Android在访问受限的沙盒中运行应用,访问沙盒外的资源是受到限制的(包括读写用户的私有数据(如联系人)、读写其他应用的文件、执行网络访问、使设备保持唤醒状态)。在6.0之前,应用在安装时,所请求的权限都被授予,这样的话就会造成一些不必要的权限的授予,否则无法安装使用。在6.0之后,引入了运行时权限机制,即对于那些危险(涉及用户隐私)的权限,需要在运行过程中进行授予。

进程级安全限制,让任何两个应用都不能在同一进程中运行,因为它们需要作为不同的 Linux 用户运行(Android 为每个软件包提供唯一的 Linux 用户 ID)。但可以在每个软件包的 AndroidManifest.xml 的 manifest 标记中使用 sharedUserId 属性,为它们分配相同的用户 ID。这样做以后,出于安全目的,两个软件包将被视为同一个应用,具有相同的用户 ID 和文件权限。注意,为保持安全性,只有两个签署了相同签名(并且请求相同的 sharedUserId)的应用才被分配同一用户 ID。

二、在Manifest中声明权限:

对于沙盒未提供的功能,需要申明访问权限,使用<uses-permission android:name="..."/>。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

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

</manifest>

在Manifest中申明的权限,如果是普通权限,则在安装时,就自动授予了,如果是危险权限,则需要运行时确认。

三、运行时请求权限:

在Android6.0之前,所有权限都列在清单文件中,必须在安装时授权,不授权则无法安装。

在6.0(API23)之后,Android引入了运行时权限的概念,将系统权限分为两种:

正常权限:不会对用户隐私造成风险的权限。在manifet中声明则系统自动授予。

危险权限:涉及到用户隐私数据的权限。需要用户在运行时授予这些权限。

1.检查权限:


// 检测权限是否授予
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    // 检测该全是是否被拒绝,同时提供一个解释,为何需要此权限
    // 如果用户在过去拒绝了权限请求,并在权限请求系统对话框中选择了 Don't ask again 选项,
    // 此方法将返回 false。如果设备规范禁止应用具有该权限,此方法也会返回 false
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
        // 显示一个解释用的提示,之后尝试再次请求该权限。
    } else {
        // 如果不显示解释,则请求权限
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
        // MY_PERMISSIONS_REQUEST_READ_CONTACTS 是自定义的请求码
    }
}


2.处理权限请求响应:


@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // 如果请求取消了,数组将是空的
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限请求通过,可以执行权限相关的操作
            } else {
                // 未授权,不允许执行权限相关操作
            }
            return;
        }
        // 其他的权限请求
    }
}


注意:

1)授权提示框不显示具体权限,而是整个权限组。如READ_CONTACTS,显示要访问设备联系人。用户只要为权限组授权一次,以后该权限组其他权限请求将默认授予。但是 其它权限仍要请求,因为权限分组在将来的 Android 版本中可能会发生变化。不应依赖特定权限属于或不属于相同组这种假设。


2)如果用户拒绝了某项权限请求,应该有个提示。例如,可以显示一个对话框,解释为什么需要该权限。
3)当系统要求用户授予权限时,用户可以选择指示系统不再要求提供该权限。requestPermissions() 再次要求该权限,系统会立即拒绝,直接调用onRequestPermissionsResult() 方法,并传递 PERMISSION_DENIED。

四、权限建议:


a.可以用Intent取代权限。例如,当你想做个拍照的功能时,可以用intent请求别的应用来完成,之后返回照片。这样既不用申请权限,也省得自己写个照相机(界面,功能等等);

b.申请自己所需的权限,甚至可以用a中的方法精简权限数量;
b.申请自己所需的权限,甚至可以用a中的方法精简权限数量;
c.在哪里需要则在哪里进行权限申请,不要全部在启动时就开始申请权限;
d.在必要时解释一下为何应用要申请该权限;
e.适配6.0+。在6.0之前我们可以很放心的使用我们在Manifest中申请的权限,但是在6.0之后,我们必须要在运行时进行权限的检查。因此,测试时要两种情况都测。