Android 6.0 权限行为变更详解

342 阅读6分钟

Android 6.0 权限行为变更

运行时权限说明

Android 6.0 引入了一种新的权限模式,使得用户可以在运行 APP 的时候对一些比较敏感的权限进行管理。这种新的模式可以让用户更好的了解和控制权限,同时为应用精简了安装和自动更新过程。

对于以 Android 6.0 或者更高版本为目标平台的应用,务必在运行的时候检查和请求权限(针对一些危险权限)否则,如果直接调用相关需要特殊权限的方法的话,会导致 APP 的崩溃。检查是否已经拥有权限了可以使用方法 checkSelfPerssion() 如果要请求权限使用方法 requestPermissions 方法。这两个方法都是在 API 23 后引入的,也就是说在之前的 API 中是没有这俩方法的。如果你的 minSdkVersion 设置的值是在 23 以下的话,直接调用上面的方法会有这种提示 Call requires API level 23 (current min is 21):........

提醒

提示说的很清除了,调用这种方法是需要 API 23 的,而当前 min 是 21,也就说明你的 APP 是可以运行在 Android 5.0 系统的手机上面的,然而 checkSelfPermission 方法是在 Android 6.0 才引进的,所以会有这种错误的提示。那么毕竟现在 Android 5.0 的系统还是有很多用户量的,这个时候我们应该怎么办呢?这个时候 ActivityCompatContextComapt 就派上用途的,这个两个类是 Android API 特意为了考虑软件向前兼容考虑的。

什么样的权限需要请求用户授权呢?

对于一些敏感的用户数据,比如一些牵扯到读写功能的权限是需要向用户请求权限的。对于一些无关紧要的权限,可以在安装的时候系统自动将这些权限授予了我们的应用。

普通权限,如果应用程序在其清单中声明了,则系统会在安装时自动授予应用程序该权限,系统不会提示用户授权普通权限,用户也无法撤销

  • 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
  • FOREGROUND_SERVICE
  • GET_PACKAGE_SIZE
  • INSTALL_SHORTCUT
  • INTERNET
  • KILL_BACKGROUND_PROCESSES
  • MANAGE_OWN_CALLS
  • MODIFY_AUDIO_SETTINGS
  • NFC
  • READ_SYNC_SETTINGS
  • READ_SYNC_STATS
  • RECEIVE_BOOT_COMPLETED
  • REORDER_TASKS
  • REQUEST_COMPANION_RUN_IN_BACKGROUND
  • REQUEST_COMPANION_USE_DATA_IN_BACKGROUND
  • REQUEST_DELETE_PACKAGES
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
  • SET_ALARM
  • SET_WALLPAPER
  • SET_WALLPAPER_HINTS
  • TRANSMIT_IR
  • USE_FINGERPRINT
  • VIBRATE
  • WAKE_LOCK
  • WRITE_SYNC_SETTINGS

危险权限:危险权限涵盖应用程序需要涉及用户私人信息的数据或资源的区域,或者可能会影响用户存储数据或其他应用程序的操作。这种权限就需要动态申请了

许可组 权限
CALENDAR READ_CALENDAR``WRITE_CALENDAR
CALL_LOG READ_CALL_LOGWRITE_CALL_LOGPROCESS_OUTGOING_CALLS
CAMERA CAMERA
CONTACTS READ_CONTACTS``WRITE_CONTACTS``GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION``ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE``READ_PHONE_NUMBERS``CALL_PHONE``ANSWER_PHONE_CALLS``ADD_VOICEMAIL``USE_SIP
SENSORS BODY_SENSORS
SMS SEND_SMS``RECEIVE_SMS``READ_SMS``RECEIVE_WAP_PUSH``RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE``WRITE_EXTERNAL_STORAGE

如何获取权限

应用必须通过 <users-permission> 在应用清单中标志来声明 APP 所需要的权限。例如,需要发送 SMS 消息的应用程序需要在清单文件中声明下面的权限:

