Android6.0之运行时权限

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
--------全文完--------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值