Android手機上獲取物理惟一標識碼

最近在作項目的過程當中須要惟一標識用戶的設備,後臺在作push notification的時候須要用到這個惟一的標識號。java

首先我會想到的是設備的device id,毫無疑問能夠惟一標識設備,第一個版本也正是這樣作的。國慶期間用戶的一封郵件讓哥很不淡定,由於須要拿到device id,因此必然要在AndroidManifest文件中添加權限android

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

添加完這條權限很天然的在用戶下載App的時候會提示如下權限接受的列表:安全

OK。問題來了,用戶以爲這個東西比較敏感,我選擇不安裝大家的這個App,心中一萬隻羊駝在奔跑。dom

想一想換換其餘方式來實現這一需求吧。今天和你們總結分享下每種方式的利弊。工具

第一種方式:設備的Device Id做爲惟一標識學習

在AndroidManifest配置文件中添加權限ui

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

具體獲取的方法以下,我是寫在工具類中的:spa

public static String getDeviceIdInfo(Context mContext) {
        //String imei = ((TelephonyManager) mContext.getSystemService(mContext.TELEPHONY_SERVICE)).getDeviceId();
        String imei = Secure.getString(mContext.getContentResolver(), Secure.ANDROID_ID);

        return imei;
    }

這種實現方式的缺點在於:code

1.遇到安全警覺性比較高的用戶,我不接受這樣的權限,不安裝你的App。blog

2.非手機設備,若是隻帶有Wifi的設備或者音樂播放器沒有通話的硬件功能的話就沒有這個DEVICE_ID。

3.做爲手機來說,IMEI是惟一的,它應該相似於359881030314356(除非你有一個沒有量產的手機(水貨)它可能有無效的IMEI,如:0000000000000)。說白了,若是隻爲了獲取它,沒有用到其餘的通話功能,那這個權限有點大才小用。

4.在少數的一些手機設備上,該實現有漏洞,會返回垃圾,如:zeros或者asterisks的產品。

第二種方式:獲取MAC ADDRESS

咱們也能夠經過手機的Wifi或者藍牙設備獲取MAC ADDRESS做爲DEVICE ID,可是並不建議這麼作,由於並非全部的設備都有Wifi,而且,若是Wifi沒有打開,那硬件設備沒法返回MAC ADDRESS.
The WLAN MAC Address string, 是另外一個惟一ID。毫無疑問你須要在AndroidManifest文件中添加以下權限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

代碼中的實現:

WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();

Returns: 00:11:22:33:44:55 (這不是一個真實的地址。並且這個地址能輕易地被僞造。).WLan沒必要打開,就可讀取些值。

第三種方式:BT MAC ADDRESS

只在有藍牙的設備上運行。而且要加入android.permission.BLUETOOTH 權限.

BluetoothAdapter m_BluetoothAdapter = null; // Local Bluetooth adapter
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();

Returns: 43:25:78:50:93:38 . 藍牙沒有必要打開,也能讀取。

第四種方式:Serial Number

裝有SIM卡的設備能夠經過getSystemService(Context.TELEPHONY_SERVIEC).getSimSerialNumber();獲取到
sim serial number。 注意對CDMA設備,返回的是一個空值。
在Android 2.3能夠經過android.os.Build.SERIAL獲取,非手機設備能夠經過該接口獲取。

第五種方式:ANDROID_ID

ANDROID_ID是設備第一次啓動時產生和存儲的64bit的一個數,當設備被wipe後該數重置
ANDROID_ID彷佛是獲取Device ID的一個好選擇,但它也有缺陷:

它在Android <=2.1 or Android >=2.3的版本是可靠、穩定的,但在2.2的版本並非100%可靠的
在主流廠商生產的設備上,有一個很常常的bug,就是每一個設備都會產生相同的ANDROID_ID:9774d56d682e549c

具體獲取的方法:

String m_szAndroidID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);

第六種方式:Installtion ID : UUID

這種方式也正是我最後採用的一種方式。

以上幾種方式都有或多或少存在的必定的侷限性或者bug,在這裏,有另一種方式解決,就是使用UUID,該方法無需訪問設備的資源,也跟設備類型無關。
這種方式是經過在程序安裝後第一次運行後生成一個ID實現的,但該方式跟設備惟一標識不同,它會由於不一樣的應用程序而產生不一樣的ID,而不是設備惟一ID。

所以常常用來標識在某個應用中的惟一ID(即Installtion ID),或者跟蹤應用的安裝數量。

我在程序中新建了這麼一個工具類來獲取這個UUID

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID;

import android.content.Context;

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {  
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();

        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}

綜上所述,我仍是比較推薦最後一種方式。若是還有別的實現方式你們能夠留言一塊兒學習討論。

相關文章
相關標籤/搜索