`
yangsongjing
  • 浏览: 248544 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

android 6.0权限

阅读更多
从Android 6.0开始, 用户需要在运行时请求权限, 本文对运行时权限的申请和处理进行介绍, 并讨论了使用运行时权限时新老版本的一些处理.

Android应用权限简要介绍
一个Android应用默认情况下是不拥有任何权限的, 这即是说, 在默认情况下, 一个应用是没有权利去进行一些可能会造成不好影响的操作的. 这些不好的影响可能是对其它应用,操作系统,或者是用户.
如果应用需要一些额外的能力,则它需要在AndroidManifest.xml中静态地声明相应的权限.

如果应用没有在manifest中声明权限, 却使用了相应的功能, 在调用到相应功能的时候, 将会抛出异常.
比如程序要发送一个请求,却忘记加Internet权限, 那么在发送这个请求的时候程序就会抛出异常,一般不会catch这个异常,所以程序直接就崩溃了:
Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)


在Android 6.0 (API 23) 发布之前, 所有的权限都在安装应用的时候显示给用户,用户选择安装则表示全部接受这些权限, 之后无法撤销对这些权限的授权.
Android 6.0开始, 一部分比较危险的权限需要在程序运行时显式弹框,请求用户授权.
至于什么时候弹这个框,由应用程序自己决定.
对于其他权限,认为不是很危险,所以仍然保持原来的做法,在用户安装应用程序时就予以授权.
还需要注意的是,在设置中,对于应用的危险权限,用户可以选择性地进行授权或者关闭.

Permission的保护等级
permission的保护等级通过protectionLevel属性设置, 共有4种: normal,dangerous,signature,signatureOrSystem.
具体可以参见介绍:http://developer.android.com/guide/topics/manifest/permission-element.html

签名相关的比较不常用, 剩下的两种是normal和dangerous.
Guides里面对这两种类型进行了讨论: 官网Guides: https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
总结下来就是: 所有的权限仍然在manifest中静态声明, normal权限的在安装的时候自动授权, 而dangerous的权限需要应用明确地请求用户授权.
当然对于Android 6.0以下的手机,或者以前开发的旧应用来说, dangerous权限也是安装时授权的, 具体看下一节的讨论.

Dangerous Permissions:
Table 1. Dangerous permissions and permission groups.

Permission Group Permissions
CALENDAR
READ_CALENDAR
WRITE_CALENDAR
CAMERA
CAMERA
CONTACTS
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE
RECORD_AUDIO
PHONE
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS
BODY_SENSORS
SMS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE


想要查看所有dangerous的权限, 也可以用命令:
adb shell pm list permissions -g -d
 
手机版本和程序版本的不同处理
这里引用一段Guides里面的原文:
If the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the app requests permissions from the user at run-time. The user can revoke the permissions at any time, so the app needs to check whether it has the permissions every time it runs. For more information about requesting permissions in your app, see the Working with System Permissions training guide.
If the device is running Android 5.1 (API level 22) or lower, or the app's targetSdkVersion is 22 or lower, the system asks the user to grant the permissions when the user installs the app. If you add a new permission to an updated version of the app, the system asks the user to grant that permission when the user updates the app. Once the user installs the app, the only way they can revoke the permission is by uninstalling the app.
这里头要注意and和or的使用,说明了只有满足targetSdkVersion和实际使用设备的版本都在23及以上的时候,才会采用新的动态权限机制. 其他情况, 跟之前一样, 在安装和升级应用的时候就授权了所有的权限.

可以总结为:
1.所有的权限都在manifest中声明.
2.如果(1)你的app的targetSdkVersion是23及以上,并且(2)app运行在Android 6.0及以上的设备,危险权限必须动态请求.
当权限被拒绝,app理应还是能够使用的,只不过权限相关的部分功能不能用.
3.上一条中的两个条件(1)(2)没有同时满足,即属于其他情况, 所有权限在安装时请求,如果用户不接受,则不安装.

特别注意这种情况: 旧应用新系统.
如果targetSdkVersion小于23,即被认为是Android 6.0发布之前开发的应用, 还没有兼容6.0.
这种应用即便是被装在Android 6.0的机器上,也是采用原来的安装即授予权限逻辑, 所有权限在应用安装时全部被授权.
在Android 6.0的设备上安装targetSdkVersion小于23的应用之后, 可以在应用的设置中查看,发现所有的dangerous权限状态都是打开.
所以不用担心老的应用在Android 6.0上会各种乱崩.

但是用户仍然可以在系统设置中禁用权限:
在模拟器上点击授权开关的时候弹出了以下提示:

如果用户执意要取消授权, 应用虽然不会直接崩溃,但是功能变为默默无作为状态, 返回值可能变为null或者0,进而引起无法预料的行为或者崩溃.

为什么要及时升级targetSdkVersion
这是因为每一个版本的API有可能会产生新的权限,这些新增的权限, 对于targetSdkVersion比该API低的应用是自动获取的.
所以targetSdkVersion最好是能及时写到最新,这样避免应用自动获取到新API新增的权限.

结论: 对targetSdkVersion还不存在的权限是自动获取到的.

可以参见: API Guides: https://developer.android.com/guide/topics/security/permissions.html
其中”Automatic permission adjustments”那段.

Permission group
所有的权限都有自己的permission group.
系统弹框请求某一个permission时也是只说明了它的类别,当用户同意,系统会给予它该条permission.(只有这一条).
但是如果app已经有了该group下的另一条permission,系统将会自动授予权限(也即请求权限的callback直接返回),这过程中不与用户交互.

动态权限请求的实现
原文: https://developer.android.com/training/permissions/requesting.html
因为权限动态检查相关的API是Android 6.0才加入的, 所以minSdkVersion不是23时,推荐使用SupportLibrary来实现,好处是: 程序里不必加if来判断当前设备的版本.
1.检查权限状态
如果执行的操作需要一个dangerous permission, 那么每次在执行操作的地方都必须check你是否有这个permission, 因为用户可以在应用设置里随意地更改授权情况, 所以必须每次在使用前都检查是否有权限.

检查权限的方法: ContextCompat.checkSelfPermission()两个参数分别是Context和权限名.
返回值是:PERMISSION_GRANTED if you have the permission, or PERMISSION_DENIED if not.

比如:
复制代码
if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS)) {
    //has permission, do operation directly
    ContactsUtils.readPhoneContacts(this);
    Log.i(DEBUG_TAG, "user has the permission already!");
} else {
    //do not have permission
复制代码

2.动态请求权限
如果上面权限检查的结果是DENIED, 那么就需要显式地向用户请求这个权限了.
Android提供了几个方法来动态请求权限, 调用这些方法会显示出一个标准的Dialog, 这个Dialog目前是不能被定制的.

2.1有时候可能需要解释为什么需要这个权限
有时候你可能会需要跟用户解释一下权限的用途.
注意不是每条权限都需要解释,显而易见的那种可以不解释,太多的解释会降低用户体验.

一种方式是,当用户拒绝过这个权限,但是又用到了这个功能, 那么很可能用户不是很明白为什么app需要这个权限, 这时候就可以先向用户解释一下.
为了发现这种用户可能需要解释的情形, Android提供了一个工具类方法: shouldShowRequestPermissionRationale()
如果app之前请求过该权限,被用户拒绝, 这个方法就会返回true.
如果用户之前拒绝权限的时候勾选了对话框中”Don’t ask again”的选项,那么这个方法会返回false.
如果设备策略禁止应用拥有这条权限, 这个方法也返回false.

注意具体解释原因的这个dialog需要自己实现, 系统没有提供.

2.2请求权限
请求权限的方法是: requestPermissions() 传入一个Activity, 一个permission名字的数组, 和一个整型的request code.
这个方法是异步的,它会立即返回, 当用户和dialog交互完成之后,系统会调用回调方法,传回用户的选择结果和对应的request code.
代码:
复制代码
if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS)) {
    //has permission, do operation directly
    ContactsUtils.readPhoneContacts(this);
    Log.i(DEBUG_TAG, "user has the permission already!");
} else {
    //do not have permission
    Log.i(DEBUG_TAG, "user do not have this permission!");

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

        // Show an explanation 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.
        Log.i(DEBUG_TAG, "we should explain why we need this permission!");
    } else {

        // No explanation needed, we can request the permission.
        Log.i(DEBUG_TAG, "==request the permission==");

        ActivityCompat.requestPermissions(MainActivity.this,
                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.
    }
}
复制代码

这个对话框是系统的,不能自定义.
经验证, 请求权限对话框中的”Don’t ask again”的选项, 只有该条权限之前的状态是Denied的时候,才会出现.
以前从未授权(即第一次弹框), 或者之前的状态是Granted(当然这种情况一般不会弹框询问), 出现的弹框都是不带该不再询问的选项的.

2.3处理请求权限的响应
当用户对请求权限的dialog做出响应之后,系统会调用onRequestPermissionsResult() 方法,传回用户的响应.
这个回调中request code即为调用requestPermissions()时传入的参数,是app自定义的一个整型值.
如果请求取消,返回的数组将会为空.

代码:
复制代码
@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.
                ContactsUtils.readPhoneContacts(this);
                Log.i(DEBUG_TAG, "user granted the permission!");

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Log.i(DEBUG_TAG, "user denied the permission!");
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}
复制代码


系统自动回调的情况:
有一些情形下,调用
1.自动授权: 如果用户已经允许了permission group中的一条A权限,那么当下次调用requestPermissions()方法请求同一个group中的B权限时, 系统会直接调用onRequestPermissionsResult() 回调方法, 并传回PERMISSION_GRANTED的结果.
2.自动拒绝: 如果用户选择了不再询问此条权限,那么app再次调用requestPermissions()方法来请求同一条权限的时候,系统会直接调用onRequestPermissionsResult()回调,返回PERMISSION_DENIED.

Demo地址: https://github.com/mengdd/AndroidMRuntimePermissionSample


Best Practices
原文: https://developer.android.com/training/permissions/best-practices.html
Best Practices 总结:
1.用Intent启动其他应用来完成功能.
2.只用真的需要的权限.
3.不要一次请求多个权限来烦用户,有的权限可以等到要用的时候再请求.
4.向用户解释为什么需要这个权限.
5.从Android 6.0开始,每一条权限,都需要测试开关两种状态下是不是都能让应用正常运行,而不是崩溃.
并且相关的权限可能会需要测试不同的组合.

ADB命令
可以用命令行来管理权限:
Use the adb tool to manage permssions 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> ...
参考资料:
API Guides: https://developer.android.com/guide/topics/security/permissions.html
Training: https://developer.android.com/training/permissions/index.html
Runtime permissions: https://source.android.com/devices/tech/config/runtime_perms.html
permission element: http://developer.android.com/guide/topics/manifest/permission-element.html

设计Patterns -> Permissions: https://www.google.com/design/spec/patterns/permissions.html

博客文章: http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/

第三方库:
PermissionsDispatcher: https://github.com/hotchemi/PermissionsDispatcher
RxPermissions: https://github.com/tbruyelle/RxPermissions
Grant: https://github.com/anthonycr/Grant

本文地址: http://www.cnblogs.com/mengdd/p/4892856.html
本文Demo地址:  https://github.com/mengdd/AndroidMRuntimePermissionSample
分享到:
评论

相关推荐

    Android6.0权限DEMO

    "Android 6.0权限DEMO"是一个示例项目,它演示了如何在新系统环境下适当地请求和管理权限。这个DEMO可以帮助开发者理解并实践新的权限模型,确保他们的应用能够顺利运行在Android 6.0及以上版本。 首先,我们需要...

    Android6.0权限处理 示例

    在`Android6.0 权限处理.md`文件中,详细记录了这个Demo的实现步骤和代码示例,包括如何初始化RxPermissions,何时何地请求权限,以及如何处理权限结果。而`PermissionHandler`可能是示例代码中的一个关键类,负责...

    Android6.0权限工具类

    以下是对"Android6.0权限工具类"的详细解释和相关知识点。 1. **运行时权限**:在Android 6.0之前,应用在安装时会自动获得清单文件中声明的所有权限。但在6.0之后,针对如读取联系人、访问位置等敏感权限,应用...

    android 6.0权限申请封装

    在Android 6.0(API级别23)中,谷歌引入了运行时权限管理系统,这是一项重要的安全更新,改变了之前版本中对应用权限的传统处理方式。在此系统下,应用程序不再在安装时获得所有请求的权限,而是需要在运行时根据...

    android 6.0权限动态申请DEMO

    下面我们将深入探讨Android 6.0权限动态申请的相关知识点。 1. **运行时权限模型**:在Android 6.0中,系统将权限分为两类:正常权限和危险权限。正常权限对应用功能的影响较小,系统在安装时自动授予;而危险权限...

    Android-android6.0权限管理

    Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样,一方面让用户更加容易的控制自己的隐私,一方面需要重新适配应用权限.

    Android6.0 权限处理

    综上所述,`Android6.0 权限处理`是Android开发中的重要环节,需要开发者对新的权限机制有清晰的理解和恰当的实现,以确保应用在不同Android版本上的功能完整性和用户体验。`TextPermission`这个类可能就是实现这一...

    android 6.0权限开发,拍照,相册崩溃问题

    本文将深入探讨Android 6.0权限开发中的拍照和相册崩溃问题,以及如何有效地解决这些问题。 ### 一、Android 6.0运行时权限 在Android 6.0之前,应用在安装时会一次性获取所有所需权限。但在6.0及更高版本中,用户...

    android 6.0权限动态申请demo

    在Android 6.0(API级别23)及以上版本,谷歌引入了运行时权限模型,对应用程序的权限管理进行了重大改革。之前,用户在安装应用时一次性授予所有权限,但在Android 6.0中,系统引入了动态权限申请机制,使得用户...

    android 6.0权限申请

    首先,我们需要理解Android 6.0权限系统的运作方式。在新的模型下,危险权限(如访问联系人、短信或位置等敏感信息)不再在安装时自动授予,而是需要在应用需要使用这些功能时动态请求。应用必须通过`ActivityCompat...

    Android6.0权限问题解决

    #### Android 6.0权限管理变化 - **按需授权**:用户不必在安装应用时同意所有的权限请求,而是在应用首次运行或特定功能被调用时才请求所需的权限。 - **权限组**:将相关的权限分组,比如位置权限组包含粗略位置...

    Android6.0权限处理Dome

    本教程的"Android6.0权限处理Dome"将指导您如何在Android 6.0及更高版本中正确地处理这些运行时权限。 一、运行时权限的重要性 在之前的Android版本中,应用在安装时会一次性获取所有声明的权限,无论用户是否真正...

    android6.0权限管理封装demo

    本“android6.0权限管理封装demo”就是针对这一功能的一个示例项目,旨在帮助开发者更好地理解和实施这一新机制。 首先,我们来了解一下Android 6.0权限管理的核心概念。在Android 6.0之前,如果一个应用在安装时...

    经典android6.0权限动态获取,绝对值得一看

    总的来说,Android 6.0权限动态获取是现代Android开发中的核心知识点,理解和熟练掌握它对于任何Android开发者来说都是必须的。通过实际操作和实践,开发者可以更好地适应新的权限模型,为用户提供更安全、更友好的...

    android6.0权限管理demo

    在这个"android6.0权限管理demo"中,我们将探讨如何适配这一新机制,确保应用在Android 6.0及更高版本上正常运行。 首先,我们需要理解的是,在Android 6.0之前,应用程序在安装时会一次性获取所有声明的权限。然而...

    android6.0 权限适配 demo

    本"android6.0 权限适配 demo"提供了一个使用permissionsdispatcher库进行权限管理的示例,帮助开发者更方便地处理运行时权限。 permissionsdispatcher是一个强大的、注解驱动的库,简化了Android 6.0及更高版本的...

    android 6.0 权限适配工具

    首先,我们要理解Android 6.0权限适配的核心概念:运行时权限。在API 23及以上,对于危险权限(如访问联系人、摄像头、位置等),应用必须在需要这些权限的时候请求用户的许可,而不是在安装时。这需要开发者在代码...

    android 6.0 权限适配Demo

    在Android 6.0(API级别23)及以上版本,系统引入了运行时权限模型,对应用程序的权限管理进行了重大改革。之前,用户在安装应用时一次性授予所有权限,但在Android 6.0中,部分敏感权限需要在运行时由用户动态授权...

    Android6.0权限管理解决办法demo实例

    本示例"Android6.0权限管理解决办法demo实例"将帮助开发者理解和处理这一变化。 一、运行时权限的重要性 运行时权限管理让应用更加尊重用户的隐私,因为用户可以知道哪些权限被应用请求,并且可以选择性地授予。...

    Android6.0权限管理工具类

    在Android 6.0(Marshmallow)版本之后,系统引入了一项重要的权限管理变革,即运行时权限(Runtime Permissions)。这个变化对应用开发者提出了新的挑战,因为用户不再在安装应用时一次性授予所有权限,而是可以在...

Global site tag (gtag.js) - Google Analytics