首页 > 其他分享 >一行代码搞定Android 6.0动态权限申请

一行代码搞定Android 6.0动态权限申请

时间:2023-03-28 14:34:28浏览次数:37  
标签:搞定 CONTACTS 申请 用户 访问 应用 6.0 Android 权限


1、前言

从Android 6.0(API 23)开始,对系统权限做了很大的改变。在之前用户安装APP前,只是把APP需要使用的权限列出来给用户告知一下,APP安装后都可以访问这些权限。从6.0开始,一些敏感权限,需要在使用时动态申请,并且用户可以选择拒绝授权访问这些权限,已授予过的权限,用户也可以去APP设置页面去关闭授权。这对用户来说提高了安全性,可以防止一些应用恶意访问用户数据,但是对于开发来说,也增加了不少工作量,这块不做适配处理的话,APP在访问权限的时候会容易crash。

2、权限等级和权限组

权限主要分为normal、dangerous、signature和signatureOrSystem四个等级,常规情况下我们只需要了解前两种,即正常权限和危险权限。

2.1、正常权限

正常权限涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。应用声明其需要正常权限,系统会自动授予该权限。例如设置时区,只要应用声明过权限,系统就直接授予应用此权限。下面是截止到API 23的普通权限(需翻墙访问)

普通权限

普通权限

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

2.2、危险权限

危险权限涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如读取用户联系人,在6.0以上系统中,需要在运行时明确向用户申请权限。

2.3、权限组

系统根据权限用途又定义了权限组,每个权限都可属于一个权限组,每个权限组可以包含多个权限。例如联系人权限组,包含读取联系人、修改联系人和获取账户三个权限。 
* 如果应用申请访问一个危险权限,而此应用目前没有对应的权限组内的任何权限,系统会弹窗提示用户要访问的权限组(注意不是权限)。例如无论你申请READ_CONTACTS还是WRITE_CONTACTS,都是提示应用需要访问联系人信息。 
* 如果用户申请访问一个危险权限,而应用已经授权同权限组的其他权限,则系统会直接授权,不会再与用户有交互。例如应用已经请求并授予了READ_CONTACTS权限,那么当应用申请WRITE_CONTACTS时,系统会立即授予该权限。下面为危险权限和权限组:

权限组

权限

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

3、运行时请求权限

关于运行时请求权限,官网介绍的很清楚,也有很多其他文章介绍,这里只是简单罗列一下。

3.1、检查权限

应用每次需要危险权限时,都要判断应用目前是否有该权限。兼容库中已经做了封装,只需要通过下面代码即可:

int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

如果有权限则返回PackageManager.PERMISSION_GRANTED,否则返回PackageManager。PERMISSION_DENIED。

3.2、请求权限

当应用需要某个权限时,可以申请获取权限,这时会有弹出一个系统标准Dialog提示申请权限,此Diolog不能定制,用户同意或者拒绝后会通过方法onRequestPermissionsResult()返回结果。当用户拒绝过此权限申请时,再次申请Dialog上可以勾选不再提示,这种情况下,以后再申请权限不会弹Dialog直接返回拒绝。所以一些依赖某些敏感权限的应用,需要自己去处理,向用户解释 为什么需要此权限,说服用户授予权限。请求权限代码如下:

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

3.3、处理权限请求响应

当用户处理权限请求后,系统会回调申请权限的Activity的onRequestPermissionsResult()方法,只需要覆盖此方法,就能获得返回结果

@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;
        }
    }
}

3.4、考虑使用intent

有很多权限操作可以考虑调用其他应用,这样的话当前应用就不需要申请权限。例如想要获取相机照相,可以通过ACTION_IMAGE_CAPTURE唤起相机应用去完成,相机应用会把照片返回。同样拨打电话、访问联系人,都可以考虑使用类似方法。相比较其他应用,这类专门的应用做一些操作更容易让用户接受。

4、 关于国产机6.0以下系统

部分国产厂商定制了系统(例如小米、华为),在6.0以下系统就可以单独控制权限。但是通常它们处理的不够彻底,代码中判断是否授权的时候,返回的是已经授权。而真正去做操作的时候,却会因为没有权限导致应用crash。例如我曾遇到过的场景: 
* 访问联系人,可以拿到Cursor对象,但是cursor.moveToFirst()会返回false。 
* 访问摄像头时,获取到的Camera对象为空

所以在低版本手机上,不要以为拥有系统授权就万事大吉了,一定要多加条件判读和测试。

