关于IMEI、MEID、IMSI
简介
IMEI、MEID都是用于标识一台物理设备的ID信息。在Android 8.0以下系统提供的API中,会根据不同条件返回二者之一的信息。
- IMEI: 国际移动设备识别码,是区别移动设备的标志,一般用于标识某一台独立的设备,双卡双待的手机有两个IMEI号。
格式:15位十进制数 - MEID: 同样也是移动设备标识码,但一般用于CDMA制式的设备上,是ESN码的升级版,只有一个MEID。
格式:14位十六进制数
API
1、SDK26开始,TelephonyManager提供了两个独立的API以获取IMEI和MEID: getImei 、 getMeid 。两个API都可传入下标号获取多个设备号信息,getImei(0)获取卡一的IMEI,getImei(1)获取卡二的IMEI,和SIM卡放在什么位置没有关系,和是哪个运营商的也没有关系,没有SIM卡也可以获取IMEI,getImei()方法获取的IMEI就是卡一的IMEI,卡槽的IMEI是固定的,验证机型小米5S,华为P30,华为Mate10,电信移动卡
/**
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param slotIndex of which IMEI is returned
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
try {
return telephony.getImeiForSlot(slotIndex, getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}
2、SDK26以下的系统获取IMEI或MEID的API为TelephonyManager.getDeviceId(),若当前设备有MEID号,则优先返回MEID,否则返回IMEI号。则获取到的设备ID需要通过长度判断才能知晓该ID为IMEI还是MEID,会存在IMEI获取不到,只能获取MEID的情况。 比如用户插移动联通的卡,返回imei1,imei2,插电信的卡就变成返回imei1,meid了 (PS:这个我没有验证网上博客有人这么写)
SDK26以下:谷歌官方把getImei这个获取IMEI的单独API隐藏起来了,不知道为啥,,如果要调用可以利用反射
/**
* Returns the IMEI. Return null if IMEI is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param slotId of which deviceID is returned
*/
/** {@hide} */ SDK26以下的版本加了个隐藏的注解!!
public String getImei(int slotId) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
try {
return telephony.getImeiForSlot(slotId, getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}
我们公版项目里只用了getDeviceId这个过时的方法来获取IMEI,照理是会存在问题,但是如果只是作为唯一标识的话,获取到的是IMEI还是MEID没差。。。我们只获取IMEI,不获取MEID
/**
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @param slotIndex of which deviceID is returned
*
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated SDK28 已经把这个方法标成不推荐使用了。。。!!
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
return null;
return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
}
关于IMSI,和SIM卡绑定,,双卡手机,getSubscriberId方法不传参读的是主卡的IMSI,当主卡断网或者手动把主卡设置成另一张卡时,读的就是另一张卡的IMSI,和卡槽没有关系,只和当前用的是哪张卡有关系,如图,主副卡切换时读取的IMSI变化,IMEI不变化