迁移源地址为:
Android 6.0以上系统-动态获取权限获取
个人原文地址:Android 6.0以上系统-动态获取权限获取
刚刚发布了,Android7.0(android N)StrictMode API政策禁。文章,具体如android7.0做了哪些优化不了解的可以去了解下,方便大家对下面的内容理解。个人比较感兴趣的就是android7.0对提供了VR(虚拟现实)的接口,太忙了,没时间,放着吧,就像放下感情一样。
现在个人做了一个动态权限的简单测试,非常简单的一个小demo。欢迎点击右上角关注该yTips专栏,内容会持续更新下去。顺便提一下an-aw-base框架也有了更新,主要更新了Android7.0带来的StrictMode API 政策禁导致an-aw-base框架会crach掉的问题,但是目前小小改动还不能发布新的兼容性版本,大家可以持续关注个人http://GitHub.com的动态。
如有使用问题请发送电子邮件。
邮件地址: staryumou@163.com / qyddai@gmail.com。
文章的题目是Android 6.0以上系统,动态获取权限,这里我们以如下权限讲解,(包含了android7.0)
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
其它诸如读写外部存储的权限,以及相机拍照,裁剪,SD卡,短信啊,状态等权限的android7.0使用StrictMode API 的方法大同小异。(码字有点累錒)
问题
我们想要获取手机如调用getDeviceId()获取手机串码,只在Manifest里添加android.permission.READ_PHONE_STATE权限是不够的,如果不做权限的动态申请和处理,可能会报如下错误:
Caused by: java.lang.SecurityException: getDeviceId: Neither user 10084 nor current process has android.permission.READ_PHONE_STATE.
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:4118)
at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:801)
at com.an.test.MainActivity.mytest(MainActivity.java:51)
at java.lang.reflect.Method.invoke(Native Method)
java.lang.SecurityException,大家看到了吗?就是这个权限咯,当然这个只是android6.0 以上系统才会儿出现的错误,强迫症的我也做了一些验证谷歌对应用的授权策略做了变动和对比在android6.0一下系统有什么区别,在文章最后会给出大家测试的结果。
那么我们作为开发者如何解决,让我们的application兼容(向上兼容呢)?
解决办法
第一步:在Manifest.xml中添加权限。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
第二部:Activity实现接口
implements ActivityCompat.OnRequestPermissionsResultCallback
需要注意的是ActivityCompat在android.support.v4.app.包中。还有有一点需要特别注意的就是,建议大家在Android_N的sdk版本中引入的,所以如果你的编译版本不是Android_N的话,就不要用这个方法了,否者编译都通过不了。
第三步:动态申请权限并处理。这里我是点击一个按钮开始请求权限。
public void mytest(View view) {
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
} else {
TelephonyManager telephonyMgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String uid = telephonyMgr.getDeviceId();
String phone = telephonyMgr.getLine1Number();
String network = telephonyMgr.getNetworkOperatorName();
String number = telephonyMgr.getSimSerialNumber();
String subscriberId = telephonyMgr.getSubscriberId();
String networkCountryIso = telephonyMgr.getNetworkCountryIso();
String networkOperator = telephonyMgr.getNetworkOperator();
textView.setText("uid:" + uid + "\nphone" + phone + "\nnetwork" + network + "\nnumber" + number + "\nsubscriberId" + subscriberId + "\nnetworkCountryIso" + networkCountryIso + "\nnetworkOperator" + networkOperator);
}
}
这里稍微解释一下:checkSelfPermission去检查app是不是具有READ_PHONE_STATE权限,;equestPermissions去动态申请权限,如果有权限我们就直接打印出手机号码,手机串号,手机识别码,IMEI号等等信息。
点击按钮后会出现如下图所示的界面。
<p>结合这张图再给大家一点yTips:</p><p>当请求权限时就会在用户的屏幕上弹出如上的界面,用户点击拒绝或者同意都会触发我们的一个回调函数,在下面第四步骤,如果同意就返回true,否者就会返回false。</p><p> 这种情况下,当用户点击同意后,下次再次访问就不需要再次申请了,如果用户点击拒绝,当用户下次再次请求的时候该弹出框还会再次出现,这里我需要额外补充的是,在我们开发模式的时候,如果我们之前选择了同意某项权限后,当我们没有卸载程序而是直接又一次编译程序,此时系统认为我们具有了权限;另一点值得注意的就是这些权限用户是可以动态取消的,所以一个健壮的程序应当做好判断。(这段话鹅厂专家说的)。</p><p>第四步:重写onRequestPermissionsResult()方法,对权限申请结果做处理:</p><div><pre>@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_READ_PHONE_STATE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
TelephonyManager telephonyMgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String uid = telephonyMgr.getDeviceId();
String phone = telephonyMgr.getLine1Number();
String network = telephonyMgr.getNetworkOperatorName();
String number = telephonyMgr.getSimSerialNumber();
String subscriberId = telephonyMgr.getSubscriberId();
String networkCountryIso = telephonyMgr.getNetworkCountryIso();
String networkOperator = telephonyMgr.getNetworkOperator();
textView.setText("uid:" + uid + "\nphone" + phone + "\nnetwork" + network + "\nnumber" + number + "\nsubscriberId" + subscriberId + "\nnetworkCountryIso" + networkCountryIso + "\nnetworkOperator" + networkOperator);
}
break;
default:
break;
}
}
</code></pre></div><p>通过onRequestPermissionsResult()函数的回掉我们判断获取授权的结果,如上代码我们得到手机相关的信息并打印了出来。结果如下图,给大家看看。</p><p>如果用户拒绝则是else if 的代码</p><div><pre>else if (grantResults[0] == PackageManager.PERMISSION_DENIED){
L.d("imei", "permission is not granted after requested!");
//这里表示申请权限后被用户拒绝了
} else {
L.d("imei", "permission is not granted after requested!");
}
</pre></div><p>更多权限的问题,大家可以参考google官方文档:</p><p>https://developer.android.com/training/permissions/requesting.html</p><p>上面说过文章标题《Android 6.0以上系统-动态获取权限获取》我们单一的针对READ_PHONE_STATE这个权限做了案列分析,其它的权限方法雷同。</p><p>最后补充Android StrictMode API 测试结果,我这里真机测试了,给出结果,大家以后可以不用去尝试了,当然喜欢折腾的人除外。</p><p>测试结果。</p><p>从左到右 依次是三星5.0.1系统,华为,三星,魅族,小米</p><ol><li>Nexus 6p API 24 android 7.0 模拟器 </li></ol><p>报ANR SecurityException ,结果需要动态权限的政策StrictMode</p><p>2. MeiZhu API 22 android5.1 正常运行,不需要动态权限(其实也可以不会错)</p><p>但是我个人的想法是不需要,因为我可以做坏事情。哈哈。秘密。</p><p>3.SamSung -G9006V android4.4.2 API 19 正常运行,不需要动态权限(其实也可以不会错)</p><p>4.HuaWei NEM-TL00H android6.0 API23</p><p>安装时不给权限,则会报SecurityException,</p><p>安装时给READ_PHONE_STATE权限,正常运行。</p><p>5.Xiaomi HM2A android4.4.4 API 19 正常运行,不需要动态权限。</p><p>6.SamSang-GT19500 android 5.0.1 正常运行,不需要动态权限。</p><p>
晴雨晴 </p><p>2017年3月28日18:12:47</p>