了解Android設備唯一標識以及在開發中如何安全地使用這些標識符
Android設備唯一標識在開發中常被用于識別設備、進行用戶行為分析、實現個性化推送等功能。出于隱私和安全考慮,一些標識碼(如IMEI和MAC地址)的獲取和使用可能受到一定的限制。在開發過程中,需要遵守相關的隱私政策和法規,確保用戶數據的安全和合規性。
Android設備的唯一標識主要包括以下幾種:
- 「IMEI(國際移動設備識別碼)」:IMEI是International Mobile Equipment Identity的縮寫,即通常所說的手機序列號、手機“串號”。它是由15位數字組成的“電子串號”,相當于移動電話的身份證,用于在移動電話網絡中識別每一部獨立的手機等移動通信設備。IMEI碼由GSM(全球移動通信協會)統一分配,授權BABT(英國通信認證管理委員會)審受。
- 「MEID」:MEID是移動設備識別碼的另一種形式,主要用于CDMA制式的手機。
- 「MAC地址」:MAC地址是媒體訪問控制地址,也稱為物理地址或硬件地址,用于在網絡中唯一標識一個網絡設備。
- 「ANDROID_ID」:ANDROID_ID是Android系統為設備分配的一個唯一ID,主要用于應用程序內部識別設備。
- 「UUID(通用唯一識別碼)」:UUID是一個軟件建構的標準,亦為開放軟件基金會組織在分布式計算環境領域的一部分。其目的,是讓分布式系統中的所有元素,都能有唯一的辨識資訊,而不需要透過中央控制端來做辨識資訊的指定。
- 「OAID」:OAID(Open Anonymous Device Identifier,開放匿名設備標識符)是移動廣告行業為了遵循用戶隱私保護政策而推出的一種設備標識符。
IMEI
IMEI(國際移動設備識別碼)是一個重要的設備標識符,用于唯一地識別每一部移動電話。IMEI碼由15位數字組成,每部移動電話的IMEI碼都是獨一無二的。識別碼可以幫助運營商和制造商追蹤設備的來源和狀態,以及在需要時進行遠程控制。
在Android應用中獲取IMEI:
- 「添加權限」:在應用的AndroidManifest.xml文件中添加讀取電話狀態的權限。
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
- 「獲取TelephonyManager」:獲取一個TelephonyManager實例。
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- 「獲取IMEI」:使用TelephonyManager的getDeviceId()方法可以獲取設備的IMEI。
String imei = telephonyManager.getDeviceId();
注意點:
- 「隱私政策」:IMEI是設備的敏感信息,在獲取和使用IMEI之前,須確保應用遵守了相關的隱私政策和法規。需要在應用的隱私政策中明確告知用戶將收集和使用IMEI,并且獲得用戶的明確同意。
- 「權限變更」:從Android 6.0(API 級別 23)開始,運行時權限模型引入后,需要在運行時請求READ_PHONE_STATE權限。
- 「可用性」:在某些情況下,例如模擬器或者沒有SIM卡的設備,getDeviceId()可能會返回null或者一個非標準的值。在獲取IMEI后,應該檢查它是否為null或有效。
- 「兼容性」:對于Android 10(API 級別 29)及以上版本,由于隱私保護的增強,非系統應用可能無法訪問IMEI。在這種情況下可能需要尋找其他方式來標識設備或用戶。
- 「Google Play 政策」:確保應用遵守Google Play的政策,特別是在處理用戶數據方面。不當的數據收集和使用可能導致應用被從Google Play中移除。
MEID
MEID是移動設備識別碼的一種形式,主要用于CDMA制式的手機或通訊平板。類似于每部CDMA設備的“身份證號”,通過這個識別碼,網絡端可以對設備進行跟蹤和監管。在移動通信網絡中,MEID是識別移動設備的重要依據,有助于確保設備的合法性和在網絡中的正常使用。MEID也可以用于設備追蹤、保修驗證等目的。
在Android應用中獲取MEID:
- 「添加權限」:在AndroidManifest.xml文件中添加讀取電話狀態的權限。
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
- 「獲取TelephonyManager」:獲取一個TelephonyManager實例。
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- 「獲取MEID」:使用TelephonyManager的getMeid()方法可以獲取設備的MEID。
//8.0以后,區分IMEI和MEID
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "getImei:" + manager.getImei());
Log.d(TAG, "getMeid:" + manager.getMeid());
} else {
//8.0之前:不區分IMEI和MEID,在安卓8.0廢棄
Log.d(TAG, "getDeviceId:" + manager.getDeviceId());
}
MAC地址
MAC地址是指設備的物理地址,也叫做硬件地址。MAC地址是網絡設備在網絡中的唯一標識,由一串英文加數字的字符串組成,具有全球唯一性。每個網絡設備,包括手機、電腦、路由器等,都有一個唯一的MAC地址。這個地址不會隨網絡或位置的更改而變化,因此能夠準確地標識特定設備。
在Android設備上,可以通過特定的路徑查看MAC地址。一般可以在“設置”菜單中找到“關于手機”或“關于設備”選項,選擇“狀態消息”或“網絡狀態”等子菜單找到“WLAN MAC地址”或類似的選項。
Android MAC地址是設備在網絡中的唯一標識符,對于設備通信和網絡管理都起著關鍵作用,但也應注意其潛在的安全風險。
在Android設備上,有多種方法可以獲取MAC地址。以下是兩種常見的方法:
方法一:通過WifiManager獲取
- 通過getSystemService(Context.WIFI_SERVICE)方法獲取到WifiManager的實例。
- 使用getConnectionInfo()方法獲取到連接信息。
- 調用getMacAddress()方法獲取MAC地址。
方法二:通過NetworkInterface獲取
- 獲取設備上的網絡接口列表。通過調用NetworkInterface.getNetworkInterfaces()方法實現,方法會返回一個枚舉類型的網絡接口列表。
- 遍歷這個接口列表,找到以太網接口。
- 在找到以太網接口后,通過該接口的getHardwareAddress()方法獲取MAC地址。
從Android 6.0(API級別23)開始,運行時權限引入后,需要在運行時請求訪問網絡狀態的權限。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Android_id
ANDROID_ID是Android系統提供的一個用于標識設備的唯一ID。是一個64位的十六進制字符串,由16個字符組成,是設備特定的標識符,可以用于唯一地標識一個Android設備。
在Android 8.0(API 26級)和更高版本的平臺上,64位數字(表示為十六進制字符串),對于應用程序簽名密鑰、用戶和設備的每個組合都是唯一的。ANDROID_ID的值由簽名密鑰和用戶限定范圍。如果在設備上執行出廠重置或APK簽名密鑰發生更改,則該值可能會更改。
在低于Android 8.0(API 26級)的平臺版本中,用戶首次設置設備時隨機生成的64位數字(表示為十六進制字符串),在用戶設備的使用壽命內應保持不變。在具有多個用戶的設備上,每個用戶都顯示為一個完全獨立的設備,因此ANDROID_ID值對每個用戶都是唯一的。
ANDROID_ID的生成是基于設備的硬件信息和操作系統的版本號等,在同一臺設備上是固定的,但是在不同的設備上是不同的。ANDROID_ID是在設備首次啟動時生成的。存儲在設備的/data/data/com.android.providers.settings/databases/settings.db數據庫中的secure表中。在設備首次啟動時,系統會檢查secure表是否存在一個名為android_id的條目,如果不存在,則會生成一個唯一的ANDROID_ID,并插入到secure表中。如果設備被恢復出廠設置,則會重新生成一個新的ANDROID_ID。
雖然ANDROID_ID是唯一的,但不是100%可靠的,因為可以被某些應用程序修改或篡改。如果重置設備,ANDROID_ID也會被重置。刷機或者更換了ROM,ANDROID_ID也會被重置。
//在 Android 8.0(API 級別 26)及更高版本中,SSAID(AndroidID) 提供了一個在由同一開發者簽名密鑰簽名的應用之間通用的標識符。
//當設備恢復出廠設置,或者Root過的話,OTA升級系統,值會被改變
public static void getAndroidId(Context context){
String androidId = Settings.Secure.getString(context.getApplicationContext().getContentResolver(),Settings.Secure.ANDROID_ID);
Log.d(TAG, "androidId:" + androidId);
}
UUID
UUID(Universally Unique Identifier,全局唯一標識符)是一種軟件建構的標準,亦為開放軟件基金會(OSF)組織在分布式計算環境(DCE)領域的一部分。UUID是一個128位的字符串,通常以32個十六進制數字表示,按照8-4-4-4-12的36個字符格式分成五段,形式為8-4-4-4-12的32個字符,例如:550e8400-e29b-41d4-a716-446655440000。
UUID的主要目的是提供唯一性,減少沖突的可能性,并且不依賴于中央注冊機構來分配標識符。由于UUID的生成算法使用了一些隨機的元素(如當前的時間戳和機器標識符),因此它可以在不同的系統和應用程序中生成幾乎不重復的標識符。
//在大多數非廣告用例中,可用于跟蹤已注銷用戶的偏好設置,這是建議的解決方案
public static void getUUID(){
String uniqueID = UUID.randomUUID().toString();
Log.d(TAG, "UUID:" + uniqueID);
}
OAID
OAID(Open Anonymous Device Identifier,開放匿名設備標識符)是移動廣告行業為了遵循用戶隱私保護政策而推出的一種設備標識符。它的主要目的是在保護用戶隱私的前提下,為廣告主和開發者提供一種替代IMEI、Android ID等傳統設備標識符的方式,以便進行廣告跟蹤、效果衡量和個性化推送等操作。
OAID具有以下特點:
- 「匿名性」:OAID是匿名的,不會直接關聯到用戶的個人信息,從而保護了用戶的隱私。
- 「可重置性」:用戶可以在設備的設置中選擇重置OAID,廣告主和開發者就無法繼續追蹤該設備。
- 「合規性」:由于OAID遵循了用戶隱私保護政策,使用OAID進行廣告跟蹤和數據分析更符合法規要求。
在Android設備上,OAID通常由廣告服務提供商或設備制造商提供。開發者需要集成相應的SDK(軟件開發工具包)來獲取OAID。開發者可以將其用于廣告跟蹤、推送通知等目的。
具體使用可以查看各廠商的說明文檔手冊:
小米OAID: https://dev.mi.com/distribute/doc/details?pId=1634
OPPO OAID: https://open.oppomobile.com/new/developmentDoc/info?id=12344
華為OAID: https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/oaid-0000001050783198
考慮到隱私和安全的問題,如果應用不需要IMEI,MEID來進行關鍵功能,最好避免收集和使用。可以考慮使用其他方法來標識設備或用戶,比如使用ANDROID_ID,OAID或者生成一個UUID來在應用中標識設備。