Android进阶之6.0运行时权限处理

1 概述

对于6.0的几个主要的变化,查看查看官网的这篇文章Runtime Permissions,其中包含Runtime Permissions。
  Android 6.0系统中需要动态授权的危险权限表,一共是9组27个权限。当我们在动态授权时,只要用户允许了一组当中的一个权限,那么系统默认会通过整组的权限,所以我们在动态授权时每组只要将一个permission进行授权即可。
在这里插入图片描述
  具体的权限说明,参考:android6.0获取通讯录权限

2 运行时权限的变化及特点

在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。
  新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

3 授予单个权限的Demo

/**
 * 个人中心页面
 * Created by chenliguan on 16/6/29.
 */
public class PersonActivity extends AppCompatActivity {
    private static final int PERMISSIONS_CALL_PHONE = 1;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()) {    
             case R.id.vContact:
                  callPhone();//拨号
                  break;
                  
             default:
                  break;
        }
    }

    /**
     * 拨号
     */
    public void callPhone() {
		/**
		 * 1.检查权限
		 */
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
			/**
			 * 2.申请授权
			 * 第二个参数是需要申请的权限的字符串数组
			 * 第三个参数为requestCode,主要用于回调的时候检测
			 */
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.CALL_PHONE}, PERMISSIONS_CALL_PHONE);
        } else {
            submitPhoneCall();
        }
    }

    /**
     * 处理权限申请回调
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_CALL_PHONE: 
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                
                submitPhoneCall();//调用拨号界面,不直接拨打电话
            } else {
                showShortToast(R.string.toast_permission_no);
            }
            return;
        
        default:
            break;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    /**
     * 调用拨号界面,不直接拨打电话
     */
    private void submitPhoneCall() {
        //Intent.ACTION_CALL 直接拨打电话
        intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + Config.CLIENT_SERVER.replace("-", "")));
        startActivity(intent);
    }
}

4 授予多个权限的Demo

// 声明一个数组,用来存储所有需要动态申请的权限
String[] permissions = new String[]{
         Manifest.permission.ACCESS_COARSE_LOCATION,
         Manifest.permission.ACCESS_FINE_LOCATION,
         Manifest.permission.WRITE_EXTERNAL_STORAGE,
         Manifest.permission.READ_EXTERNAL_STORAGE,
         Manifest.permission.READ_PHONE_STATE,};
         
// 声明一个集合,在后面的代码中用来存储用户拒绝授权的权
List<String> mPermissionList = new ArrayList<>();

// 检查权限方法
private void checkPermission() {
     mPermissionList.clear();
     /**
      * 判断哪些权限未授予,以便必要的时候重新申请
      */
     for (String permission : permissions) {
         if (ContextCompat.checkSelfPermission(mContext, permission) != PackageManager.PERMISSION_GRANTED) {
             mPermissionList.add(permission);
         }
     }
     /**
      * 判断存储委授予权限的集合是否为空
      */
     if (!mPermissionList.isEmpty()) {
         // 后续操作...
     } else {//未授予的权限为空,表示都授予了
         // 后续操作...
     }
 }

boolean mShowRequestPermission = true;//用户是否禁止权限

// 回调动态授权结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
     super.onRequestPermissionsResult(requestCode, permissions, grantResults);
     switch (requestCode) {
         case 1:
             for (int i = 0; i < grantResults.length; i++) {
                 if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                     //判断是否勾选禁止后不再询问
                     boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(ShopNearbyActivity.this, permissions[i]);
                     if (showRequestPermission) {
                         // 后续操作...
                     } else {
                        // 后续操作...
                     }
                 }
             }
             // 授权结束后的后续操作...
             break;
         default:
             break;
     }
 }

5 判断某项权限是否被授权

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            int checkResult = appOpsManager.checkOpNoThrow(
                    AppOpsManager.OPSTR_FINE_LOCATION, Binder.getCallingUid(), context.getPackageName());
            if(checkResult == AppOpsManager.MODE_ALLOWED){
                Toast.makeText(context,"有权限",Toast.LENGTH_LONG).show();
                Log.e("jijiaxin","有权限");
            }else if(checkResult == AppOpsManager.MODE_IGNORED){
                Toast.makeText(context,"被禁止了,没有权限",Toast.LENGTH_LONG).show();
                Log.e("jijiaxin","被禁止了,没有权限");
            }else if(checkResult == AppOpsManager.MODE_ERRORED){
                Toast.makeText(context,"出错了",Toast.LENGTH_LONG).show();
                Log.e("jijiaxin","出错了");
            }else if(checkResult == 4){
                Toast.makeText(context,"权限需要询问",Toast.LENGTH_LONG).show();
                Log.e("jijiaxin","权限需要询问");
            }
        }

6 权限授权第三方框架

6.1 推荐AndPermission

AndPermission
中文文档-中国开发者必看

补充:RxPermissions

6.2 使用

(1)Gradle

compile 'com.yanzhenjie:permission:1.1.2'

(2) 使用模板

// Activity:
AndPermission.with(activity)
    .requestCode(100)
    .permission(Permission.SMS)
    .rationale(...)
    .callback(...)
    .start();

// Fragment:
AndPermission.with(fragment)
    .requestCode(100)
    .permission(
        // Multiple permissions group.
        Permission.SMS,
        Permission.LOCATION
    )
    .rationale(...)
    .callback(...)
    .start();

// Anywhere:
AndPermission.with(context)
    .requestCode(100)
    .permission(Permission.SMS)
    .rationale(...)
    .callback(...)
    .start();

// If only want to request a permission: 
AndPermission.with(this)
    .requestCode(300)
    .permission(Manifest.permission.WRITE_CONTACTS)
    .rationale(...)
    .callback(...)
    .start();

// If only want to request some permissions: 
AndPermission.with(this)
    .requestCode(300)
    .permission(
        Manifest.permission.WRITE_CONTACTS,
        Manifest.permission.READ_SMS
    )
    .rationale(...)
    .callback(...)
    .start();

(3) 例子

AndPermission.with(context)
             .requestCode(200)
             .permission(
                 Manifest.permission.ACCESS_FINE_LOCATION,
                 Manifest.permission.READ_PHONE_STATE)
             .callback(new PermissionListener() {
                 @Override
                 public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {
                     if (requestCode == 200) {
                     }
                 }
                 @Override
                 public void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {
                 }
             })
             .start();

7 参考博客

Android 6.0 运行时权限处理

Android 6.0 运行时权限处理完全解析

权限相关和第三方库PermissionsDispatcher

Android适配6.0动态申请权限,多权限同时申请

Android AppOpsManager权限判断

国产 Android 权限申请最佳适配方案——permissions4m

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值