Android Permissions-系统权限

2016-08-29 · 🙈Ray · 0条 · 421次

一. 声明权限

每一个android软件都运行在一个受限访问的沙盒中。如果app要访问它所在的沙盒以外的资源或者信息就要请求适当的权限。在清单文件中列出应用需要的权限。

基于权限的敏感程度,系统可能会自动授予权限(如开启闪光灯),也可能需要设备使用者通过请求(如获取通讯录)。

基于系统版本不同,在android5.1以及更低版本的系统中,用户要在安装的时候通过权限,在6.0和更高的系统中可以在运行app的时候授予权限。

决定你的应用需要什么权限

当开发软件的时候,当app使用需要权限的能力时需要注意。通常,app在使用不是它创建的资源或者信息的时候,或者进行影响设备或其他app行为的操作的时候需要某些权限。

For a list of system permissions, see Normal and Dangerous Permissions.

一个app仅需要它直接执行的操作的权限。当它请求另外的app执行任务或者提供信息的时候是不需要提供执行这项任务或者拿到这些信息所需要的权限的。

向清单(Manifest)文件中添加权限

在<manifest>元素中添加子元素<uses-permission>来添加权限。

例:发送SMS的权限


package="com.example.snazzyapp">

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


<application ...>
...
</application>

</manifest>

二. Requesting Permissions at Run Time

从Android6.0(API 23)开始,不再在安装的时候选择权限,而是在运行时。简化了安装过程,同时也给了用户对app功能的更多控制,可以选择开启哪些权限而不开启哪些权限。用户通过到设置界面,可以随时取消app的权限。

系统权限分为两类——normal和dangerous

普通权限不会直接危害到用户的隐私。如果在清单文件中声明了普通权限,系统会自动授予。

危险权限会给app访问用户私密数据的能力。如果清单文件中有该类权限,需要用户明确地授予。

如果设备是Android5.1或者更低的版本,或者app的target SDK是22或者更低:如果在清单文件中有危险权限,用户要在安装的时候授予,如果用户不同意,系统压根儿不会安装。

如果设备是Android6.0或者更高,或者应用的target SDK是23或者更高:应用会在运行的时候请求它需要的危险权限。用户可以对每个权限做出授予或者拒绝的选择,即使用户拒绝授予权限,应用也可以继续运行,只是限制了部分能力。(从Android6.0开始,即使应用的target SDK达不到23,用户也可以在任何时候收回权限。在开发的时候,无论应用的target SDK是多少,都需要测试应用以确认即使没有某些必要的权限也可以正常运行。)

Check For Permissions

因为用户可以随时收回权限,所以在每次执行需要某项危险权限的操作时都需要检查应用是否有该项权限。使用 ContextCompat.checkSelfPermission() 方法。

例:

如果有该权限会返回 PackageManager.PERMISSION_GRANTED,如果不具有会返回 PERMISSION_DENIED

Request Permissions

Android提供了几个方法供你去请求权限,调用这些方法会弹出标准的不可以自定义的Android dialog。

向用户解释为什么需要某项权限

但是记住不要将用户淹没在解释中,如果你提供了太多的解释,用户会不开森的。嫌烦。合理解释就可以了,如打开相册应用请求相册权限是合理的不需要解释,但是相册应用请求联系人或者位置可能就会让用户感到害怕了,就需要稍微解释一下。

一个合适的方法就是仅在用户拒绝权限请求的时候解释一下。如果用户不断尝试使用需要某项权限的功能,但是不断拒绝权限请求,这就表明用户极有可能不理解为何app需要这些权限去支持该功能。

为了帮助开发者找到用户可能需要解释的情况,Android提供了一个有用的方法shouldShowRequestPermissionRationale(). 若果app之前请求过权限并且用户拒绝了,该方法返回true。

注:如果用户之前拒绝过请求,并且在系统对话框中选择了Don’t ask again,那么这个方法将会返回false。如果设备策略(某些定制系统会禁止应用获取某些权限?)禁止拥有某项权限,这个方法也会返回false。

Request the permissions you need

App需要调用 requestPermissions()方法去请求它仍未具有的合适的权限。该方法需要传递想要获取的权限的整数请求码(integer request code)以及要获取的权限。这个方法是异步的:它会立刻返回,当用户对弹出的对话框做出响应后,系统会调用带有结果的回调方法,传递相同的请求码。