<uses-permission android:name = “android.permission.SEND_SMS” />

如果在清单中列出的权限,不会对用户的隐形或者设备造成太大的风险,这个时候系统会自动给你的应用授权。如果在应用清单中列出了危险权限(可能影响用户隐私或者设备正常运行的权限)这个时候就需要在代码中调用向对应的 API 动态请求获取权限了。

请求提示危险权限

只有危险权限才需要我们在代码中动态向用户请求,Android 要求用户授予危险权限的方式是和用户设备上运行的 Android 系统的版本以及我们的应用所针对的系统版本有关的。

运行时请求(Android 6.0以及更高版本)

由于国内 Android 系统都是在正宗 Android 系统的基础上二次开发的,所以在这种特性的问题上会和正宗的 Android 系统有不同。
举个例子 :比如你将你开发的 APP 的 targetSDKVersion 设置为 23 以下的话,如果在原生的 Android 系统上,运行的时候是不需要运行时请求危险权限的,因为这个特性是在 API 23 才加入的。但是如果你这样设置的话,在国内的手机上运行还是有问题的(比如小米手机)如果你没有动态申请危险权限,会导致你的 APP 崩溃,也就是说 targetSDKVersion 这个属性对国内的非原生 Android 手机不是那么管用。针对国内的手机建议是:最好 targetSDKVersion 的版本是是最新的,代码里面的 API 也要对应 targetSDKVersion 版本的 API 这样才能保证最大程度的兼容 这句话可能有点不好理解,我再举个例子:比如,在小米手机 8.0 系统上,你设置了 targetSDKVersion 为 22,这个时候如果是原生 Android 系统的话是不需要再动态申请权限了,但是在小米上还是需要的的,这个时候你调用 checkSelfPermission 等等动态调用权限的方法,你会发现还是会出现各种问题,当你把 targetSDKVersion 调整为 23 就可以了。这就是上面那句话的意思。

在需要一些危险权限的时候,必须要向用户动态请求,用户会看到一个系统的对话框,告诉用户这个应用程序需要访问那个权限,让用户选择 拒绝 或者 允许,如果用户拒绝权限请求,则下次应用请求权限的时候,弹出的对话框会增加一个 不再提醒 选择框,如果用户选择 不再询问 并点击 拒绝 ,则系统不会再弹出权限请求框

请求权限弹出框

注意这个对话框,不同的定制系统是不一样,是不能更改的

实际运用

上面讲了那么多概念性的内容,现在来进行实际运用

比如,我的下一步操作需要读写内存卡权限,那么代码如何书写

  1. 首先应该检查应用有没有获取此权限
  2. 判断是否需要展示解释
  3. 请求权限
  4. 处理回调

下面就一步一步的来详细说明

// 判断应用有没有获取此权限
if(ContextCompat.checkSelfPermission(Activity.this,Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
    // 没有获得权限
    // 判断是否需要展示解释
    if(ActivityCompat.shouldShowRequestPermissionRationale(Activity.this,"权限名字")){
        // 说明用户之前已经拒绝过了,这个时候再发起权限请求,最好
        // 向用户解释一下为什么要获取这个权限
    }else{
        // 正式发出权限请求
        ActivityCompat.requestPermissions(Activity.this,"权限名数组");
        
    }
        
    
}else{
    // 已经取得权限了
    do.......
}

// 处理结果回调
public void onRequestPermissionResult(int requestCode,@NonNull String[] permissions,@NonNull int [] grantResults){
   // 根据 grantResults 的结果来判断是否取得权限
    
}

好了,以上就是最基本的运用方法,其他的一些框架都在这个基础上封装的。
注意: 一定要按照上面的顺序来进行(缺少任何步骤都不行),否则在有些系统的手机上会有各种问题。

个人创建了一个微信群,里面有行业的大佬,会不断的分享一些优质文章,交流技术,谈天说地。想要加入的可以添加我好友,拉你进群。早点找到组织,困惑会在交流中消失!

picture