前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >6.0 运行时权限处理

6.0 运行时权限处理

作者头像
佛系编码
发布2018-05-22 11:49:58
7290
发布2018-05-22 11:49:58
举报
文章被收录于专栏:Android学习之路

6.0 运行时权限处理

在6.0以前 权限都是在安装时授权的,如果用户不授权就无法安装; Android从6.0(API 23)开始 使用运行时权限,而不是像以前那样安装时授权。当你需要某些权限时,系统会向用户去申请权限。用户可以随时取消授权给你的权限。 6.0中权限分为两类 普通权限和危险权限,普通权限在AndroidManifest 文件中注册就可以得到,对于能获得用户隐私的权限属于危险权限。在使用的时候必须用户授权才能使用。例如 拍照,录音 sd卡的操作,危险权限被分为很多组,只要一组中的其中一项被授权 Android 就会将这一组的权限打包都授权给你app

image
image

危险权限

危险权限被分为了9组

代码语言:javascript
复制
Permission Group    Permissions

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

普通权限

代码语言:javascript
复制
  • ACCESS_LOCATION_EXTRA_COMMANDS  
• ACCESS_NETWORK_STATE
• ACCESS_NOTIFICATION_POLICY
• ACCESS_WIFI_STATE
• BLUETOOTH
• BLUETOOTH_ADMIN
• BROADCAST_STICKY
• CHANGE_NETWORK_STATE
• CHANGE_WIFI_MULTICAST_STATE
• CHANGE_WIFI_STATE
• DISABLE_KEYGUARD
• EXPAND_STATUS_BAR
• GET_PACKAGE_SIZE
• INSTALL_SHORTCUT
• INTERNET
• KILL_BACKGROUND_PROCESSES
• MODIFY_AUDIO_SETTINGS
• NFC
• READ_SYNC_SETTINGS
• READ_SYNC_STATS
• RECEIVE_BOOT_COMPLETED
• REORDER_TASKS
• REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
• REQUEST_INSTALL_PACKAGES
• SET_ALARM
• SET_TIME_ZONE
• SET_WALLPAPER
• SET_WALLPAPER_HINTS
• TRANSMIT_IR
• UNINSTALL_SHORTCUT
• USE_FINGERPRINT
• VIBRATE
• WAKE_LOCK
    • WRITE_SYNC_SETTINGS

请求权限

targetSdkVerion

申请权限之前必须先说一下tartgetSdkVersion ,目标sdk版本,一般定义在build.gradle文件中。 如果 targetSDKVersion 是22 安装好之后 Android系统就知道这个App在系统API22一下都测试过了并且能正确运行的,假如这个App运行在了Android6.0系统上,Android就会对这个App很”照顾“,兼容它正确运行。6.0系统会把App申请的权限都默认给这个App。 但是 ,在6.0系统 ,用户可随时撤销授权给app的权限 ,即使系统默认都授权给你,用户也可以取消掉。这时就没权限了。所以即使是targetSDKVersion < 23 也不是就万事大吉了。Android为我们提供了android.support.v4.content.PermissionChecker 来检测是否具有某些权限 判断 targetSdkVersion

代码语言:javascript
复制
/**
 * 检查targetSDKVersion 是否在 23以上
 * @return
 */
private boolean checkTargetSdkVersion(){
    PackageInfo info= null;
    try {
        info = getPackageManager().getPackageInfo(getPackageName(),0);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    int targetSdk=  info.applicationInfo.targetSdkVersion;
    log("TargetSdkVersion:"+targetSdk);
    if (targetSdk>=Build.VERSION_CODES.M){
        return true;
    }
    return false;
}

检查权限

在去请求权限之前 应该先检查一下系统 的版本 如果系统版本在6.0以上再去请求权限,如果不在就不去请求,直接使用

代码语言:javascript
复制
/**
 * 检查系统版本是否在6.0或者6.0以上
 * @return 
 */
private boolean checkVersion(){
    // Build.VERSION.SDK_INT 当前系统版本
    //Build.VERSION_CODES.M 6.0版本
    if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.M){
        return true;
    }
    return false;
}

PermissionChecker.checkSelfPermission() 方法就是用于检查App自身有没有某一个权限 此方法适用于 targetSdkVersion < 23 context.checkSelfPermission() 适用于 targetSDKVersion >=23 返回结果有三种 状态

  • PermissionChecker.PERMISSION_GRANTED; //有权限
  • PermissionChecker.PERMISSION_DENIED ; //无权限
  • PermissionChecker.PERMISSION_DENIED_APP_OP;//无权限

