1. 程式人生 > >獲取手機唯一識別碼IMEI

獲取手機唯一識別碼IMEI

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號。

歡迎一起交流討論
群號:469890293