Android 6.0 动态权限机制

来源:互联网 发布:淘宝卖的信用卡套现 编辑:程序博客网 时间:2024/05/22 16:03

一、权限分类

1.Dangerous permissions

  • CALENDAR
    • READ_CALENDAR
    • WRITE_CALENDAR
  • 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

2.Normal Permissions

  • ACCESS_LOCATION_EXTRA_COMMANDS
  • ACCESS_NETWORK_STATE
  • ACCESS_NOTIFICATION_POLICY
  • ACCESS_WIFI_STATE
  • BLUETOOTH
  • BLUETOOTH_ADMIN
  • BROADCAST_STICKY
  • CHANGE_NETWORK_STATE
  • CHANGE_WIFI_MULTICAST_STATE
  • CHANGE_WIFI_STATE
  • DISABLE_KEYGUARD
  • EXPAND_STATUS_BAR
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • REQUEST_INSTALL_PACKAGES
  • SET_ALARM
  • SET_TIME_ZONE
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • UNINSTALL_SHORTCUT
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

二、动态获取权限

从Android6.0开始,用户对App的授权发生在App运行的时候而不是App安装的时候,这就意味着用户授权不再是当安装App或者更新App时同意授权才能进行安装。

系统权限被分为正常权限危险权限两类(见一、权限分类):
- 正常权限不会直接威胁到用户隐私,当使用正常权限时只需要在Manifest文件中声明,系统自动进行授权。
- 危险权限涉及到用户隐私数据,当使用危险权限时,不仅仅是在Manifest文件中声明,而且还需要用户明确同意后才可以使用。

无论是正常权限或者危险权限,都需要在Manifest中声明,但是由于不同的系统版本以及App的TargetSDK不同,会有不同的影响:
- 若设备运行的是Android5.1之前的系统,或者App的TargetSDK为22之前的,当你在Manifest中声明使用了危险权限时,用户只能在安装App时同意授权才能进行安装,否则用户不同意授权则无法安装App;
- 若设备运行的是Android6.0之后的系统,或者App的TargetSDK为23之后的,当你在Manifest中声明使用了危险权限时,必须在App运行时请求所有危险权限的授权且用户可选择是否授权危险权限的使用。当用户不授权危险权限的使用时,App仍可以在有限的权限条件下运行。

需要注意的是,从Android 6.0 (API level 23)后用户可以对App的权限进行管理,无论App的Target是否为低的API Level。所以需要开发人员对App进行测试以确保当某些权限被用户禁止后仍然能以合适的表现方式运行,而不是崩溃!!!

1.检查权限

当执行需要某个危险权限的操作时,必须每次检查是否被授权了该权限。用户可任意授权或者禁止授权,即使昨天授权了危险权限的使用,今天也可以禁止,所以检查权限是必要的。

通过调用ContextCompat.checkSelfPermission()进行权限检查,以检查WRITE_CALENDAR权限为例:

// 确保thisActivity为当前的Activityint permissionCheck = ContextCompat.checkSelfPermission(thisActivity,Manifest.permission.WRITE_CALENDAR);switch(permissionCheck){case PackageManager.PERMISSION_GRANTED:    // TODO 权限被授权使用    break;case PackageManager.PERMISSION_DENIED:    // TODO 权限被禁止使用,App需要明确向用户请求该权限的使用    break;}

2.请求权限

若App在Manifest声明使用危险权限时,必须向用户请求这些危险权限的使用权。Android提供一些方法方便开发者请求权限的使用,当这些方法被调用时,将弹出一个标准的无法自定义的Android对话框。

(1)向用户解释使用某些危险权限的原因

在某些情况下,你可能需要帮助用户理解为什么App需要使用这些权限,所以在App请求权限之前,需要考虑向用户提供使用权限的相关解释,而这些解释尽量言简意赅且便于用户理解。

这里建议开发者在用户已经禁止了危险权限的请求时再向用户提供权限使用的解释(最优的方法是在请求权限时就对用户进行解释)。

Android提供的shouldShowRequestPermissionRationale()方法可以帮助开发者确定用户何时需要一个对危险权限授权的解释。当App已经请求过权限且被用户禁止了的时候,该方法返回true,此时就需要向用户进行权限使用的解释;当用户在权限请求对话框中禁止App权限的使用且选择了“Don’t ask again”的选项时,该方法返回false;还有就是当设备策略(a device policy)禁止App使用权限时,该方法也会返回false。

(2)请求需要的权限

通过调用requestPermissions()方法请求需要的权限。

当调用该方法传递所需权限的同时,也需要传递一个整型RequestCode来标记该权限的请求以区分不同的权限请求。

该方法为异步方法,当用户对权限请求对话框进行响应后,系统会立刻回调App中特定的回调方法并传入结果数据(见“(3)处理权限请求响应”),结果数据包括之前传递的RequestCode。
以下为示例代码:

// 以下thisActivity为当前Activity// 权限被禁止时的操作if (ContextCompat.checkSelfPermission(thisActivity,Manifest.permission.READ_CONTACTS)         != PackageManager.PERMISSION_GRANTED) {     // 调用该方法判断是否需要给出权限使用的解释    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 {        // 不需要给出权限使用的解释时,进行请求权限        ActivityCompat.requestPermissions(                thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},                REQUEST_CODE);    }}
(3)处理权限请求响应

当用户对权限请求对话框进行响应后,系统会回调App中onRequestPermissionsResult() 方法并传入结果参数数据,开发者需要覆盖该方法以处理判断权限是否被授权使用,此外,开发者可以通过返回的RequestCode区分不同权限请求的返回结果。
以下为示例代码:

@Overridepublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {    switch (requestCode) {        case REQUEST_CODE: {            // 若请求被取消,结果数组为空            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // 权限请求中所请求的第一个权限被授权使用,可以进行下一步操作            } else {                // 权限被禁止时的操作            }            return;        }        // 其它case来处理不同的权限请求响应    }}

需要注意的是,权限请求对话框只显示App所请求的单个权限所属的权限组而不是具体到某个权限,所以用户确认授权后是给予App使用权限组中的所有权限,而不仅仅是权限组中的单个权限的使用。例如,在Manifest中声明使用READ_CONTACTS和WIRTE_CONTACTS两个权限(这两个权限属于CONTACTS权限组),当App请求READ_CONTACTS权限且用户同意授权后,再请求WRITE_CONTACTS权限时系统不会与用户进行交互而是直接同意授权。

但是,App仍然需要明确的请求每个权限,而不仅仅是依赖于用户同意某个权限组而不去请求权限组中的某个权限,因为权限组中的单个权限可能在未来的Android releases中改变。

当系统要求用户授权权限时,用户有权选择让系统不再弹框提示。既然这样,无论App什么时候调用requestPermissions()请求权限,系统都会立刻否定该请求并在回调方法中返回PERMISSION_DENIED。这就意味着App调用requestPermissions()是没办法确保与用户的直接交互已经发生。

后记

第一次发博客有点紧张,有不足的地方请大家指出,我会及时更正。本篇文章是参考Android官方文档一字一句进行翻译并添加自己的理解,有哪里不对的地方还望大家指出,谢谢!同时转载记得注明出处哦!http://blog.csdn.net/linzerocandy/article/details/52355355

本文参考Demo:https://github.com/ZeroCandy/Demo(P.S.Demo里都是一些小Demo,平常写着玩仅供参考)

0 0
原创粉丝点击