PermissionChecker.PERMISSION_DENIED 和 PermissionChecker.PERMISSION_DENIED_APP_OP 的区别:

  • targetSDKVersion 小于23没有权限就返回 PermissionChecker.PERMISSION_DENIED_APP_OP
  • targetSdkVersion23或者以上的返回 PermissionChecker.PERMISSION_DENIED
代码语言:javascript
复制
//检测targetSDKVersion 是否在23以上
if (checkTargetSdkVersion()){
    //targetSDKVersion >=23
    //检查是否具有读取短信的权限
    result = checkSelfPermission(permission);
}else{
    //targetSDKVersion <23
    //检查是否具有读取短信的权限
    result= PermissionChecker.checkSelfPermission(this,permission);
}

请求权限

使用 requestPermissions() 方法去请求权限 参数有两个 权限数组 和请求码

代码语言:javascript
复制
requestPermissions(new String[]{"android.permission.READ_SMS"},10);

在请求权限之前最好是跟用户解释清楚为什么要使用这个权限 ,用时候用户并不清楚为什么使用权限 就会被拒绝,如果一个权限被请求一次以上 在系统申请权限的Dialog会出现一个不再提醒的复选框 那怎么判断 用户是否勾选了这个 不再提醒呢 ,Android提供了 shouldShowRequestPermissionRationale() 方法; 这个方法 在 第一次请求的时候 和 在用户勾选了不再提醒时 返回false ,其他均返回true

代码语言:javascript
复制
// 第一次请求就返回false 拒绝过返回true 或者 用户选择不再提示返回false
boolean answer=  shouldShowRequestPermissionRationale(permission);
log("shouldShowRequestPermissionRationale :"+answer);
if (!answer){
    new AlertDialog.Builder(this).setTitle("权限说明")
            .setMessage("此功能需要读取短信的权限,没有权限无法使用此功能。请在稍后授权后使用")
            .setNegativeButton("确定", new DialogInterface.OnClickListener() {
                @RequiresApi(api = Build.VERSION_CODES.M)
                @Override
                public void onClick(DialogInterface dialog, int which) {

                    requestPermissions(new String[]{permission},SMS);

                }
            })
            .setNeutralButton("取消",null)
            .show();
}else{
    requestPermissions(new String[]{permission},SMS);

}
image
image

处理用户响应

重写 activity的 onRequestPermissionsResult() 的方法 处理权限的响应 权限的申请是可以多个权限一块申请的 ,所以 响应结果也是 数组和 请求的权限数组对应

代码语言:javascript
复制
/**
 *  申请权限的响应
 * @param requestCode 请求码
 * @param permissions 权限数组
 * @param grantResults 结果数组
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode){
        case SMS:
          LogCheckResult(grantResults[0]);
            if (grantResults.length>0 && grantResults[0]==PermissionChecker.PERMISSION_GRANTED){
                //TODO 读取短信
                Toast.makeText(this,"读取短信授权成功",Toast.LENGTH_SHORT).show();
                tv.setText(getSmsInPhone());
            }else{
                Toast.makeText(this,"读取短信授权失败",Toast.LENGTH_SHORT).show();
            }
            break;
       

    }
}

完整的短信读取权限申请 流程

请求权限

代码语言:javascript
复制
/**
 * 请求短信权限
 */
@RequiresApi(api = Build.VERSION_CODES.M)
private void requestSms() {
    // 权限
        final String permission = "android.permission.READ_SMS";
    //检查当前系统版本是否在6.0以上
    if (checkVersion()){
        int result =-1;
        //检测targetSDKVersion 是否在23以上
            if (checkTargetSdkVersion()){
                //targetSDKVersion >=23
                //检查是否具有读取短信的权限
                result = checkSelfPermission(permission);
            }else{
                //targetSDKVersion <23
                //检查是否具有读取短信的权限
                result= PermissionChecker.checkSelfPermission(this,permission);
            }
            LogCheckResult(result);
            if(result==PermissionChecker.PERMISSION_GRANTED){
                //已经有了权限
                //TODO 读取短信
                Toast.makeText(this,"读取短信授权成功",Toast.LENGTH_SHORT).show();
                tv.setText(getSmsInPhone());
            }else{
                //没有权限
                //TODO 请求权限
                // 第一次请求就返回false 拒绝过返回true 或者 用户选择不再提示返回false
              boolean answer=  shouldShowRequestPermissionRationale(permission);
                log("shouldShowRequestPermissionRationale :"+answer);
                if (!answer){
                    new AlertDialog.Builder(this).setTitle("权限说明")
                            .setMessage("此功能需要读取短信的权限,没有权限无法使用此功能。请在稍后授权后使用")
                            .setNegativeButton("确定", new DialogInterface.OnClickListener() {
                                @RequiresApi(api = Build.VERSION_CODES.M)
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    requestPermissions(new String[]{permission},SMS);
                                }
                            })
                            .setNeutralButton("取消",null)
                            .show();
                }else{
                    requestPermissions(new String[]{permission},SMS);
                }
            }
    }else{
        //无需请求
        Toast.makeText(this,"读取短信授权成功",Toast.LENGTH_SHORT).show();
        tv.setText(getSmsInPhone());
    }
}

