美文网首页
运行时权限

运行时权限

作者: 永安里_ | 来源:发表于2018-11-01 15:05 被阅读0次

Android应用权限简要介绍

    1. 一个Android应用默认情况下是不拥有任何权限的, 一个应用是没有权利去进行一些可能会造成不好影响的操作的. 这些不好的影响可能是对其它应用,操作系统,或者是用户.如果应用需要一些额外的能力,则它需要在AndroidManifest.xml中静态地声明相应的权限.
      如果应用没有在manifest中声明权限, 却使用了相应的功能, 在调用到相应功能的时候, 将会抛出异常.
      比如程序要发送一个请求,却忘记加Internet权限, 那么在发送这个请求的时候程序就会抛出异常,一般不会catch这个异常,所以程序直接就崩溃了:
      Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
      Android 6.0开始, 一部分比较危险的权限需要在程序运行时显式弹框,请求用户授权.
      至于什么时候弹这个框,由应用程序自己决定.
      对于其他权限,认为不是很危险,所以仍然保持原来的做法,在用户安装应用程序时就予以授权.

Permission的保护等级

permission的保护等级通过protectionLevel属性设置, 共有4种: normal,dangerous,signature,signatureOrSystem.
签名相关的比较不常用, 剩下的两种是normaldangerous
总结下来就是: 所有的权限仍然在manifest中静态声明, normal权限的在安装的时候自动授权, 而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

可以总结为:
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权限状态都是打开.

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.checkSelfP
ermission(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(MainActivit
        y.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.

相关文章

  • Android - base - 运行时权限获取

    Android 6.0 引入的运行时权限机制 大纲 运行时权限机制简介 在程序运行时申请权限 #运行时权限机制简介...

  • 【Susen】目录

    Android运行时权限Android运行时权限列表EasyPermissionsAndPermissionPer...

  • 运行时权限

    1.运行时权限  以下权限需要进行运行时权限处理:  以CALL_PHONE为例,进行运行时权限申请:   第一步...

  • 无标题文章

    Android 6.0 运行时权限处理 标签(空格分隔): android 运行时权限介绍 Android 6.0...

  • 新特性与行为变更 -- 代码2

    运行时权限 运行时权限 在应用间共享文件 FileProvider 计划排定作业 JobIntentService...

  • Android优雅地申请动态权限

    Android6.0以上的系统中,引入了运行时权限检查,运行时权限分为正常权限和危险权限,当我们的App调用了需要...

  • Android 6.0变更一览

    Android 6.0 API 运行时权限 运行时申请权限,需要targetSDK>=23,并且手机的系统大于6....

  • 版本升级坑

    Android6.0 1.运行时权限 Android 6.0 运行时权限管理最佳实践:https://blog.c...

  • Android-6.0 棉花糖权限的那点事

    Android6.0引入了全新的权限管理方式,也就是运行时权限,至于什么是运行时权限,我们先看一下6.0以前的权限...

  • Android 6.0 运行时权限处理完全解析

    Android 6.0 运行时权限处理完全解析 运行时权限的变化及特点 对于6.0以下的权限及在安装的时候,根据权...

网友评论

      本文标题:运行时权限

      本文链接:https://www.haomeiwen.com/subject/rlatxqtx.html