Android 6.0动态权限申请

来源:互联网 发布:苹果版解压缩软件 编辑:程序博客网 时间:2024/06/10 22:07

Android 6.0运行时权限动态申请处理

最近需要在项目中对android 6.0以上的手机做权限处理,所以抽了个时间,将大于或等于6.0以上的权限处理做一个总结!

android 在6.0以后,将权限分为两类,分别为Normal Pemission和Dangerous Permission,Normal Permission不需要用户在操作的时候进行授权,例如最常用的访问网络的权限;Dangerous Permission 则不同,其涉及到了用户的隐私,必须在用户操作的过程中,进行授权通过了,才可以进行某些预定的操作,例如获取手机联系人,若用户没有对此进行授权,则会导致程序无法获取到手机上的联系人。而当用户拒绝该权限之后,没有在设置中将其打开,则会一直处于权限拒绝状态,所以,我们需要对此进行处理。

下面,将通过一个打电话的例子来演示操作。

在6.0以下的手机中,我们可以直接通过Intent的方式来拨打电话,代码如下:

    private void call(){            Intent intent = new Intent(Intent.ACTION_CALL);            Uri data = Uri.parse("tel:" + mPhone);            intent.setData(data);            startActivity(intent);        }

而在6.0以上的手机中,我们则需要通过一些步骤,确定当前程序是否拨打电话的权限,如果有权限,则可以和如上方式一样直接调用call()方法来打电话,但是若检测到当前程序没有拨打电话的权限。那么,我们需要通过如下操作来进行处理:

1:申请用户授权拨打电话的权限2:若授予了该权限,则调用call()方法进行拨打电话3:若用户拒绝了,则我们需要进行一些其他的操作,来告诉用户,该功能不可用。

下面,我将具体的完整流程整理了下(画图技术太烂,不要在意,哈哈,希望大家都能看明白我画的是啥玩意儿 ^_^ ):

————————————-一条有逼格的分界线,下面开始撸码—————————————–

