权限检查(二)
我是插入的:推荐权限检查第三方 https://github.com/jsmeli/PermissionCheck ,望多多支持,感激不尽
1.问题
权限问题一直是android开发人员很头疼的问题,比如经常会碰到朋友抱怨,这个录音权限判断不了或者是判断了没效果,只能另辟蹊
径。其实我们开发过程中很容易碰到这些问题,但是这些问题都很零碎,所以也引不起大的注意,但是却容易发生一些意外状况.当然
今天的主题是M版本的权限问题,这个问题阻拦了很多应用sdk升级23之路。就我自己的研究来看,我有好几个朋友未升级的理由都
是,M版本的权限检查太恶心了,我们里面有那么多地方用到,改的很费劲,那么究竟如何呢?大家如果可以翻墙的话,可以去看看
下面这篇文档,里面着重提到了权限检查的问题。
http://developer.android.com/intl/zh-cn/about/versions/marshmallow/android-6.0-changes.html
2.概述
一个Android应用默认情况下是不拥有任何权限的, 这即是说, 在默认情况下, 一个应用是没有权利去进行一些可能会造成不好影响的操
作的. 这些不好的影响可能是对其它应用,操作系统,或者是用户。如果应用需要一些额外的能力,则它需要在AndroidManifest.xml中静
态地声明相应的权限。如果应用没有在manifest中声明权限, 却使用了相应的功能, 在调用到相应功能的时候, 将会抛出异常。
for example:
比如程序要发送一个请求,却忘记加Internet权限, 那么在发送这个请求的时候程序就会抛出异常,一般不会catch这个异常,所以程序直接
就崩溃了:
caused by: java.lang.securityexception: permission denied (missing internet permission?)
3.权限分组
在Android 6.0 (API 23) 发布之前, 所有的权限都在安装应用的时候显示给用户,用户选择安装则表示全部接受这些权限, 之后无法撤销
对这些权限的授权。Android 6.0开始, 一部分比较危险的权限需要在程序运行时显式弹框,请求用户授权。至于什么时候弹这个框,由应
用程序自己决定。对于其他权限,认为不是很危险,所以仍然保持原来的做法,在用户安装应用程序时就予以授权。还需要注意的是,在设
置中,对于应用的危险权限,用户可以选择性地进行授权或者关闭。当然,在我们开发过程中其实注意两类就够了,一种就是直接可以申
请的,另一种就是需要手动检查的,也就说涉及到隐私的权限。
直接申请的权限列表(Normal权限):
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
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM
INSTALL_SHORTCUT
UNINSTALL_SHORTCUT
需要进行检查的组(Dangerous权限)
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE
4.问题解决方案
其实我们大部分开发过程中的需求都是需要使用到Dangerous权限,为啥呢,因为产品经理的需求,产品想要的数据基本或多或少都
会涉及到用户的一些隐私信息,所以苦逼的还是我们这些开发人员…….
权限检查的代码网上其实都大同小异,基本都是那么写的(以通讯录权限为例):
//动态获取权
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager .PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.READ_CONTACTS)) {
//这种情况是该用户已经选择了不再提示的选项,需要手动给该用户做提示操作
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission .READ_CONTACTS},PERMISSION_REQUEST);
}
} else {
//获取通讯录信息
Intent intent = new Intent(Intent.ACTION_PICK,ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, CHOOSE_CONTACT);
}
如果没有权限并且进行了申请,那么是会有回调结果的
权限申请后的回调:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST:
if (grantResults.length > 0 && grantResults[0] == PackageManager
.PERMISSION_GRANTED) {
//获取通讯录信息
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts
.CONTENT_URI);
startActivityForResult(intent, CHOOSE_CONTACT);
}
break;
}
}
这就是一套正常流程了,看着是没有毛病的,但是我试了其他的手机,就有了问题了,联想的ZUK Z2手机,无论权限禁止与否,
checkSelfPermission(Manifest.permission.READ_CONTACTS)
该方法返回值都是0,也就是说默认是一直都有权限,那么就有问题了这样走的是有权限的流程,就直接打开通讯录了,其实这时候权
限是禁止的找了各种资料发现6.0以下的手机都会返回0,这个问题好像有点眉目了,我就检查了代码还真是少了这个判断,那么我就
又开始各种修改,觉得找到了问题的关键了,修改后
//动态获取权限
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager
.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(context,
Manifest.permission.READ_CONTACTS)) {
//这种情况是该用户已经选择了不再提示的选项,需要手动给该用户做提示操作
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission
.READ_CONTACTS}, PERMISSION_REQUEST);
}
} else {
//获取通讯录信息
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, CHOOSE_CONTACT);
}
}
运行后结果
这就不对了,怎么会酱紫,这就不科学了,完全没有道理。
手机相关权限:
手机型号:
一看也确实是6.0.1的系统,这就比较无解了,那么碰上这种手机如何处理呢?个人处理方式,就通讯录来说的话,该手机的现象是即
使权限禁止,也能打开通讯录,因为代码判断拦不住,居然也能调用成功,但是回传联系人的时候使用ContentProvider读取时候就
报异常了,所以为了满足需求,这边做了以下的处理,如果捕获到异常,弹出自定义的提示框,让用户去授予权限。
try{
//读取通讯录过程
}catch(Exception e){
//捕获到异常就做处理
}
ps:授予权限的快捷键,最好是跳到设置里面的应用程序列表(附上代码)
Intent intent = new Intent(Settings.ACTION_APPLICATION_SETTINGS);
startActivity(intent);
如果有碰到这样问题的同学欢迎讨论,思想总是在碰撞中产生火花。
个人邮箱: jsmeli@163.com