双卡双待 getDeviceId unique device ID IMEI 不唯一 会变问题

最近接到用户反馈无法登录的情况越来越多,因为我们的app设计上是不能换手机用,也就是绑定了唯一的设备ID。从反馈上来看,有一个线索是大部分是双卡双待的用户出现这个问题,并且切换过SIM卡。看来getDeviceId这个方法在双卡双待手机上获取IMEI还是有问题的。

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.

注释上已经说明了获取的IMEI不会绝对得唯一,GSM CDMA是sim卡网络制式,也就说getDeviceId会根据网络制式返回不同的IMEI,那我们要修正这个问题,就要获取所有的IMEI。继续看文档,果然,发现API版本23新增了一个方法 public String getDeviceId(int slotId),参数slotId文档没有详细写应该怎么填,查看源码发现如下一段常量。

 

/** No phone radio. */
    public static final int PHONE_TYPE_NONE = PhoneConstants.PHONE_TYPE_NONE;
    /** Phone radio is GSM. */
    public static final int PHONE_TYPE_GSM = PhoneConstants.PHONE_TYPE_GSM;
    /** Phone radio is CDMA. */
    public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA;
    /** Phone is via SIP. */
    public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP;


这样我们就能获取所有的IMEI了,如下代码:

 

public static String getWholeImei() {
		String imeiStr = null,imeiStr1= ",",imeiStr2= ",",imeiStr3= ",",imeiStr4= ",";
		try {
			imeiStr = ((TelephonyManager) MyApp.getInstance()
					.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
			imeiStr1 += ((TelephonyManager) MyApp.getInstance()
					.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId(TelephonyManager.PHONE_TYPE_NONE);
			imeiStr2 += ((TelephonyManager) MyApp.getInstance()
					.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId(TelephonyManager.PHONE_TYPE_GSM);
			imeiStr3 += ((TelephonyManager) MyApp.getInstance()
					.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId(TelephonyManager.PHONE_TYPE_CDMA);
			imeiStr4 += ((TelephonyManager) MyApp.getInstance()
					.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId(TelephonyManager.PHONE_TYPE_SIP);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		LogUtil.i(imeiStr+imeiStr1+imeiStr2+imeiStr3+imeiStr4);
		return imeiStr+=imeiStr1+=imeiStr2+=imeiStr3+=imeiStr4;
	}

 

 

需要注意的一点是 虽然API文档上显示此方法是api23,也就是android L 6.0才加的,但是笔者在5.0以上的手机上都能调用,5.0以下才会报NoSuchMethod错误,所以最好的做法就是捕捉ERROR,避免app崩溃。

 

最后举个例子上个结果:

获取到的IMEI:whole_imei=869315022916292,A000005E67BFA4,869315023576038,A000005E67BFA4,A000005E67BFA4

然后上个黑科技 手机拨号界面输入*#06# 就能查看IMEI MEID之类的信息哦

双卡双待 getDeviceId unique device ID IMEI 不唯一 会变问题_第1张图片

证明我们获得了本手机上的所有IMEI。

但是这个getDeviceId方法获取的结果会随着用户插的sim卡改变,比如用户插移动联通的卡,返回imei1,imei2,插电信的卡就变成返回imei1,meid了。如果想要获取固定的imei1,imei2,meid信息,可以调用如下方法:

/**
     * Returns the IMEI. Return null if IMEI is not available.
     *
     * 

Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ /** {@hide} */ public String getImei() { return getImei(getDefaultSim()); } /** * 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} */ 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; } }

因为此方法是hide方法,并且对版本也有要求(可能5.0以上),所以需要用反射调用。

try {
			Method getImei = tm.getClass().getDeclaredMethod("getImei",int.class);
			String imei1 = (String) getImei.invoke(tm,0);
			String imei2 = (String) getImei.invoke(tm,1);
		} catch (Throwable e) {
			e.printStackTrace();
		}

同理,还有获取meid的方法:

try {
			Method getMeid = tm.getClass().getDeclaredMethod("getMeid");
			String meid = (String) getMeid.invoke(tm);
		} catch (Throwable e) {
			e.printStackTrace();
		}

 

你可能感兴趣的:(android)