IMEI、MEID都是用于标识一台物理设备的ID信息。在Android 8.0以下系统提供的API中,会根据不同条件返回二者之一的信息。
IMEI: 国际移动设备识别码,是区别移动设备的标志,一般用于标识某一台独立的设备,双卡双待的手机有两个IMEI号。 格式:15位十进制数MEID: 同样也是移动设备标识码,但一般用于CDMA制式的设备上,是ESN码的升级版,只有一个MEID。 格式:14位十六进制数 API1、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. * *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. * *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. * *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不变化