android如何正确获取iccid,特别是中间带有字母的iccid

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权限的,该权限是危险级别的权限,该干啥都懂了吧得意


猜你喜欢

转载自blog.csdn.net/baidu_27196493/article/details/81003837