Android唯一識別號(設備指紋)的生成及原理

目的:

儘可能實現,同一設備在不刷機不恢復出廠的情況下,每次生成的設備指紋不變;並且儘可能保證兩部不同的設備生成的設備指紋不能一樣)

原理:

1.將imei號+手機硬件信息+androidID拼接成一個字符串(由於個別手機某些時候獲取的wifi MAC和藍牙MAC不一致,故舍去這兩項);
2.再用MD5把以上信息處理成32位的字符串;

參考:移動應用統計唯一ID的基本原理及 友盟UMID 方案解析

代碼實現如下:

/** 
 * 獲取設備指紋的工具類 
 * 
 * @author BarryHuang 
 * @DATE 2015-8-19 
 */  

public class FingerprintUtil {  
    private static final String TAG = FingerprintUtil.class.getSimpleName();  

    private static final String FINGER_PRINT = "fingerprint";  

    /** 
     * 獲取設備指紋 
     * 如果從SharedPreferences文件中拿不到,那麼重新生成一個, 
     * 並保存到SharedPreferences文件中。 
     * 
     * @param context 
     * @return fingerprint 設備指紋 
     */  
    public static String getFingerprint(Context context) {  
        String fingerprint = null;  
        fingerprint = readFingerprintFromFile(context);  
        if (TextUtils.isEmpty(fingerprint)) {  
            fingerprint = createFingerprint(context);  
        } else {  
            Log.e(TAG, "從文件中獲取設備指紋:" + fingerprint);  
        }  
        return fingerprint;  
    }  

    /** 
     * 從SharedPreferences 文件獲取設備指紋 
     * 
     * @return fingerprint 設備指紋 
     */  
    private static String readFingerprintFromFile(Context context) {  
        return PreferenceManager.getDefaultSharedPreferences(context).getString(FINGER_PRINT, null);  
    }  

    /** 
     * 生成一個設備指紋(耗時50毫秒以內): 
     * 1.IMEI + 設備硬件信息(主要)+ ANDROID_ID + WIFI MAC組合成的字符串 
     * 2.用MessageDigest將以上字符串處理成32位的16進制字符串 
     * 
     * @param context 
     * @return 設備指紋 
     */  
    public static String createFingerprint(Context context) {  
        long startTime = System.currentTimeMillis();  

        // 1.IMEI    
        TelephonyManager TelephonyMgr = (TelephonyManager) context  
                .getSystemService(Context.TELEPHONY_SERVICE);  
        final String imei = TelephonyMgr.getDeviceId();  

        Log.i(TAG, "imei=" + imei);  

        //2.android 設備信息(主要是硬件信息)    
        final String hardwareInfo = Build.ID + Build.DISPLAY + Build.PRODUCT  
                + Build.DEVICE + Build.BOARD /*+ Build.CPU_ABI*/  
                + Build.MANUFACTURER + Build.BRAND + Build.MODEL  
                + Build.BOOTLOADER + Build.HARDWARE /* + Build.SERIAL */  
                + Build.TYPE + Build.TAGS + Build.FINGERPRINT + Build.HOST  
                + Build.USER;  
        //Build.SERIAL => 需要API 9以上    
        Log.i(TAG, "hardward info=" + hardwareInfo);  

        /* 3. Android_id 刷機和恢復出廠會變  
         * A 64-bit number (as a hex string) that is randomly  
        * generated when the user first sets up the device and should remain  
        * constant for the lifetime of the user's device. The value may  
        * change if a factory reset is performed on the device.  
        */  
        final String androidId = Secure.getString(context.getContentResolver(),  
                Secure.ANDROID_ID);  
        Log.i(TAG, "android_id=" + androidId);  


        /** 
         * 4. The WLAN MAC Address string(個別手機剛開機完成後會獲取不到,捨去)  
         */    
        /*WifiManager wifiMgr = (WifiManager) context  
                .getSystemService(Context.WIFI_SERVICE);  
        final String wifiMAC = wifiMgr.getConnectionInfo().getMacAddress();  
        Log.i(TAG,"wifi Mac="+wifiMAC);*/    


        /*  
         *  5. get the bluetooth MAC Address  
         *  (有部分手機,如三星GT-S5660 2.3.3,當藍牙關閉時,獲取不到藍牙MAC;  
         *   所以爲了保證 device id 的不變,捨去)  
         */    
        /*BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
        String bt_MAC = null;  
        if (bluetoothAdapter == null) {  
            Log.e(TAG, "bluetoothAdapter is null");  
        } else {  
            bt_MAC = bluetoothAdapter.getAddress();  
        }  
        Log.i(TAG,"m_szBTMAC="+bt_MAC);*/  


        // Combined Device ID    
        final String deviceId = imei + hardwareInfo + androidId/* + wifiMAC + bt_MAC*/;  
        Log.i(TAG, "deviceId=" + deviceId);  

        // 創建一個 messageDigest 實例    
        MessageDigest msgDigest = null;  
        try {  
            msgDigest = MessageDigest.getInstance("MD5");  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        }  

        //用 MessageDigest 將 deviceId 處理成32位的16進制字符串    
        msgDigest.update(deviceId.getBytes(), 0, deviceId.length());  
        // get md5 bytes    
        byte md5ArrayData[] = msgDigest.digest();  

        // create a hex string    
        String deviceUniqueId = new String();  
        for (int i = 0; i < md5ArrayData.length; i++) {  
            int b = (0xFF & md5ArrayData[i]);  
            // if it is a single digit, make sure it have 0 in front (proper    
            // padding)    
            if (b <= 0xF) deviceUniqueId += "0";  
            // add number to string    
            deviceUniqueId += Integer.toHexString(b);  
//          Log.i(TAG,"deviceUniqueId=" + deviceUniqueId);    
        } // hex string to uppercase    
        deviceUniqueId = deviceUniqueId.toUpperCase();  
        Log.d(TAG, "生成的設備指紋:" + deviceUniqueId);  

        Log.e(TAG, "生成DeviceId 耗時:" + (System.currentTimeMillis() - startTime));  
        PreferenceManager.getDefaultSharedPreferences(context).edit().putString(FINGER_PRINT, deviceUniqueId).commit();  

        return deviceUniqueId;  
    }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章