android如何正确获取iccid,特别是中间带有字母的iccid
在android设备上面获取sim卡的iccid,相信很多开发者都能很容易做到,网上也有大量的获取方法,99%的写法都和下面一样
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); iccid = tm.getSimSerialNumber();
在正常情况下,上面的方法是有效的,没有问题。本文再提供一个方法供参考,该方法只有在sdk level不小于22的时候才能用
SubscriptionInfo info = SubscriptionManager.from(context).getActiveSubscriptionInfoForSimSlotIndex(DEFAULT_SLOT_INDEX); if (info != null) { iccid = info.getIccId(); }
为什么说正常情况下有效呢,是因为上述方法只能获取到十进制表示的iccid字符串,上面的本质上调用的com.android.internal.telephony.Phone.getIccSerialNumber(),该方法源码如下:
/** * Retrieves the serial number of the ICC, if applicable. Returns only the decimal digits before * the first hex digit in the ICC ID. */ public String getIccSerialNumber() { IccRecords r = mIccRecords.get(); return (r != null) ? r.getIccId() : null; }
从上面方法的注释可以看出,这个方法是能够获取到第一个十六进制数字前面的十进制数字,有人会问这个是什么情况,iccid里面还有十六进制数字吗?答案当然是有的,移动的某些物联网卡的iccid在中间部位会有一个十六进制数字,如62203B766342343,上面的方法获取到的都是B前面的数字“62203”。
那么如何获取到全部的iccid呢?其实Phone里面还有一个方法
/** * Retrieves the full serial number of the ICC (including hex digits), if applicable. */ public String getFullIccSerialNumber() { IccRecords r = mIccRecords.get(); return (r != null) ? r.getFullIccId() : null; }
从注释可以看出这个方法是可以获取到带有字母的iccid的全部数字的。那么我们开发app的时候如何从上层调用到Phone的getFulliccSerailNumber()方法呢?其实Phone对象可以在PhoneSubInfoController的getPhone(int subId)方法获取,而PhoneSubInfoController对象可以在TelephonyManager.getSubscriberInfo(),TelephonyManager对象如何获取就不用说了吧,到了这里就知道方法了吧,是的,就是利用反射机制,代码如下:
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); try { Method method = tm.getClass().getDeclaredMethod("getSubscriberInfo"); try { method.setAccessible(true); Object obj = method.invoke(tm); Method method2 = obj.getClass().getDeclaredMethod("getPhone",int.class); method2.setAccessible(true); Object obj2 = method2.invoke(obj,0); Method method3 = obj2.getClass().getMethod("getFullIccSerialNumber"); String iccid2 = (String) method3.invoke(obj2); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); }
上面的方法也不是百分百有效的,因为国内的android设备厂商都是系统都是定制的,会修改源码,一些api的名字可能有变化导致报找不到方法的异常。
另外,获取IMEI是需要READ_PHONE_STATE权限的,该权限是危险级别的权限,该干啥都懂了吧