关注微信公众号:程序员小安,精彩文章定期推送。
1.前言
获取IMEI相信大家非常熟悉,但是项目中使用时,发现当手机卡为电信的时候,获取的并不是IMEI,而是MEID,什么是MEID,为什么会出现这种情况呢? IMEI国际移动设备识别码(IMEI:International Mobile Equipment Identification Number)是区别移动设备的标志,储存在移动设备中,可用于监控被窃或无效的移动设备。目前GSM和WCDMA手机终端需要使用IMEI号码 MEID移动设备识别码(Mobile Equipment Identifier)是CDMA手机的身份识别码,也是每台手机有唯一的识别码。通过这个识别码,网络端可以对该手机进行跟踪和监管。用于CDMA制式的手机。MEID的数字范围是十六进制的,和IMEI的格式类似。
2.使用方法
为什么会出现获取的不是IMEI,而是MEID呢,继续往下看。 一般情况下,大家获取imei号,通过以下两个步骤实现。 1)添加读取权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
2)获取设备imei号
public static String getImei(Context context) {
TelephonyManager telephonyMgr = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
String imei = telephonyMgr.getDeviceId();
return imei ;
}
很明显,通过调用getDeviceId()希望获取IMEI,但是得到的却是MEID,定位到getDeviceId()的源码,如下:
/**
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
try {
ITelephony telephony = getITelephony();
if (telephony == null)
return null;
return telephony.getDeviceId(mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}
注释很明显了,CDMA手机返回的是MEID或者ESN,也就是电信卡返回的是MEID,到这里我们发现了问题所在,那么如何解决呢,浏览源码,我们发现,有个隐藏的(hide)方法,如下:
/**
* Returns the IMEI. Return null if IMEI is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
/** {@hide} */
public String getImei() {
return getImei(getDefaultSim());
}
这个方法可以获取IMEI,但是由于是hide方法,不能直接调用,所以我们只能通过反射调用该方法。
3.通过反射获取IMEI
代码很简单,如下所示:
public static String getMachineImei(Context context) {
TelephonyManager manager = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
Class clazz = manager.getClass();
String imei = "";
try {
Method getImei=clazz.getDeclaredMethod("getImei",int.class);//(int slotId)
getImei.setAccessible(true);
imei = (String) getImei.invoke(manager);
} catch (Exception e) {
}
return imei;
}
通过上述反射调用getImei(),则可以在电信卡手机成功获取IMEI号,当前前提是存在IMEI号。
如有错误欢迎指出来,一起学习。