获取双卡手机IMEI、IMSI

作者: 咻咻ing | 来源:发表于2017-05-09 20:16 被阅读3021次

    现在 Android 手机越来越多的使用双卡双待,对于安装双卡的手机,有时我们想要获取两张卡的IMSI、IMEI等信息。我们知道 Android 中提供了相关 api,通过类 TelephonyManager可以获取IMSI、IMEI等信息,注意:在Android M及以后,在使用类TelephoneManager之前,需要动态申请权限android.permission.READ_PHONE_STATE,否则获取到的信息可能为空。</br>
    但是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信息。</br>
    在这里解释一下上文提到的 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

    相关文章

      网友评论

        本文标题:获取双卡手机IMEI、IMSI

        本文链接:https://www.haomeiwen.com/subject/tcgutxtx.html