Android6.0权限机制(一):介绍

96
08_carmelo
2017.05.10 23:06* 字数 1299

本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布
Android6.0权限机制(一):介绍
Android6.0权限机制(二):封装
Android6.0权限机制(三):6.0以前国产手机权限处理

为何google在6.0加入这个权限机制

android6.0之前其实也有权限机制,很简单就是开发者在manifest.xml注册,用户安装app时候,当做权限清单列出来告知用户我需要这些个权限,但是这样用户基本不会去看,导致app权限滥用造成安全隐患。

权限分类

Android权限有100多种不可能每种都去运行时授权,因此google把权限分为两类:
1.普通权限:例如网络请求等,按照老的权限机制
2.危险权限:9种共24个(电话,短信,sd卡,位置,摄像头,传感器,日历,录音,联系人),就是我们要动态申请的。

用adb命令查看危险权限列表:(tip:记住9种24类)

adb shell pm list permissions -d -g
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

看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的那么有个问题:分组对我们的权限机制有什么影响吗?的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化。

怎么兼容

1.假设我们的项目之前没加这个权限机制,那现在我们怎么处理呢,要不要加这个权限判断,这个取决与app的版本兼容性也就是你们是否愿意为Android6.0以上的用户们处理这个问题。targetSdkVersion这个属性就是控制是否要引入权限机制的开关。

  • 项目中targetSdkVersion<23: 按照老的权限机制,只在manifest声明就可以了,运行不会报错,但是会有隐患:
    比如,我的APP有个拨号功能,把targetSdkVersion=21,安装到API23(Android6.0)的设备,可以正常拨号,看似正常。
    但是用户可以直接去设置里面关掉权限:
image.png

我在模拟器上有这个警告提示,但不保证所有手机都会有这个提示!这时再打开APP就无法拨号了,由于没有检查权限,用户得不到任何提示,一脸懵逼。

  • targetSdkVersion>=23: 这时就需要在代码中检查权限了,否则打开app去执行需要权限的操作会崩溃。如果关闭权限将会弹出提示框提示你开启权限。

2.如果app原先的targetSdkVersion低于23,现在升级到targetSdkVersion=23的app,那么里面的权限默认全部开启!除非用户卸载重装这个app,才是默认关闭所有权限

关于读写SD卡权限

在6.0之前由于读写SD没有限制,导致sd卡目录被app滥用,于是google把sd卡续写权限列为危险权限,如果开发者不想申请sd卡读写权限,可以访问0/Android/data/包名 这个目录,不需要权限可以随便访问,Android也是建议开发者将这个目录作为app的缓存目录

使用

  • 首先配置build.gradle,targetSdkVersion版本应该>=23,然后导入support-v4包:
apply plugin: 'com.android.application'
    android {
       compileSdkVersion 23
        buildToolsVersion "25.0.2"
        defaultConfig {
            applicationId "com.example.carmelo.myapplication"
            minSdkVersion 19
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
            }
        }
    }
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:23.2.1'
}
  • manifest.xml声明权限
<uses-permission android:name="android.permission.CALL_PHONE"/>
  • 在Activity或者Fragment中判断是否开启了这个权限,如果开启了就拨号,没有的话就申请权限:

界面弹出框:拒绝或者同意,回调两种结果:

[图片上传中。。。(2)]

public class MyActivity extends Activity {
    private Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);
        btn = (Button) findViewById(R.id.textView);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int check = ContextCompat.checkSelfPermission(MyActivity.this, Manifest.permission.CALL_PHONE);
                if(check== PackageManager.PERMISSION_GRANTED){
                    call();
                }else {
                    ActivityCompat.requestPermissions(MyActivity.this
                            ,new String[]{Manifest.permission.CALL_PHONE}
                            , 1);
                }
            }
        });
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==1){
            if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
                call();
            }else {
                Toast.makeText(MyActivity.this,"没有拨打电话权限",Toast.LENGTH_SHORT).show();
            }
        }
    }
    private void call(){
        Intent intent = new Intent();
        intent.setData(Uri.parse("tel://1212121212"));
        intent.setAction(Intent.ACTION_CALL);
        startActivity(intent);
    }
}
  • 不再提示的处理:
    如果用户勾选了不再提示,并且拒绝了权限,那么后面不会再弹框,并且结果一直回调到没有权限,此时根据产品需求处理,一般2种方法:
  1. 在回调中弹出Dialog跳到设置界面开启权限
  2. 直接弹出提示:没有权限(这种更好),因为用户就是拒绝了权限,不要烦他了
Android经验分享
Web note ad 1