Android 6.0终于是千呼万唤始出来了,除了动画更加酷炫之外,也有很多吊炸天的功能,比如新增加的权限管理,看完它,作为一个程序猿,第一感觉就是,真是日了狗了!
在android 6以前,程序在manifest声明的权限,在用户安装程序的时候,就已经展示出来并全部赋予权限了,这种权限管理的特征就是只在安装时显示一次,管你同不同意,只要你安装了,就代表你同意了。因此我敢吃键盘来赌你安装的时候从来没有看那些权限列表。
虽然对用户来说很坑爹,但是对程序猿来说就是福利,因为自android 6之后,部分权限已经不允许这样了,除了以前正常的编码之后,还需要添加对Dangerous permissions的权限请求,google怕你偷取用户数据干一些见不得人的事情,可谓是用心良苦啊
附上Dangerous permissions及它所属权限组预览表
虽然上面的权限需要另外在代码中请求授权,但是同一组的权限是相通的,比如用户给了你READ_CLAENDAR权限,你就获得了CALENDAR权限组下的所有权限。
在此之前,说一说android6.0在设置的应用界面增加了一个权限管理功能,打开如下
说明了我们已经可以手动管理一些危险的权限了,想想当我们关闭这个权限的时候,当我执行到需要这个权限的代码的时候回怎么样,有两种情况
- 崩溃
- 返回值为null或者0。
为什么会有两种情况,在target SDK22(android 5.1)以前,根本就没有这个权限管理啊,要是你关了权限直接导致程序奔溃了,那不是gg了,所以官方为了广大用户着想,当你设置了target SDK为22以下时,直接返回空(但是如果你没在程序中考虑到返回空值的情况而不处理的话还是有可能会导致崩溃的)
直接的情况自然就是target SDK23以上了,简单暴力,使我们不得不在代码里添加请求权限
权限功能是在android6.0才有,请时刻想象你的手机运行棉花糖系统
在6.0手机上运行程序时,如果你是定义target SDK22以下的时候,记得这些权限默认是开启的,只有你手贱关闭的时候才会返回空;而在target SDK23以上的时候,默认是关闭的,如果你不处理,就直接程序崩溃
综上所述,不管你设置target SDK是多少,只要想在android6.0下运行程序,最好都要添加权限请求。
废话了那么多,终于要说正事了,到底是如何在代码里管理权限的呢,请大家洗耳恭听。
在本次示例中,我做了一个图片选择器,用到了READ_EXTERNAL_STORAGE,属于STORAGE权限组,要想在6.0下运行,我要在代码中对READ_EXTERNAL_STORAGE或者WRITE_EXTERNAL_STORAGE授权。
因为权限管理类在23才有,所以我用了support v4包
//初始化所有图片文件目录
private void initDirectory() {
int checkSelfPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(checkSelfPermission != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION);
}else{
//有权限了,获取图片数据
getCameraData();
}
}
上面代码很简单,首先先查询指定的权限有没有被授权,如果有则直接获取数据,如果没有的话,调用requestPermissions请求获取权限,上面的权限参数是String数组,说明可以同时请求多个授权。
执行之后,系统启动个dialog询问用户.
既然请求了,那应该就有回调。我们需要在该类下重写onRequestPermissionsResult方法
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode){
case REQUEST_STORAGE_PERMISSION:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
//获取数据
getCameraData();
}else{
Toast.makeText(PhotoPickActivity.this,"获取权限失败",Toast.LENGTH_SHORT).show();
}
break;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
用户运行和拒绝的界面都如下所示,只要有请求权限,就算拒绝了也不会崩溃,而是返回null或0.这么简单就不说了吧
一般来说,当用户觉得这个权限请求很莫名其妙的时候(比如显示图片的时候突然请求获取location权限),通常会不给授权。于是google提供了ActivityCompat.shouldShowRequestPermissionRationale来给哪些莫名其妙的权限提供一个解释自身清白的机会。
当shouldShowRequestPermissionRationale方法返回true,就是建议你给他一个解释的时候了。一般第一次弹出请求权限框的时候(即没有”不在询问”选项框的时候)返回false.
当第一次拒绝之后,系统觉得你拒绝它是有原因的,因此接下来的的弹出框(即有”不在询问”选项框的时候)都返回true
勾选不在询问或者授权成功情况下都返回false
接下来就看看他是怎么使用的
private void initDirectory() {
int checkSelfPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(checkSelfPermission != PackageManager.PERMISSION_GRANTED){
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(PhotoPickActivity.this)
.setMessage("你需要启动权限WRITE_EXTERNAL_STORAGE来获取图片")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(PhotoPickActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION);
}
})
.setNegativeButton("Cancel",null)
.create()
.show();
}else{
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION);
}
}else{
getCameraData();
}
}
基本的分析写完了,最后在总结一下
- 当你还没写好这些权限请求时,千万不要把target sdk设置为23以上,不然用户就悲剧了,总不能叫他去设置里面开启权限吧
- 养成支持权限的习惯,说不定用户哪天就关了那个重要的权限而忘了,你就可以贴心提醒它了