刚开始工做,最近在看Android经典入门书籍《第一行代码》。后来才发现看的是初版,因为Android版本升级,各类feature变了不少,因此书里有些例子已经不能在新一点的版本上正确运行了,我就踩到了一个坑,是关于Android 6.0之后系统对于应用permission的处理的变化。html
在《第一行代码》“8.2.1 接收短信”这一节里,书中给了一个demo项目,主要功能是一旦手机接收到短信的时候,app自动显示出发信人和短信内容。原理很简单:系统在收到短信的时候,会发出值为“android.provider.Telephony.SMS_RECEIVED”的一条广播,因此只需在代码里注册一个BroadcaseReceiver接收这个广播而且读出短信信息而后显示到屏幕上就好了。android
高高兴兴的照着书敲完代码,在模拟器上运行程序,打开DDMS编辑模拟短息,send~走你~duang~~短信接收到了,可是应用上什么都没显示,立马傻眼。检查了一遍代码,确认没错,又尝试一次,duang~仍是不行。因而开始怀疑是否是DDMS有什么问题,就用本身的手机(Android 5.0)试了一下,结果程序正常了,应用成功的显示了短信发信人和内容。这证实模拟器上确实是有什么地方不对劲,看了一眼Virtual Device Manager,我用的模拟器是Android 7.0,联想到以前Android 7.0上下载和打开文件所遇到的坑,警戒的怀疑是否是因为版本变化所引发的不一样。因而在Android 5.0的模拟器上又尝试的一下,duang~成功了。这就证实了确实是版本升级所引发的不一样。app
肯定了问题缘由,开始搜索资料,通过一番调查,其实Android官方文档对permission的行为写的很清楚,在这里总结记录一下。异步
Android把permission分为两种:async
normal permission:不会直接威胁用户的隐私ide
danger permission:可能会访问用户的隐私数据测试
应用要在Manifest文件中声明本身所须要的permission,然而用户在安装应用的时候,系统版本不一样,则会有不一样的对permission的处理:this
对于Android 5.1 (API 22)或更低版本的系统(如下简称“低版本系统”),在用户安装应用的时候,系统会展现应用所需的全部permission的列表(包括normal permission和danger permission),并询问用户是否赞成授予全部权限。若是用户由于不想授予某一或某些权限,应用则不会被安装。code
对于Android 6.0 (API 23)或者更高版本(如下简称“高版本系统”),在用户安装应用的时候,系统会自动授予应用所需的全部normal permission并安装程序,可是并不授予应用所需的danger permission。用户有机会在应用运行时选择是否授予全部或部分danger permission,而且能够随时在设置里收回授予给应用的任何danger permission。orm
看到这里区别就比较明了了,对于低版本系统,若是不想授予某些权限,则应用根本不会被安装。对于高版本系统,若是你不想授予某些danger permission,只要选择不授予就能够了,不会影响应用安装,也不影响应用运行,可是某些feature可能就不能用了(好比你不想授予读取短信功能,那么应用里与短信相关的feature就不能用了,可是与短信无关的feature可使用)。这样有一个好处就是用户能够控制不授予应用哪些数据,而即便不授予应用某些数据,用户仍然可使用“残血版”的应用。
高版本系统在运行时提供给用户授予permission的机会,因此开发者要在代码中对检查和请求permission作相应的处理,在Android framework里提供了相应的方法,在Support Library里也提供了相似的方法。Android的官方文档推荐使用Support Library里的方法,由于使用更简单。
可使用ContextCompat.checkSelfPermission()来检查是否已经得到了某个permission:
// Assume thisActivity is the current activity int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
若是应用已经获取了permission,则返回PackageManager.PERMISSION_GRANTED,若是没有获取,则返回PERMISSION_DENIED。
若是应用没有得到某个permission,则能够经过调用requestPermissions()来请求权限
// Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } }
上述代码中在调用requestPermissions()以前先调用了一个方法shouldShowRequestPermissionRationale(),这个方法给应用一个机会向用户解释为何要请求这个permission。
当requestPermissions()这个方法被调用时,系统会弹出一个样式固定的弹窗,这个弹窗不能定制,供用户选择是否授予permission。requestPermissions()是异步执行的,这个方法会立刻返回。在用户作出选择以后,系统会调用onRequestPermissionsResult(),对请求permission的结果是在这个方法中处理的
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } // other 'case' lines to check for other // permissions this app might request } }
看到这,其实个人问题已经有了解决方法,先检查是否有读取短信权限,若是有的话直接注册广播接收器,若是没有的话请求权限,若是得到权限以后再注册广播接收器,运行,duang~成功~
Android的permission有个权限组(permission group的概念),好比RECEIVE_SMS、READ_SMS、SEND_SMS......都属于SMS组,在应用已经得到了某一组中的某一权限,则下次再请求同组中的其余权限时,系统不会询问用户则直接授予请求的权限。
官方文档提醒开发者,因为用户可能不授予请求的permission,全部开发者要充分测试各类状况,确保在有没有权限的时候应用要有合理的表现。
对于记录的不是很详细的地方,能够参考官方连接:https://developer.android.com...