现在 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)
等方法,可以根据slotId
、subId
来获取不同卡槽的信息,但是这些方法是hide
方法,被系统隐藏了。然而在 API 23
及以后,系统开放了 public String getDeviceId(int slotId)
方法。至此,可以想到我们的实现思路是,在 Android 5.0
及之后,通过反射系统方法来获取双卡的IMEI和IMSI信息。</br>
在这里解释一下上文提到的 slotId
,subId
。slotId
为卡槽Id,它的值为 0
、1
;subId
为卡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
网友评论