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