由于項目需要,最近在調用Android設備唯一標識符方案。由于項目涉及支付相關內容,對設備唯一標識符識別有較高的準確率要求。而考慮到項目app在海外運營,主要通過google play store發布,而google由于GDPR等政策最近對設備標識符采集進行了嚴控,如何才能在不采集用戶危險權限的前提下,準確唯一的標識到用戶的設備呢?這里分享下方案輸出前期的一些調研內容。
IMEI/MEID/Device ID
國際移動設備識別碼(International Mobile Equipment Identity,IMEI)
國際移動設備識別碼一般貼于機身背面與外包裝上,同時也存在于手機內存中,通過輸入*#06#即可查詢
GSM設備返回的是IMEI碼,CDMA設備返回的是MEID碼或者ESN碼
雙卡雙待手機存在兩個,需根據具體硬件適配獲取
只有Android手機才有,非手機設備沒有
需要權限:android.permission.READ_PHONE_STATE
TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
String szImei = TelephonyMgr.getDeviceId();
IMSI
國際移動用戶識別碼(IMSI:International Mobile Subscriber Identification Number)
儲存在SIM卡中, 跟SIM卡綁定的,更換SIM卡就會發生變化
在僅支持wifi的pad設備上是沒有的
需要權限:android.permission.READ_PHONE_STATE
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String imsi = manager.getSubscriberId();
Android ID
在設備首次啟動時,系統會隨機生成一個64位的數字,并把這個數字以16進制字符串的形式保存下來,即Android id
恢復出廠設置,重新生成
root手機,可以改寫
部分廠商bug,導致補發機型上Android id相同
不需要權限,與系統強依賴,穩定性不足
String m_szAndroidID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
MAC地址
手機wifi無線網卡的MAC地址,與終端硬件關聯,可用作設備的唯一標識
從Android 6.0開始,系統接口采集到的MAC地址返回固定串:02:00:00:00:00:00
未連wifi獲取不到,需要權限: android.permission.ACCESS_WIFI_STATE
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
藍牙MAC
從Android 6.0開始,系統接口統一返回:02:00:00:00:00:00
需要權限: android.permission.BLUETOOTH
BluetoothAdapter m_BluetoothAdapter = null;
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();
Pseudo-Unique ID
API<9時,通過讀取設備的ROM版本號、廠商名、CPU型號和其他硬件信息來組合出一串15位的號碼
API >=9時,通過“Build.SERIAL”這個屬性來保證ID的獨一無二
//獲得獨一無二的Psuedo ID
public static String getUniquePsuedoID() {
String serial = null;
String m_szDevIDShort = "35" +
Build.BOARD.length()%10+ Build.BRAND.length()%10 +
Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
Build.TAGS.length()%10 + Build.TYPE.length()%10 +
Build.USER.length()%10 ; //13 位
try {
serial = android.os.Build.class.getField("SERIAL").get(null).toString();
//API>=9 使用serial號
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
//serial需要一個初始化,隨意值
serial = "serial";
}
//使用硬件信息拼湊出來的15位號碼
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
存在問題
翻看Build.class的源碼,可以發現字段SERIAL已經被標注為@Deprecated了,google建議通過新接口getSerial獲取手機的序列號。這里存在問題:
- 被標注為@Deprecated的SERIAL以后可能被google下掉(或加入黑名單),后續通過反射或許拿不到。
-
getSerial接口需要READ_PHOE_STATE權限
企業微信截圖_15560952357236.png
參考