美文网首页
Android 6.0 运行时权限

Android 6.0 运行时权限

作者: JairusTse | 来源:发表于2017-04-01 18:38 被阅读189次

    Android M 运行时权限介绍

    Android 6.0 已经发布很长一段时间了,做Android开发的同学都知道Android 6.0 新增了运行时权限机制,见官网:Android 6.0 变更。 网上已经有很多成熟的解决方案,在这里记录一种方案,为了方便自己快速找回,其次也可以作为公司项目解决该问题的规范,毕竟几个人一起开发每个人都用自己的方案,代码会很难维护。

    对于我们开发者来说,最需要关注的是,Android M(API版本23)把权限分为 正常权限和危险权限。正常权限只需在Manifest声明就可以使用,危险权限则需要请求用户授权,用户也可以在权限管理中取消授权,如果程序处理不当,在调用没有权限的功能时就有可能会闪退。如果我们把 targetSdkVersion 调到 23 以下,所有权限在安装时都会被授权,但是用户还是可以手动取消授权,这样的话也会导致无法预料的后果。所以最好的方法是用户每次执行危险权限操作时,都先检查授权,如果没有授权,就弹框申请授权。

    危险权限有下面这些:

    权限组 权限
    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

    每个危险权限都有自己的权限组,如果用户授权了某个权限,同一个权限组里面的其他权限也会自动授予权限。

    动态申请权限的实现

    我们可以使用Android系统提供的方法实现权限申请,包括以下几个步骤:

    • 检查权限状态:ContextCompat.checkSelfPermission()
    • 申请授权:ActivityCompat.requestPermissions()
    • 处理回调:onRequestPermissionsResult()

    每次都自己处理授权还是比较麻烦的,所以可以考虑使用相关开源项目,我选择的是 RxPermissions ,一个基于 RxJava 的运行时权限检测框架,因为项目中也会使用到 RxAndroid 和 RxBus ,所以就选择了这个框架。

    RxPermissions 使用教程

    • 在 build.gradle 中:
    repositories {
        jcenter() // If not already there
    }
    
    dependencies {
        compile 'com.tbruyelle.rxpermissions:rxpermissions:0.9.3@aar'
        compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
    }
    
    
    • 在 AndroidManifest 中声明权限:
    <!-- 每个权限组选取一个权限 -->
    <uses-permission android:name="android.permission.READ_CALENDAR"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.BODY_SENSORS"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    
    
    • 在 Activity 或者 Fragment 中检查申请运行时权限:
    RxPermissions rxPermissions = new RxPermissions(this);
    
    //申请单个权限
    rxPermissions.requestEach(Manifest.permission.CALL_PHONE)
            .subscribe(new Action1<Permission>() {
                @Override
                public void call(Permission permission) {
                    if(permission.granted) {
                        //授权成功
    
                    } else if(permission.shouldShowRequestPermissionRationale == true){
                        //禁止授权
    
                    } else if(permission.shouldShowRequestPermissionRationale == false){
                        //禁止授权且不再询问
    
                    }
                }
            });
    
    //同时申请多个权限
    rxPermissions.request(Manifest.permission.READ_CALENDAR,
            Manifest.permission.CAMERA,
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.CALL_PHONE,
            Manifest.permission.BODY_SENSORS,
            Manifest.permission.SEND_SMS,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            .subscribe(new Action1<Boolean>() {
                @Override
                public void call(Boolean aBoolean) {
                    if(aBoolean) {
                        //全部已经授权
    
                    } else {
                        //起码有一个未授权
    
                    }
                }
            });
    
    

    上面的例子基本上可以解决开发中遇到的大部分运行时权限问题。

    自己封装的授权工具类

    • 里面的 T.show() 是我自己封装的 Toast 工具类,可以替换成 Toast.makeText()
    package com.jairus.utils;
    
    import android.app.Activity;
    import android.text.TextUtils;
    
    import com.tbruyelle.rxpermissions.Permission;
    import com.tbruyelle.rxpermissions.RxPermissions;
    
    import rx.functions.Action1;
    
    /**
     * 授权工具类
     * 作者: JairusTse
     * 日期: 18/5/12 18:44
     */
    public class PermissionUtil {
    
        //权限组,用户授权了某个权限,同一个权限组里面的其他权限也会自动授予权限。
        //这里每组选择一个权限,如果这个规则改变了,就要授权具体的权限。
        public static final String CALENDAR = "android.permission.READ_CALENDAR"; //日历
        public static final String CAMERA = "android.permission.CAMERA"; //相机
        public static final String CONTACTS = "android.permission.READ_CONTACTS"; //通讯录
        public static final String LOCATION = "android.permission.ACCESS_FINE_LOCATION"; //定位
        public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; //麦克风
        public static final String PHONE = "android.permission.CALL_PHONE"; //电话
        public static final String SENSORS = "android.permission.BODY_SENSORS"; //传感器
        public static final String SMS = "android.permission.READ_SMS"; //短信
        public static final String STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; //存储
    
        //用户禁止授权的默认提示语
        private static String SHOW_AGAIN_MESSAGE = "您拒绝了授权,无法正常使用";
        //用户禁止授权并且勾选了不再询问的默认提示语
        private static String NOT_SHOW_AGAIN_MESSAGE = "您禁止了授权,请在手机设置里面授权";
    
        /**
         * 请求危险权限的授权
         * @param activity
         * @param listener
         * @param args
         */
        public static void requestEach(Activity activity, final OnPermissionListener listener, String ... args) {
            requestEach(activity, SHOW_AGAIN_MESSAGE, NOT_SHOW_AGAIN_MESSAGE, listener, args);
        }
    
        /**
         * 请求危险权限的授权
         * @param activity
         * @param showAgainMsg 用户禁止授权的提示语
         * @param notShowAgainMsg 用户禁止授权并且勾选了不再询问的提示语
         * @param listener
         * @param args 权限组
         */
        public static void requestEach(Activity activity, final String showAgainMsg, final String
                notShowAgainMsg, final OnPermissionListener listener, String ... args) {
    
            if(args.length == 1) {
                //只请求一个权限
                requestSingleEach(activity, showAgainMsg, notShowAgainMsg, listener, args[0]);
            } else if(args.length > 1) {
                //请求多个权限
                requestMultipleEach(activity, showAgainMsg, listener, args);
            }
        }
    
        /**
         * 请求单个授权
         * @param activity
         * @param showAgainMsg 用户禁止授权的提示语
         * @param notShowAgainMsg 用户禁止授权并且勾选了不再询问的提示语
         * @param listener
         * @param permission 权限
         */
        private static void requestSingleEach(Activity activity, final String showAgainMsg, final String
                notShowAgainMsg, final OnPermissionListener listener, String permission) {
            RxPermissions rxPermissions = new RxPermissions(activity);
            rxPermissions.requestEach(permission)
                    .subscribe(new Action1<Permission>() {
                        @Override
                        public void call(Permission permission) {
    
                            if(permission.granted) {
                                //授权成功
                                if (listener != null) {
                                    listener.onSucceed();
                                }
                            } else {
                                if(permission.shouldShowRequestPermissionRationale == true) {
                                    //用户禁止授权提示
                                    T.show(!TextUtils.isEmpty(showAgainMsg) ? showAgainMsg : SHOW_AGAIN_MESSAGE);
                                } else if(permission.shouldShowRequestPermissionRationale == false) {
                                    //用户禁止授权并且勾选了不再询问提示
                                    T.show(!TextUtils.isEmpty(notShowAgainMsg) ? notShowAgainMsg : NOT_SHOW_AGAIN_MESSAGE);
                                }
    
                                if (listener != null) {
                                    listener.onFailed(permission.shouldShowRequestPermissionRationale);
                                }
                            }
    
    
                        }
                    });
        }
    
        /**
         * 同时请求多个授权
         * @param activity
         * @param showMsg 没有全部授权的提示语
         * @param listener
         * @param args 权限组
         */
        private static void requestMultipleEach(Activity activity, final String showMsg, final OnPermissionListener listener, String ... args) {
    
            RxPermissions rxPermissions = new RxPermissions(activity);
            rxPermissions.request(args)
                    .subscribe(new Action1<Boolean>() {
                        @Override
                        public void call(Boolean aBoolean) {
    
                            if(aBoolean) {
                                //全部已经授权
                                if (listener != null) {
                                    listener.onSucceed();
                                }
    
                            } else {
                                //起码有一个没有授权
                                if (listener != null) {
                                    listener.onFailed(true);
                                }
                                //授权失败提示
                                T.show(!TextUtils.isEmpty(showMsg) ? showMsg : SHOW_AGAIN_MESSAGE);
                            }
    
                        }
                    });
        }
    
        public interface OnPermissionListener {
            void onSucceed();
            void onFailed(boolean showAgain);
        }
    
    }
    
    
    • 调用方法
    /**
     * 获取存储和相机权限
     * @param activity
     */
    public void openPhotoPicker(Activity activity) {
        PermissionUtil.requestEach(activity, new
                PermissionUtil.OnPermissionListener() {
                    @Override
                    public void onSucceed() {
                        //授权成功
                        //do something...
                    }
    
                    @Override
                    public void onFailed(boolean showAgain) {
                        //授权失败
                    }
        }, PermissionUtil.STORAGE, PermissionUtil.CAMERA);
    }
    

    相关文章

      网友评论

          本文标题:Android 6.0 运行时权限

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