Android6.0运行时权限最佳实践

原创 2016年08月29日 10:46:05

一. 背景

6.0后Google对Android的权限管理做了大的调整,可以让用户自由的选择是否允许打开一些涉及个人隐私的权限。

二. 新的变化

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

  • Normal permission
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_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
  • Dangerous Permissions:
group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

可以通过adb shell pm list permissions -d -g进行查看。

看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,

那么有个问题:分组对我们的权限机制有什么影响吗?

的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。

三. 最佳实践

1.在AndroidManifest文件中添加需要的权限。

如果没有在Androidmanifest中添加声明,那么在申请该权限的时候将会报错。

2.检查权限

if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
}else{
    //
}

这里涉及到一个API,ContextCompat.checkSelfPermission 主要用于检测某个权限是否已经被授予,方法返回值为 PackageManager.PERMISSION_DENIED 或者 PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

3.申请授权

ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

该方法是异步的,第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。可以从方法名 requestPermissions 以及第二个参数看出,是支持一次性申请多个权限的,系统会通过对话框逐一询问用户是否授权。

4.处理权限申请回调

@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.

            } else {

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

对于权限的申请结果,首先验证 requestCode 定位到你的申请,然后验证 grantResults 对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么 grantResults 的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了~

5.附加

这个API主要用于给用户一个申请权限的解释,该方法只有在用户在上一次已经拒绝过你的这个权限申请。也就是说,用户已经拒绝一次了,你又弹个授权框,你需要给用户一个解释,为什么要授权,则使用该方法。然后我测试后没有成功,可能国内的rom会导致失败

// Should we show an explanation?
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.

}

6.完整使用

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    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 {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                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.
    }
}

四. Fragment中运行时权限的特殊处理

  • 在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的onRequestPermissionsResult
  • 如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,建议使用getParentFragment().requestPermissions方法,
    这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment
@Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
      List<Fragment> fragments = getChildFragmentManager().getFragments();
      if (fragments != null) {
          for (Fragment fragment : fragments) {
              if (fragment != null) {
                  fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
              }
          }
      }
  }

转载链接:http://blog.csdn.net/Just_Sanpark/article/details/52351008
参看博客:http://blog.csdn.net/lmj623565791/article/details/50709663

android6.0运行时权限完美封装

前几天看了郭大神的运行时权限的专讲,深受启发,由于现在基于目前项目中的运行时权限封装的还不是那么完美,趁着郭神建议的还是历历在目。于是把它完整的敲了下来。在加上自己的一些见解,封装成一个完整的demo...
  • androidstarjack
  • androidstarjack
  • 2017年01月03日 13:41
  • 1979

Android 6.0 运行时权限管理最佳实践

Android 6.0 运行时权限管理最佳实践 这是一篇迟来的文章,Android M已经发布一年多了(6.0的变化),在Android M中权限系统被重新设计,发生了颠覆性的变化,很多人把...
  • qq263229365
  • qq263229365
  • 2016年09月12日 18:16
  • 417

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

转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/50709663; 本文出自:【张鸿洋的博客】 一、概述 随着A...
  • lmj623565791
  • lmj623565791
  • 2016年02月22日 09:31
  • 238708

Android 6.0运行时权限请求示例

...
  • zxwd2015
  • zxwd2015
  • 2016年05月04日 09:28
  • 3497

Android 6.0 运行时权限处理解析

1.概述  不知道大家有没有遇到过这种情况,开发app的时候发现自己手机选择照片是正常的,测试那边的一台手机怎么搞都不行,然后查看版本之后才发现是6.0的手机。      随着Android ...
  • z240336124
  • z240336124
  • 2016年11月11日 17:55
  • 16795

Android 6.0 运行时权限介绍和使用方法及其封装

Android 6.0 新特性之运行时权限以及封装Easypermissions的使用方法介绍
  • fkq_2016
  • fkq_2016
  • 2017年01月12日 11:24
  • 2494

权限管理最佳实践:一,登录控制

转载来自:http://www.blogjava.net/Metadmin/archive/2010/09/01/330609.html 权限管理最佳实践:一,登录控制 -----------...
  • shehun11
  • shehun11
  • 2014年12月08日 16:16
  • 717

Android 6.0 运行时权限封装之路

前言时间如梭,总在不经意间流逝。经常会想,毕业到现在我都干了些什么,该有什么样的追求?运行时权限运行时权限是 Android 6.0 (SDK 23)新特性,更好的保护了用户的隐私。如果你build....
  • u012551350
  • u012551350
  • 2016年11月01日 17:42
  • 2319

适配android6.0:运行时权限检查机制

前言清明放假终于结束了,赶紧写点东西来脉动回来。这是一篇偏概念性的文章,文字偏多,所以别捉急,慢慢看。现在高版本的android系统市场占有率提升的非常快,这依赖于智能手机越来越便宜,越来越普遍,新手...
  • u011315960
  • u011315960
  • 2017年04月07日 15:52
  • 761

Android6.0运行时权限回调不执行的手机

使用android第一行代码(第二版)7.2节关于运行时权限的代码时,发现在真机魅族PRO6时若第一次在弹出的对话框中拒绝授权,则下次重新启动则不会再弹出是否授权对话框,并且此后状态为未授权状态!而模...
  • ruizhi51
  • ruizhi51
  • 2017年01月10日 23:38
  • 1390
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android6.0运行时权限最佳实践
举报原因:
原因补充:

(最多只允许输入30个字)