5、PermissionGrantor,一行代码搞定动态权限申请。

上面运行时请求权限中,我们看到了权限申请依赖于Activity和Fragment,和startActivityForResult()方法的使用类似,必须依赖于Activity和Fragment的回调方法。正常情况下还能满足需求,可是当申请的权限的代码在一个独立的模块中时,例如我封装了一个UI控件,控件中某个操作需要申请权限,或者项目采用了MVVM框架,需要在一些view类或者model类中申请权限,这是处理起来就会很麻烦。 
我在自己代码中就遇到类似情况,后面我采用了使用一个单独的Activity来申请权限,通过回调的方式通知业务层授权结果。感觉使用起来挺方便,就把它放到maven仓库中了,项目中通过加入如下依赖即可。

compile 'com.github.dfqin:grantor:2.1.0'

5.1 PermissionGrantor使用

申请权限很简单,只需要下面一句话即可。

PermissionsUtil.requestPermission(Activity activity, PermissionListener listener, 
    String[] permissions);

下面是一个申请摄像头的例子:

private void requestCemera() {
        if (PermissionsUtil.hasPermission(this, Manifest.permission.CAMERA)) {
            //有访问摄像头的权限
        } else {
            PermissionsUtil.requestPermission(this, new PermissionListener() {
                @Override
                public void permissionGranted(@NonNull String[] permissions) {
                   //用户授予了访问摄像头的权限
                }


                @Override
                public void permissionDenied(@NonNull String[] permissions) {
                    //用户拒绝了访问摄像头的申请
                }
            }, new String[]{Manifest.permission.CAMERA});
        }
    }
  • PermissionsUtil.requestPermission还有两个重载的实现。用户拒绝授权时,会有一个默认Dialog提示用户开通权限。这个Dialog的内容可以定制,也可以不显示此Dialog,详情见Github。有什么问题欢迎讨论交流。

标签:搞定,CONTACTS,申请,用户,访问,应用,6.0,Android,权限
From: https://blog.51cto.com/u_14523369/6154778

相关文章

  • Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar处理
    Toolbar作为ActionBar使用介绍本文介绍了在Android中将Toolbar作为ActionBar使用的方法.并且介绍了在Fragment和嵌套Fragment中使用Toolbar作为ActionBar使用时需要注意的......
  • Android、苹果logo背后的故事
    很多设计菜鸟刚刚学校毕业,幻想着自己设计出苹果、Android那样的图标,然后一夜成名,但是历史的真相并不光鲜的,不管是对已有logo进行加工还是设计重新上架的品牌logo,现实比......
  • 是时候来了解android7了:多窗口支持
    这篇文章开始,我们来了解一下android7的一些新特性,话说今年android7预览版本来的比以往都稍早一些,这样对于我们开发者来说算是一个好消息,我们可以有充足的时间来看......
  • Android控制ScrollView滑动速度
    前言由于各个Android平板触摸屏的材质不一样,滑动效果会有一些区别,有的比较灵敏,有的比较迟钝,这里就遇到了要求控制滑动速度的需求... 声明正文翻阅查找ScrollView的......
  • Android Studio 导入 Eclipse 的代码后,运行时中文显示乱码
    AndroidStudio导入Eclipse的代码后,先是编辑框中中文显示乱码。使用中的方法修改设置后显示不再乱码。但运行后,程序中的中文又出现乱码的情况。在的Andorid论坛中......
  • android 生命周期复习1
    Android开发之旅:组件生命周期(一)by吴秦引言应用程序组件有一个生命周期——一开始Android实例化他们响应意图,直到结束实例被销毁。在这期间,他们有时候处于激活状态,有时候......
  • com.gc.android.market.api;
    packagecom.gc.android.market.api;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;i......
  • 将已有数据表中的数据导入Android Studio
    1.首先在androidstudio中建个空表2.右键导出,名字保持一致  3.打开navicat,新建连接(SQLite),连接名随便取一个,数据库文件选择刚才导出的 4.右键选择导入向导,选择cs......
  • android实现多线程基础
    //创建线程类classMythreadextendsThread{@Overridepublicvoidrun(){//定义行为}}//实例化线程类MyThreadmt=newMyThread(“线程名称”);///......
  • Android开发 1_触控事件分发_触控在framework层上的注册
    前言此篇博客基于Android10版本,将讲解触控在系统层上的注册。Android的触控事件分发与其他事件分发来对比的话,可以说是很不一样的。如果你阅读此篇博客想去了解在fram......