您的位置:首页 > 移动开发 > Android开发

Android6.0之运行时权限

2016-01-13 19:46 351 查看

Android 6.0来了

  Android 6.0 Marshmallow新增了运行时权限特性,还没有适配6.0系统的应用可能有点猝不及防了。这不用户反馈新买的最贵的华为手机打不开我们的应用。报的是权限异常,那就来看看android6.0新的权限特性到底是什么。

墙外的官方文档

  自从developer.android.com无法访问后就很少看android官方文档了。但是网上的博文毕竟是别人消化过的,变味了。

  其实完全可以阅读离线文档。我目前的开发环境是android studio + sdk代理,更新到sdk23版本,在sdk/doc目录下就是离线文档。再用火狐浏览器打开,脱机工作就大功告成了。

简介

  通过主页Android6.0 Marshmallow展示的”Get started”链接跳到review页面,选择Behavior changes项,找到Runtime Permissions,简略翻译如下:

  新的权限模型,允许用户在应用运行时直接管理应用权限。

  如果你的应用targetSdkVersion是M Preview发布版或更高版本,请确保在运行时检查并获取权限。即使你的目标sdk不是M Preview发布版,也应该在新的权限模型下进行测试。

  调用checkSelfPermission()方法确定权限是否已获取,调用requestPermissions去获取权限。

  更多支持信息请参考Permissions页面。关于对应用的影响,请参考TestingGuide。

  (译者注:这里有个坑,如果你在app/build.gradle和AndroidManifest.xml都配置了targetSdkVersion请确保二者统一,如果不统一,AndroidManifest.xml的配置会被app/build.gradle的配置覆盖。)

概述

  点击上面的Permissions链接,跳到Preview-API Overview-Permissions,看一下详细内容:

  新的权限系统兼容低版本sdk。

  新的模型包含下面的特性:

在manifest声明权限:像早的平台一样;

权限组:权限被分到权限组里。比如CONTACTS权限组包含了读取和写入用户通讯录和个人信息的权限。

安装时特定权限:当用户安装或更新应用程序时,系统授予所有列在manifest里的级别为PROTECTION_NORMAL的权限。比如闹钟和因特网权限是PROTECTION_NORMAL级别权限,所以会在安装时被自动授予。

  更多信息请参考Normal Permissions。

  系统也会给一个应用程序授予签名权限,在System components and signature Permissions里有描述。在安装时不会提示签名权限。

用户运行时权限授予:当应用程序请求一个权限时,系统为用户展示一个对话框,然后调用应用程序的回调方法通知应用程序用户是否授予了该权限。

  这个权限模型改变了你的应用程序使用需要权限的特性的方式。下面是你需要对此作出的调整。

总是检查权限:在应用程序进行需要权限的操作时,应该首先检查是否拥有这个权限。如果没有,需要请求授予权限。PROTECTION_NORMAL级别的权限除外。

优雅的处理权限缺失:如果应用程序没有被授予特定的权限,它必须明确的处理失败。比如,某个特性需要一项未被授予的权限,应用程序可以禁用它。如果非要使用这个权限,应用程序需要把相关的所有功能设为不可用,并且提示用户需要授予该权限。

权限是可撤销的:用户可以在任何时候撤销权限。如果用户关闭了一项应用权限,应用程序不会被通知到。你的应用程序需要在下次使用时再次确认是否拥有该权限。

权限组

  相关的权限被分在权限组中,这样用户可以通过一次授权完成对组中所有权限的授权。用户只需要对应用程序授权一项权限,那么随后相同权限组中的权限会被自动授予。比如,假设应用程序的manifest中包含了SEND_SMS和RECEIVE_SMS两项权限,它们属于相同的权限组android.permission-group.SMS。当应用需要发送一条短信时,会请求SEND_SMS权限。系统展示给用户请求授权访问SMS的权限。如果用户同意了,系统会授予应用SEND_SMS权限。随后,当应用请求RECEIVE_SMS权限。系统会自动授予这个权限,因为用户已经批准了相同权限组中的权限。

系统组件以及签名权限

  通常当用户安装应用时,系统只授权给应用manifest中PROTECTION_NORMAL级别的权限。

  但是下面的几种情况系统会授予应用更多的权限:

系统组件自动被授予manifest中的所有权限。

如果应用的manifect中请求的权限是PROTECTION_SIGNATURE级别的权限,并且应用程序的签名证书与声明该权限的应用程序的签名证书一致,系统会在安装时授予应用程序这些权限。应用程序不能在运行时请求签名权限。

