android - 运行权限(permission)

发表于:,更新于:,By Sally
大纲
  1. 1. 良好的权限体验(permissions best practices)
    1. 1.1. 考虑是请求permission还是使用intent
    2. 1.2. 只请求你需要的权限
    3. 1.3. 不要掩埋用户
    4. 1.4. 解释为什么app需要这个权限
    5. 1.5. 使用adb工具管理权限
  2. 2. 声明权限
  3. 3. 在运行时请求权限(requesting permissions at run time)
    1. 3.1. 正常权限&危险权限(normal&dangerous permission)
    2. 3.2. 检查权限 & 请求权限 & 解释为什么需要权限
    3. 3.3. 请求需要的权限
    4. 3.4. 处理权限请求响应
  4. 4. 看看这个

良好的权限体验(permissions best practices)

  • 权限请求很容易导致用户流失。

考虑是请求permission还是使用intent

两者各有优缺点

  • 请求权限permission

    • 当执行一个操作时,app能完全控制用户的体验,然而,如此广泛的控制会增加任务的复杂度,并且你需要提供相应的ui。

    • 当app运行时或者安装时(依赖android版本),需要提示用户授予权限,之后,app就可以执行操作而不需要向用户请求额外的交互。然而,如果用户拒绝授予权限,app需要权限部分的功能是没法使用的。

  • 使用意图intent

    • 你不需要为操作设计专门的ui,意图会提供ui。这也意味着你将不能继续控制用户的体验。

    • 如果用户没有设置默认的执行app,系统会弹出提示框供用户选择app。如果用户不指定默认处理程序,也许每次都会出现提示框。

只请求你需要的权限

不要掩埋用户

  • eg:一个摄像app,当用户启动app时,请求camera权限是可以被理解的。如果该app同时有分享功能,你不应该在用户启动app时就请求READ_CONTACTS权限,而应该在用户执行分享动作时再请求该权限。

解释为什么app需要这个权限

  • 调用requestPermissions()方法可以显示permissions dialog,但是不会告诉用户为什么需要该权限,有时会让用户很困惑,所以一般情况下,在调用req1uestPermissions()方法之前想用户解释为啥需要该权限是个不错的决定。

使用adb工具管理权限

1
2
3
4
// list permissions and status by group:
$ adb shell pm list permissions -d -g
// grant or revoke one or more permissions:
$ adb shelll pm [grant|revoke] <permission-name> ...

声明权限

  • 在manifest文件中声明权限
1
2
3
4
5
6
7
8
9
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.demo">


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

<application ...>
</application>

</manifest>

在运行时请求权限(requesting permissions at run time)

Android6.0开始,用户不需要在安装/更新app时直接授予权限,可以在app运行时决定是否授予权限。这种运行时权限也给了用户更多的控制权去控制应用的功能。比如:用户选择授予camera应用访问camera权限而不允许其访问设备的位置。并且用户可以在任何时候通过系统设置收回应用程序权限。

正常权限&危险权限(normal&dangerous permission)

  • 正常权限不会直接对用户的隐私带来风险,如果app的清单文件中声明了一系列正常权限,系统会自动授予这些权限。

  • 危险权限允许app访问用户的机密数据。如果app请求危险权限,用户必须明确的审批是否授予app权限。

注:在android5.1(API level 22)及以前,如果清单文件中列出了危险权限,用户在安装应用的时候决定是否授权,如果不授权则不能安装应用。
在android6.0(API level 23)及以后,app需要在清单文件中列出权限,而且需要在运行时请求危险权限。用户可以授予/拒绝任何权限,甚至在用户拒绝授权之后依然可以执行不受权限限制的功能。
在andorid6.0以后,用户在任何时候都可以收回权限,即使app的目标版本是低级别的。

检查权限 & 请求权限 & 解释为什么需要权限

If your app needs a dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission. The user is always free to revoke the permission, so even if the app used the camera yesterday, it cannot assume it still has that permission today.

  • ContextCompat.checkSelfPermission()

If your app needs a dangerous permission that was listed in the app manifest, it must ask the user to grant the permission. Android provides servral methods you can use to request a permission. Calling these methods brings up a standard Android dialog, which you cannot customize.

  • requestPermission()

To help find situations where the user might need an explanation, Android provides a utility method, shouldShowRequestPermissionRationale(). This method returns true if the app has requested this permission previously and the user denied the request.

if the user turned down the permission request in the past and chose the Dont ask aginoption in the permission request system dialog, this method returns false. The method also returns false if a device policy prohibits the app from having that permission.

1
2
3
// 如果app有该权限返回PackageManager.PERMISSION_GRANED,并且可以执行一些操作;
// 否则返回PackageManager.PERMISSION_DENIED,app明确的向用户请求权限;
int permissionCheck = ContextCompat.checkSelPermission(thisActivity, Manifest.permission.RWITE_CALENDAR);

请求需要的权限

1
2
3
4
5
6
7
8
9
10
// 检查是否有用权限
if(ContextCompat.checkSelPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
// 判断是否需要解释为啥需要权限
if(ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) {
// 显示解释,你需要等待用户的响应。当用户看到该消息后,尝试再次请求权限
} else {
// 不需要解释,直接请求权限
ActivityCompat.requestPermissions(thisActivity, new String[] {Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS_CODE);
}
}

处理权限请求响应

  • onRequestPermissionsResult()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {

switch(requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS_CODE: {
// 如果用户点击了取消,那result array 将是空的
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 获得了权限,做之后的逻辑
} else {
// 没有获得权限,失去了依赖于该权限的功能
}
return;
}
case other_permission_request: {
}
}
}

The dialog box shown by the system describes the permission group your app needs access to; it does not list the specific permission. For example,
if you request the READ_CONTACTS permission, the system dialog box just says your app needs access to the device’s contacts. The user only need to grant permission once for
each permission group. If your app requests any other permissions in that group(that are listed in your app manifest), the system automatically grants them. When you request the permission,
the system calls your onRequestPermissionsResult() callback method and passes PERMISSION_GRANTED, the same way it would if the user had explicitly granted your request through the system dialog box.

Note: Your still needs to explicitly request every permission it needs, even if the user has already granted another permission in the same group. In addition, the groupping of permission into groups may change
in future Android release. Your code should not rely on assumption that particular permissions are or are not in the same group.

For example, suppose you list both READ_CONATACTS and WRITE_CONTACTS in your app manifest. If you request READ_CONTACTS and the user grants the permission, and you then request WRITE_CONTACTS, the system immediately grants
you that permission without interacting with the user.

看看这个

1
For example, suppose you list both READ_CONTACTS and WRITE_CONTACTS in your app manifest. If you request READ_CONTACTS and the user grants the permission, and you then request WRITE_CONTACTS, the system immediately grants you that permission without interacting with the user.