响应处理

代码语言:javascript
复制
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode){
        case SMS:
          LogCheckResult(grantResults[0]);
            if (grantResults.length>0 && grantResults[0]==PermissionChecker.PERMISSION_GRANTED){
                //TODO 读取短信
                Toast.makeText(this,"读取短信授权成功",Toast.LENGTH_SHORT).show();
                tv.setText(getSmsInPhone());
            }else{
                Toast.makeText(this,"读取短信授权失败",Toast.LENGTH_SHORT).show();
            }
            break;
       

    }
}

短信读取 代码

代码语言:javascript
复制
public String getSmsInPhone() {
    log("开始读取短信");
    final String SMS_URI_ALL = "content://sms/";
    final String SMS_URI_INBOX = "content://sms/inbox";
    final String SMS_URI_SEND = "content://sms/sent";
    final String SMS_URI_DRAFT = "content://sms/draft";
    final String SMS_URI_OUTBOX = "content://sms/outbox";
    final String SMS_URI_FAILED = "content://sms/failed";
    final String SMS_URI_QUEUED = "content://sms/queued";

    StringBuilder smsBuilder = new StringBuilder();

    try {
        Uri uri = Uri.parse(SMS_URI_ALL);
        String[] projection = new String[] { "_id", "address", "person", "body", "date", "type" };
        Cursor cur = getContentResolver().query(uri, projection, null, null, "date desc");      // 获取手机内部短信
        log("cursor:"+cur.getCount());
        if (cur.moveToFirst()) {
            int index_Address = cur.getColumnIndex("address");
            int index_Person = cur.getColumnIndex("person");
            int index_Body = cur.getColumnIndex("body");
            int index_Date = cur.getColumnIndex("date");
            int index_Type = cur.getColumnIndex("type");

            do {
                String strAddress = cur.getString(index_Address);
                int intPerson = cur.getInt(index_Person);
                String strbody = cur.getString(index_Body);
                long longDate = cur.getLong(index_Date);
                int intType = cur.getInt(index_Type);

                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                Date d = new Date(longDate);
                String strDate = dateFormat.format(d);

                String strType = "";
                if (intType == 1) {
                    strType = "接收";
                } else if (intType == 2) {
                    strType = "发送";
                } else {
                    strType = "null";
                }

                smsBuilder.append("[ ");
                smsBuilder.append(strAddress + ", ");
                smsBuilder.append(intPerson + ", ");
                smsBuilder.append(strbody + ", ");
                smsBuilder.append(strDate + ", ");
                smsBuilder.append(strType);
                smsBuilder.append(" ]\n\n");
            } while (cur.moveToNext());

            if (!cur.isClosed()) {
                cur.close();
                cur = null;
            }
        } else {
            smsBuilder.append("no result!");
        } // end if

        smsBuilder.append("getSmsInPhone has executed!");

    } catch (SQLiteException ex) {
        log("SQLiteException in getSmsInPhone");
    }

    return smsBuilder.toString();
}

读取短信的代码参考这位大神的代码:http://blog.csdn.net/ithomer/article/details/7328321 关于这次的Demo,github 地址: https://github.com/sky-mxc/AndroidDemo/tree/master/permission

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 6.0 运行时权限处理
    • 危险权限
      • 普通权限
        • 请求权限
          • targetSdkVerion
          • 检查权限
          • 请求权限
        • 处理用户响应
          • 完整的短信读取权限申请 流程
          相关产品与服务
          短信
          腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档