向前和向后兼容

  如果应用程序目标sdk不是M版,应用程序继续在M版本设备上使用旧的权限模型。当用户安装应用程序时,系统会询问用户授权所有列在manifest里的权限。

  注意:在运行M版本的设备上,用户能通过设置关闭任何应用的权限(包括旧的应用)。如果用户关闭了旧应用的权限,系统会默认禁用相应的功能。当应用程序试图进行需要这些权限的操作时,这个操作不一定会引发异常。相反的,它可能返回空的数据集、错误信号或者产生未预料的行为。比如,如果你在没有权限的情况下查看日历,会返回空的数据集。

  如果你的应用运行在不是M版本的设备上,系统会像对待其他应用一样对待它:系统会在安装时询问用户声明的授权权限。

权限和Intent

  一般情况下你有两种方式来完成一项任务。你可以请求被授予权限来完成这件事,或者通过发送intent给其他的应用来完成。

  比如,假设你的应用需要调用相机拍摄一张图片。你的应用可以获取android.permission.CAMERA权限,这样你就可以直接访问相机,并调用相机api来

控制相机拍照。这样你可以控制拍照的全部过程并自己定义相机UI。

  如果你不需要这样的控制,你可以使用ACTION_IMAGE_CAPTURE这个intent来获取图片。当你启动这个intent,会有选择相机应用的提示框提示给用户,用户可以通过这个相机应用拍照,相机应用通过你的onActivityResult()方法返回结果。

  同样的,如果你想打电话、访问用户通讯录等等,你都可以通过创建相应的intent或者直接获取权限的方式。两种方式各有优劣。

  如果你用权限:

可以完全控制用户体验,但是会增加任务的复杂性。

第一次的时候回提示用户获取权限。如果用户禁止了权限,你的应用就不能进行这项操作了。

 如果你用intent:

不需要自己定制ui。缺点是不能控制用户体验。

如果没有指定默认的应用,每次都会弹出选择框。

运行时权限编码

  启用新的权限模型

  将应用的targetSDKVersion设置为”MNC”,compileSDKVersion设置为”android-MNC”,你就启用了M开发版。必须将minSdkVersion指定为”MNC”才能启用发布版。

  指定只针对M版的权限

  在manifest中使用新的

<users-permission-sdk-m>


标签来表明该权限只针对M版。这样声明后,如果应用在老的设备上安装,系统不会提醒用户授权该项权限。安装更新也是一样。

  在M版本上

<users-permission-sdk-m>




<users-permission>


是一样的。

  权限弹窗

  检查应用运行在哪个平台上

  新的权限模型只能用在M版设备上。在调用这些权限方法时必须判断Build.VERSION.CODENAME是否是”MNC”。

  检查当前是否有某项权限时使用

  Context.checkSelfPermission(permission_name)方法。比如检查拍照权限: Context.checkSelfPermission(Manifest.permission.CAMERA).

  权限和权限组如下:



解释为什么需要权限

  在一些情况下你也许需要帮助用户理解为什么需要一项权限。比如,如果用户登录了一个摄影应用,用户不会对它需要相机权限感到惊讶。但是如果用户关闭了这项权限,然后再次登录这个摄影应用,这时可能表明需要帮助用户理解为什么需要这项权限。

  为了找出哪里需要做出额外的权限解释,系统提供了

Activity.shouldShowRequestPermissionRationale(String)方法。如果用户在授权提示框里拒绝了授权请求,这个方法会返回true。表明这里需要为用户做出解释。

  如果用户在关闭权限时选择了“不再提醒”,这个方法会返回false。如果设备策略禁止了应用的这项权限同样会返回false。

请求权限

  如果应用没有它需要的权限可以通过Activity.requestPermissions(String[], int)方法获取。参数是要获取的权限及请求码。这个请求是异步的:它立即返回并展示对话框,用户操作对话框后系统调用回调方法返回结果及跟requestPermissions相同的返回码。