例:

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {

// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.

} else {

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

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

// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}

Handle the permissions request response

当用户对弹出的是否允许权限对话框做出响应后,系统会调用应用的onRequestPermissionsResult()方法,并传递用户的响应结果。应用需要重写该方法去获取权限是否通过。

例:请求READ_CONTACTS权限的回调。

@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// permission was granted, yay! Do the
// contacts-related task you need to do.

} else {

// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}

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

对于一个权限组用户只需要通过一次。当请求该权限组中的其他权限时,系统将会自动通过授予,调用 onRequestPermissionsResult() 并传递PERMISSION_GRANTED

注:当你的应用需要权限的时候仍然需要请求权限,不能因为同组的其他权限已经被授予过而放弃该行为(系统会自动授予的)。在以后发布的版本中可能改变模式。

用户拒绝某项权限请求后,如果应用不能执行用户的某些需要该权限的操作时,需要给出解释。

应用请求某些权限,用户可以选择以后不再提示。此种情况下,如果用户之前是拒绝了的,那么以后调用 requestPermissions() 系统会自动拒绝。系统会调用onRequestPermissionsResult() 并传递 PERMISSION_DENIED此种情况下,调用 requestPermissions()将不会与用户有直接交互。

三. Best Practices

如果用户被请求权限的操作给搞烦了,是很容易放弃使用的。

Consider Using an Intent

对于一项任务,你可以选择自己执行或者选择让另一款APP来“帮忙”。

例如你想用你的app拍摄照片,第一种方法是请求摄像头 CAMERA permission,然后利用CAMERA API,拍摄照片。另外一种方法是使用 ACTION_IMAGE_CAPTURE Intent来请求照片。当你发送此意图的时候,系统会让用户选择一款APP来拍摄照片(如果有默认将会使用默认),然后通过 onActivityResult() 方法返回结果。

使用权限:

当执行操作的时候,你的应用对用户体验有完全控制。然而 ,过多的控制增加了任务的复杂度,因为你要设计合适的UI。

用户可以选择一次性给予权限,或者在运行的时候,或者在安装的时候(取决于Android系统版本)。在此之后,你的应用可以执行操作不再需要与用户有额外交互。然而,如果用户不授予权限,或者后来收回权限,你的应用将会不能执行这些特定的操作。

如果使用Intent:

不需要为了操作设计UI。然而,对于用户体验将会失去控制(因为用户体验将由执行操作的APPP提供)。用户可能会跟一个你从没有见过的APP交互。

如果用户没有默认的程序,系统会让用户选择一个默认的APP。如果用户没有选择默认程序的时候,每次他们执行某个操作的时候就需要从一个对话框中选择应用。

Only Ask for Permissions You Need

每次请求权限都是要求用户做出选择。你应该将这个次数减到最低。如果用户运行Android6.0或者之后的系统,每次用户尝试新的需要权限的APP特性,应用都会打断用户的操作,因为要请求权限。如果用户运行的是早期的Android版本,用户在安装的时候不得不授予一个应用它所请求的所有权限,如果列表太长或者看起来不合适,用户可能压根儿就不会安装这款应用。因此,需要将应用需要的请求降到最低。

如果某个特性不是应用功能的核心部分,应该考虑让其他APP来执行这个功能。

Don’t Overwhelm the User

在Android6.0以及更高版本的系统中,app会在运行的时候请求权限,如果权限过多,会将用户淹没,使用户感到厌烦。所以,只有当需要的时候再去请求。

某些情况下,某些权限可能跟app密切相关。这类权限,应该在应用首次启动的时候,就去请求所有这些高相关性权限。例如你开发了一款图片(摄影)软件,那么请求Camera权限就没有什么好奇怪的。但是如果这款应用可以分享图片给联系人,那么就不该在应用首次启动的时候请求,只有当用户尝试分享的时候再去请求。

如果app有引导页,那么在引导完成后应该立刻请求这些高度相关的权限。

Explain Why You Need Permissions

当你调用 requestPermissions() ,系统显示的对话框只显示了用户请求的权限,并没有说明为什么。有时候这会让用户感到迷惑,所以在调用该方法前最好说明一下原因。

一种方式是讲这些请求放进一个app引导中来告知用户。引导轮流显示应用的特性,这样便可以展示它需要的权限。For example, the photography app's tutorial could demonstrate its "share photos with your contacts" feature, then tell the user that they need to give permission for the app to see the user's contacts. The app could then call requestPermissions() to ask the user for that access. 当然并不是每一个用户都会去看这些引导,所以在程序的正常运行中仍然需要检查并请求权限。

Test for Both Permissions Models 两种不同权限模式的测试

下面的小技巧可以帮你明确在API23及以上系统中的权限相关的代码问题:

1.明确应用当前的权限和相关的代码路径。Identify your app’s current permissions and the related code paths.

2.Test user flows across permission-protected services and data.

3.Test with various combinations of granted or revoked permissions. For example, a camera app might list CAMERA, READ_CONTACTS, andACCESS_FINE_LOCATION in its manifest. You should test the app with each of these permissions turned on and off, to make sure the app can handle all permission configurations gracefully. Remember, beginning with Android 6.0 the user can turn permissions on or off for any app, even an app that targets API level 22 or lower.

4.Use the adb tool to manage permissions from the command line:

List permissions and status by group:

$ adb shell pm list permissions -d -g

Grant or revoke one or more permissions:

$ adb shell pm [grant|revoke] <permission-name> ...

5. Analyze your app for services that use permissions.


  0