首先,先完成功能上的操作,具体代码如下,代码中,打了很多的Log,也写了很多注释,这样能让大家看的更清楚,明白!

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    initView();}private void initView(){    call = (TextView) findViewById(R.id.call);    call.setOnClickListener(new View.OnClickListener() {        @Override        public void onClick(View v) {            //检查权限            checkPermission();        }    });}private void checkPermission(){    //1:判断当前手机系统是否大于或等于6.0    //2:若大于6.0,则检查是否由打电话的权限    //3:若没有打电话的权限  则申请打电话的权限    //4:若有打电话的权限  则直接打电话    //5:若当前小于6.0,则直接打电话    if(Build.VERSION.SDK_INT >= M ){        Log.e(TAG,"版本大于等于6.0");        //checkSelfPermission方法用于检测程序是否含有某项权限         //参数一:当前的上下文对象        //参数二:需要检测的权限        /**         * checkSelfPermission方法用于检测程序是否含有某项权限         * 参数一:当前的上下文对象         * 参数二:需要检测的权限         *          * 该方法得返回值为int类型,有两种值,分别为:         * 1:PackageManager.PERMISSION_DENIED  该权限被拒绝         * 2:PackageManager.PERMISSION_GRANTED  该权限被授予         */        int isPermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.CALL_PHONE);        if(isPermission == PackageManager.PERMISSION_GRANTED){            //该权限已被授予            Log.e(TAG,"该权限已被授予");            call();        }else{            Log.e(TAG,"该权限已被拒绝");            //申请权限            /**             * ActivityCompat.requestPermissions()方法用于申请权限             * 参数一:Activity             * 参数二:需要申请的权限,其为一个数组,可同时传入多个将要申请的权限             * 参数三:请求码,用于在请求完成之后的回调中使用             */            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CALL_PHONE},REQUEST_CODE);        }    }else {        call();    }}private void call(){    Intent intent = new Intent(Intent.ACTION_CALL);    Uri data = Uri.parse("tel:" + mPhone);    intent.setData(data);    startActivity(intent);}/** * 该方法即为申请权限的回调方法  无论申请成功或者失败  都会回调这个函数 * @param requestCode  上文中提到的请求码 * @param permissions  申请的权限 * @param grantResults  申请的结果 */@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults);    if(requestCode == REQUEST_CODE){        if(grantResults != null && grantResults.length>0){            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){                Log.e(TAG,"权限已被授予,此时可以拨打电话了");                call();            }else{                Toast.makeText(this,"您拒绝了拨打电话的权限!",Toast.LENGTH_SHORT).show();            }        }    }}

到此 动态权限的功能也就处理完毕了!

你以为我会说结束了么,哈哈哈,想多了吧,老铁!^_^

不知道读到这里,大家有没有一个问题:难道我一涉及到危险权限的操作,就要写这么多代码来处理吗?这样会不会很丧心病狂啊!

下面,高大上的东西来了:封装一个高大上的权限申请框架!

写博客之前,也看了好些技术求人的方案,最终选择的是一个注解 + 反射的方案来处理

下面直接贴代码,注释已经很详细了,相信大家能看明白!

  1. PermissionHelper:权限问题集中在此处理

    package com.justh.dell.util;import android.app.Activity;import android.app.Fragment;import android.support.v4.app.ActivityCompat;import java.util.ArrayList;import static com.justh.dell.util.PermissionUtils.getDeniedPermissions;/** * Created by DELL on 2017/7/29. * 权限处理类 */public class PermissionHelper {    /**     * 需要的参数:     * 1:申请全的的Activity 或 fragment     * 2:需要申请的权限     * 3:申请权限的请求码     */    private Object mObject;    private String[] permissions;    private int requestCode;    private PermissionHelper(Object mObject){        this.mObject = mObject;    }    //第一种使用方式,直接传入参数      public static PermissionHelper requestPermission(Activity activity,String[] permissions,int requestCode){        return PermissionHelper.with(activity).requestCode(requestCode).requestPermission(permissions);    }    public static PermissionHelper requestPermission(Fragment fragment,String[] permissions,int requestCode){        return PermissionHelper.with(fragment).requestCode(requestCode).requestPermission(permissions);    }    //第二种方式:链式调用    public static PermissionHelper with(Activity activity){        return new PermissionHelper(activity);    }    public static PermissionHelper with(Fragment fragment){        return new PermissionHelper(fragment);    }    public PermissionHelper requestCode(int requestCode){        this.requestCode = requestCode;        return this;    }    public PermissionHelper requestPermission(String... permissions){        this.permissions = permissions;        return this;    }    //发起操作    public void request(){        /**         * 1:判断当前手机系统是否大于或等于6.0         */        if(!PermissionUtils.isMoreThanM()){            /**             * 当前系统小于6.0,则直接执行需要执行的方法,如拨号             * 由于需要执行的方法是不确定的  但Activity或fragment是已知的,             * 所以这里使用注解 + 反射 的方式来获取到需要执行的方法并执行操作             */            PermissionUtils.executeSuccesseMethod(mObject,requestCode);        }else{            /**             * 当前系统大于 或等于6.0             * 1:判断这些权限中,是否有被被拒绝的权限             * 2:若有,则向用户申请权限             *      2.1:若申请成功  则执行成功的方法             *      2.2:若申请失败  则执行一些提示操作             * 3:若无,则直接执行成功的方法                  */            ArrayList<String> deniedPermissions = getDeniedPermissions(mObject,permissions);            if (deniedPermissions.size() > 0){                //有被用户拒绝的权限  需要向用户提交申请                ActivityCompat.requestPermissions(PermissionUtils.getActivity(mObject),                        deniedPermissions.toArray(new String[deniedPermissions.size()]),requestCode);            }else{                //无被拒绝的权限                PermissionUtils.executeSuccesseMethod(mObject,requestCode);            }        }    }    public static void requestPermissionsResult(int requestCode, String[] permissions,Object object) {        //再去获取以下  看看是否还有被用户拒绝的权限           ArrayList<String> deniedPermission = PermissionUtils.getDeniedPermissions(object,permissions);        if(deniedPermission.size() == 0){            //用户已授权所有权限            PermissionUtils.executeSuccesseMethod(object,requestCode);        }else{            /**             * 还是有部分权限被用户拒绝了             * 执行一个类似提示或捕获异常等的方法               * 视情况而定             *              * 这里弹出一个Toast              * 套路一样  还是使用 注解 + 反射的方法             */            PermissionUtils.executeFailedMethod(object,requestCode);        }    }}

2.PermissionUtils: PermissionUtils的辅助类

    package com.justh.dell.util;    import android.app.Activity;    import android.app.Fragment;    import android.content.pm.PackageManager;    import android.os.Build;    import android.support.v4.content.ContextCompat;    import android.util.Log;    import java.lang.reflect.InvocationTargetException;    import java.lang.reflect.Method;    import java.util.ArrayList;    /**     * Created by DELL on 2017/7/29.     */    public class PermissionUtils {        private static final String TAG = PermissionUtils.class.getSimpleName();        /**         *          * @return true or false         * 如果大于或等于   返回true         * 否则  返回 false         */    public static boolean isMoreThanM(){        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;    }    /**     * 执行方法     * @param object     * @param requestCode     */    public static void executeSuccesseMethod(Object object, int requestCode) {        Class clz =  object.getClass();        //通过反射获取到这个类的全部方法        Method[] methods = clz.getDeclaredMethods();        //遍历所有方法,寻找被我们加了注解的方法        for (Method method : methods){            Log.i(TAG,method+"");            PermissionSucceed correctMethod = method.getAnnotation(PermissionSucceed.class);            //从注解中获取到requestCode 比较是否与参数中的request一致,若一致,则可确定就是该方法            if(correctMethod != null){                if(correctMethod.requestCode() == requestCode){                    //执行该方法                    executeMethod(object,method);                }            }       }    }    //执行方法    public static void executeMethod(Object object,Method method){        try {            /**             * 代表允许执行私有方法               * 若不加这句代码              * 在执行私有方法时,是会出问题滴             */            method.setAccessible(true);            method.invoke(object,new Object[]{});        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }    public static ArrayList<String> getDeniedPermissions(Object object, String[] permissions) {        //遍历检测所有权限  将未授权的权限添加到集合中去 并返回        ArrayList<String> deniedPermissions = new ArrayList<>();        for (String permission : permissions){            if(ContextCompat.checkSelfPermission(getActivity(object),permission) != PackageManager.PERMISSION_GRANTED){                //即为被拒绝的权限 将其添加到集合中  后面统一处理                deniedPermissions.add(permission);            }        }        return deniedPermissions;    }    /**     *      * @param object  activity or fragment      * @return Activity     */    public static Activity getActivity(Object object){        if(object instanceof Activity){            return (Activity) object;        }else if(object instanceof Fragment){            return ((Fragment) object).getActivity();        }        return null;    }    public static void executeFailedMethod(Object object, int requestCode) {        Class clz = object.getClass();        Method[] methods = clz.getDeclaredMethods();        for (Method method : methods){            PermissionFailed permissionFailed = method.getAnnotation(PermissionFailed.class);            if(permissionFailed != null){                if(permissionFailed.requestCode() == requestCode){                    executeMethod(object,method);                }            }        }    }}

3.PermissionSucceed :成功时的注解(相当于TAG的作用)在含有全部权限授权的情况下使用,作用在执行成功的方法的头部
package com.justh.dell.util;

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by DELL on 2017/7/29. * 执行正确的操作 */@Target(ElementType.METHOD)//代表其作用于方法中 @Retention(RetentionPolicy.RUNTIME) //表示在运行时起作用public @interface PermissionSucceed {    public int requestCode();}

4.PermissionFailed:失败时的注解 在程序含有未被用户授权的危险权限时使用,作用在执行失败的方法的头部

package com.justh.dell.util;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by DELL on 2017/7/29. * 执行某些提示 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface PermissionFailed {    public int requestCode();} 

5:在Activity中调用:

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    private void initView(){        call = (TextView) findViewById(R.id.call);        call.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //检查权限                checkPermission();            }        });    }    private void checkPermission(){        //发起请求        PermissionHelper.with(this).requestCode(REQUEST_CODE).requestPermission(Manifest.permission.CALL_PHONE).request();    }    @PermissionSucceed(requestCode = REQUEST_CODE)    private void call(){        Intent intent = new Intent(Intent.ACTION_CALL);        Uri data = Uri.parse("tel:" + mPhone);        intent.setData(data);        startActivity(intent);    }    @PermissionFailed(requestCode = REQUEST_CODE)    private void showToast(){        Toast.makeText(this,"您拒绝了拨打电话的权限!",Toast.LENGTH_SHORT).show();    }    /**     * 该方法即为申请权限的回调方法  无论申请成功或者失败  都会回调这个函数     * @param requestCode  上文中提到的请求码     * @param permissions  申请的权限     * @param grantResults  申请的结果     */    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        PermissionHelper.requestPermissionsResult(requestCode, permissions, this);    }

到此 就真的结束了 !咵咵咵写了这么多,感觉都不知道到写了啥,希望大家能看懂吧!

如若碰到什么问题或疑问的,可以通过评论进行交流,谢谢!