获取双卡手机IMEI、IMSI

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/meifannao789456/article/details/82378697

转载请注明出处:
现在 Android 手机越来越多的使用双卡双待,对于安装双卡的手机,有时我们想要获取两张卡的IMSI、IMEI等信息。我们知道 Android 中提供了相关 api,通过类 TelephonyManager可以获取IMSI、IMEI等信息,注意:在Android M及以后,在使用类TelephoneManager之前,需要动态申请权限android.permission.READ_PHONE_STATE,否则获取到的信息可能为空。
但是TelephoneManager提供的public String getDeviceId(),public String getSubscriberId()等API,只能返回默认的一个IMEI、IMSI,并不能获取双卡的信息。在 Android 5.0 之后,系统加入了public String getDeviceId(int slotId),public String getSubscriberId(int subId)等方法,可以根据slotIdsubId来获取不同卡槽的信息,但是这些方法是hide方法,被系统隐藏了。然而在 API 23及以后,系统开放了 public String getDeviceId(int slotId) 方法。至此,可以想到我们的实现思路是,在 Android 5.0 及之后,通过反射系统方法来获取双卡的IMEI和IMSI信息。
在这里解释一下上文提到的 slotIdsubIdslotId为卡槽Id,它的值为 01subId为卡Id,相当于在手机卡插到手机上时,系统为卡分配的一个标识Id,这个值通过ContentProvider来获取。

public static int getSubId(int slotId, Context context) {
        Uri uri = Uri.parse("content://telephony/siminfo");
        Cursor cursor = null;
        ContentResolver contentResolver = context.getContentResolver();
        try {
            cursor = contentResolver.query(uri, new String[] {"_id", "sim_id"}, "sim_id = ?", new String[] {String.valueOf(slotId)}, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    return cursor.getInt(cursor.getColumnIndex("_id"));
                }
            }
        } catch (Exception e) {
            LogUtil.d("getSubId", e.toString());
        } finally {
            if (null != cursor) {
                cursor.close();
            }
        }
        return -1;
    }

讲一下通过反射获取IMEI、IMSI的思路:
1、通过方法名来获取方法的参数列表

public static Class[] getMethodParamTypes(String methodName) {
        Class[] params = null;
        try {
            Method[] methods = TelephonyManager.class.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                if (methodName.equals(methods[i].getName())) {
                    params = methods[i].getParameterTypes();
                    if (params.length >= 1) {
                        LogUtil.d("length:", "" + params.length);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.d("", e.toString());
        }
        return params;
    }

2、通过subId和方法名来获取该方法的返回值

public static Object getPhoneInfo(int subId, String methodName, Context context) {
        Object value = null;
        try {
            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            if (Build.VERSION.SDK_INT >= 21) {
                Method method = tm.getClass().getMethod(methodName, getMethodParamTypes(methodName));
                if (subId >= 0) {
                    value = method.invoke(tm, subId);
                }
            }
        } catch (Exception e) {
            LogUtil.d("", e.toString());
        }
        return value;
    }

3、获取IMEI和IMSI的值

    // imei
    public static String getDeviced(Context context, int soltId) {
        return (String) getPhoneInfo(soltId "getDeviceId", context);
    }
    // imsi
    public static String getSubscriberId(int subId, Context context) {
        String imsi = (String) getPhoneInfo(subId, "getSubscriberId", context);
        return imsi;
    }

通过以上方式,可以获取Android 5.0以后双卡手机的IMEI、IMSI信息。这里解释下步骤1为何通过通过反射来获取参数列表,因为发现在部分机型上获取到的参数类型有long类型,所以直接通过反射的方式来获取了。
以上方法,亲测一加3、华为Mate8、小米Note、VIVO X6PlusA、荣耀V9可用。
扫码关注个人公众号:咻咻ing

猜你喜欢

转载自blog.csdn.net/meifannao789456/article/details/82378697