Android 6.0动态权限申请

1 篇文章 0 订阅
1 篇文章 0 订阅

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,也写了很多注释,这样能让大家看的更清楚,明白!

@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(){
    //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  申请的结果
 */
@Override
public 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);
    }

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值