if(checkSelfPermission(Manifest.permission.READ_CONTACTS)
!=PackageManager.PERMISSION_GRANTED){

// Should we show an explanation?
if(shouldShowRequestPermissionRationale(
Manifest.permission.READ_CONTACTS)){
// Explain to the user why we need to read the contacts
}

requestPermissions(newString[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);

// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant

return;
}


  处理权限响应

  用户选择后的系统回调方法是Activity.onRequestPermissonResult(int, String[], int[])。你的应用需要覆写这个方法。比如:如果你请求READ_CONTACTS权限,你可以这样处理:

publicvoid onRequestPermissionsResult(int requestCode,
String permissions[],int[] grantResults){
switch(requestCode){
case MY_PERMISSIONS_REQUEST_READ_CONTACTS:{
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){

// permission was granted, yay! do the
// calendar task you need to do.

}else{

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

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


  如果用户拒绝了权限请求,你可以采取适当的操作。比如:你可以弹出对话框解释为什么不能进行原来的操作。

  当系统请求用户授权权限时,用户可以选择不再提醒。这种情况下,当应用调用requestPermissions()请求权限时,系统会立即拒绝该请求,并调用onRequestPermiResult()方法。所以,应用不能假设每次权限请求都会跟用户交互。

测试运行时权限

  当你的应用目标sdk是M版本时,你必须处理好权限。你不能假设应用运行时拥有了某项权限。当应用运行时,很可能没有任何权限,用户可以在任何时候撤销或恢复权限。

  你必须保证你的应用在任何权限状况下都表现良好。

新的adb命令和选项

  M版本提供了几个新的命令来测试应用处理权限的场景。你可以用adb install 的-g选项来授权manifest里的所有权限。

$ adb install -g <path_to_apk>


  你可以用新的pm命令来授权或撤销权限。可以将它用于自动化测试。

  使用grant命令授权权限:

$ adb pm grant <package_name> <permission_name>


  比如,授权com.example.myapp录音权限:

$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO


  使用revoke命令撤销权限:

$ adb pm revoke <package_name> <permission_name>


最佳实践及使用说明

  新的权限模型提供了更顺畅的用户体验,也让用户能够更放心的安装应用并了解应用正在做的事情。下面是推荐的使用方式。

  只请求你需要的权限

  每次请求权限,你都在强迫用户做选择。如果用户拒绝了请求会削弱你的应用的功能。

  你应该尽量少的做请求。

  比如:通常你能够使用intent而不是权限来完成某项任务。

  不要强迫用户

  如果你一次请求了过多的权限,你可能在强迫用户并导致用户退出你的应用。相反的,你应该在需要的时候去请求权限。有些情况下,应用确实需要多个权限,这时,你应该在应用启动时尽早去请求权限。如果你的应用提供了教程,那么在教程的最后对必要的权限进行说明是很有必要的。

  Normal Permissions

  很多权限被定义为PROTECTION_NORMAL,这表明他们对用户隐私和安全造成的风险很小。比如,用户会很想知道一个应用是否会读取通讯录信息。相反,振动设备不会有太大的风险,所以它被指定为normal。

  如果你在manifest里声明了normal级别的权限,你不需要调用

Activity.checkShelfPermission()或者Activity.requestPermissions方法。

  目前PROTECTION_NORMAL级别的权限如下:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS

android.permission.ACCESS_NETWORK_STATE

android.permission.ACCESS_WIFI_STATE

android.permission.ACCESS_WIMAX_STATE

android.permission.BLUETOOTH

android.permission.BLUETOOTH_ADMIN

android.permission.BROADCAST_STICKY

android.permission.CHANGE_NETWORK_STATE

android.permission.CHANGE_WIFI_MULTICAST_STATE

android.permission.CHANGE_WIFI_STATE

android.permission.DISABLE_KEYGUARD

android.permission.EXPAND_STATUS_BAR

android.permission.FLASHLIGHT

android.permission.GET_ACCOUNTS

android.permission.GET_PACKAGE_SIZE

android.permission.INTERNET

android.permission.KILL_BACKGROUND_PROCESSES

android.permission.MODIFY_AUDIO_SETTINGS

android.permission.NFC

android.permission.PERSISTENT_ACTIVITY

android.permission.READ_SYNC_SETTINGS

android.permission.READ_SYNC_STATS

android.permission.READ_USER_DICTIONARY

android.permission.RECEIVE_BOOT_COMPLETED

android.permission.REORDER_TASKS

android.permission.SET_TIME_ZONE

android.permission.SET_WALLPAPER

android.permission.SET_WALLPAPER_HINTS

android.permission.SUBSCRIBED_FEEDS_READ

android.permission.TRANSMIT_IR

android.permission.VIBRATE

android.permission.WAKE_LOCK

android.permission.WRITE_SETTINGS

android.permission.WRITE_SYNC_SETTINGS

android.permission.WRITE_USER_DICTIONARY

com.android.alarm.permission.SET_ALARM

com.android.launcher.permission.INSTALL_SHORTCUT

--------全文完--------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 权限管理 6-0