Android6.0运行时权限处理架构搭建

Android6.0运行时权限处理架构搭建

介绍

对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

Dangerous Permissions:

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

我们发现危险的权限全是一组一组的,如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限。

申请权限的方式

1.对于6.0版本以下和6.0以上的Normal Permissions,还和以前一样

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

2.对于6.0以上的Dangerous Permission,就需要运行时申请权限

private void callPhone(){
    //需要申请的权限
    String[] usePermissions=new String[]{Manifest.permission.CALL_PHONE};
    //检测是否已经授权码
    int permission = ContextCompat.checkSelfPermission(this,
            Manifest.permission.CALL_PHONE);
    if(permission!= PackageManager.PERMISSION_GRANTED){
        //没有授权,申请权限
        ActivityCompat.requestPermissions(this,usePermissions,CALL_REQUEST_CODE);
    }else {
        //已经授权,拨打电话
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + "10086");
        intent.setData(data);
        startActivity(intent);
    }
}

申请权限时,用户可能授权,也可能拒绝,那我们怎么知道用户的选择呢?Activity提供了申请权限后的回调onRequestPermissionsResult,我们来看下它的使用:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    //判断请求码
    if(requestCode==CALL_REQUEST_CODE){
        //用户是否同意授权
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
            callPhone();
        }else {
            Toast.makeText(MainActivity.this, "Call Phone Permission Denied", Toast.LENGTH_SHORT).show();
        }
    }

}

原理很简单吧!但是每个需要权限的地方都这样调用,是不是有点麻烦?接下来我们就自己手写一个处理运行时权限的框架。

封装框架

我们先来看下libray的结构:

这里写图片描述

我们先看下注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionSuccess {
    /**
     * 请求码
     * @return
     */
    int requestCode() ;
}

基于运行时注解,下面我们来看下StonePermission:
public class StonePermission {
//参数
private Object mObject;//activity or fragment
private String[] mPermissions;
private int mRequestCode;//请求码

    private StonePermission(Object object){
        this.mObject=object;
    }

    /**
     * 直接请求权限
     * @param activity
     * @param requestCode
     * @param permissions
     */
    public static void requestPermission(Activity activity,int requestCode,String... permissions){
        realRequestPermission(activity,requestCode,permissions);
    }

    /**
     * 直接请求权限
     * @param fragment
     * @param requestCode
     * @param permissions
     */
    public static void requestPermission(Fragment fragment, int requestCode, String... permissions){
        realRequestPermission(fragment,requestCode,permissions);
    }

    /**
     * 关联调用类
     * @param activity
     * @return
     */
    public static StonePermission with(Activity activity){
        return new StonePermission(activity);
    }
    public static StonePermission with(Fragment fragment){
        return new StonePermission(fragment);
    }

    /**
     * 添加请求码
     * @param requestCode
     * @return
     */
    public StonePermission addRequestCode(int requestCode){
        this.mRequestCode=requestCode;
        return this;
    }

    /**
     * 添加申请权限
     * @param permissions
     * @return
     */
    public StonePermission permissions(String... permissions){
        this.mPermissions=permissions;
        return this;
    }

    /**
     * 执行请求权限
     */
    public void request(){
        realRequestPermission(mObject,mRequestCode,mPermissions);
    }

    /**
     * 正在处理请求权限的地方
     * @param object
     * @param requestCode
     * @param permissions
     */
    @TargetApi(Build.VERSION_CODES.M)
    private static void realRequestPermission(Object object, int requestCode, String... permissions){
        //1.如果小于6.0,直接调用成功方法
        if(!PermissionUtil.isOverMarshmallow()){
            PermissionUtil.executeSuccessMethod(object,requestCode);
            return;
        }
        //2.0 检查没有申请的权限
        List<String> deniedPermissions= PermissionUtil.checkAndObtainDeniedPermissions(object,permissions);
        if(deniedPermissions.size()>0){
            //3.0 申请权限
            ActivityCompat.requestPermissions(PermissionUtil.getActivity(object),deniedPermissions.toArray(new String[deniedPermissions.size()]),requestCode);
        }else {
            PermissionUtil.executeSuccessMethod(object,requestCode);
        }
    }






    /**
     * 在 onRequestPermissionsResult 中调用,处理权限申请结果
     * @param activity
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public static void onRequestPermissionsResult(Activity activity,int requestCode,String[] permissions,int[] grantResults){
        requestPermissionsResult(activity,requestCode,permissions,grantResults);
    }
    /**
     * 在 onRequestPermissionsResult 中调用,处理权限申请结果
     * @param fragment
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public static void onRequestPermissionsResult(Fragment fragment, int requestCode, String[] permissions, int[] grantResults){
        requestPermissionsResult(fragment,requestCode,permissions,grantResults);
    }

    /**
     * 真正回调的地方
     * @param object
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    private static void requestPermissionsResult(Object object,int requestCode,String[] permissions,int[] grantResults){
        List<String> deniedPermissions=new ArrayList<>();
        int length = grantResults.length;
        for (int i = 0; i < length; i++) {
            if(grantResults[i] != PackageManager.PERMISSION_GRANTED){
                deniedPermissions.add(permissions[i]);
            }
        }

        if(deniedPermissions.size() > 0){
            PermissionUtil.executeFaildMethod(object,requestCode);
        }else {
            PermissionUtil.executeSuccessMethod(object,requestCode);
        }
    }
}

上面就是提供给使用者的方法,是不是很简单?

接下来让我们一起来看下具体的使用:

private void callPhone(){
    //申请权限的方式:

        //第一种方式
        //StonePermission.requestPermission(this,CALL_REQUEST_CODE,Manifest.permission.CALL_PHONE);
        //第二种方式
        StonePermission.with(this)
                .addRequestCode(CALL_REQUEST_CODE)
                .permissions(Manifest.permission.CALL_PHONE)
                .request();
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    //将申请权限处理交给StonePermission
    StonePermission.onRequestPermissionsResult(this,requestCode,permissions,grantResults);
}

//成功授权后调用
@PermissionSuccess(requestCode = CALL_REQUEST_CODE)
public void success() {

    Intent intent = new Intent(Intent.ACTION_CALL);
    Uri data = Uri.parse("tel:" + "10086");
    intent.setData(data);
    startActivity(intent);

}
//申请权限失败后调用
@PermissionFail(requestCode = CALL_REQUEST_CODE)
private void  faild(){

    Toast.makeText(MainActivity.this,"申请权限失败",Toast.LENGTH_SHORT).show();

}

看到没,使用很方便呀!


下面给出处理框架的代码:点击查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值