白嫖黨可直接下滑到最後 (手動滑稽) 繞開那些不太完美的辦法
場景
最近在做一個OA考勤項目,裏面有個需求是一個賬號只允許綁定一臺設備, 這就需要將設備唯一標識碼與賬號綁定在一起,咋一聽 這還不So Easy啊,直接獲取deviceID 不就好了。。。
問題
private String getSerial() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return Build.getSerial();
} else {
return Build.SERIAL;
}
}
咋一操作也挺好。 可到了大面積的羣體用戶測試環節發現了幾個問題。
- 需要獲取手機READ_PHONE_STATE權限,這個權限涉及的信息還挺多。我們爲了設備id有點大材小用
- 在努比亞和一加手機上有返回null 和 000000 ,應該是廠商在這方面做了特別的處理來保護用戶隱私
- 在Android10 就已經完全獲取不到,返回unknown
- 如果是雙卡,其中一張卡是電信的,手機是小米的,那麼你更換卡槽的位置,deviceId會從IMIE1 變爲MEID。華爲、榮耀等機型未發現。(當然也有解決辦法獲取 getDeviceId(0)的方式)
在Android 10以下版本雖然可以獲取到IMEI碼,但是需要在應用獲取到了READ_PHONE_STATE權限,並且我們仍然沒法保證所有的設備都能正常返回
簡言之就是如果你的手機需要考慮Android9以上的設備,你就沒辦法通過獲取系統提供的API完全的獲取到設備唯一標識碼,根據Android文檔唯一標識符最佳做法你也許可以這樣…
呃… 這個特殊運營商許可 和這個 READ_PRIVILEGED_PHONE_STATE
好像都不是我們一般的安卓應用能獲取的到的。
想要能Android9以上又能不受到刷機,格式化的影響。 就只能 使用移動安全聯盟(MSA)提出的補充設備標識
是由移動安全聯盟提出的,包含以下三個標識:
名稱 | 說明 |
---|---|
OAID | 匿名設備標識符,最長64爲,所有應用都獲取到同一個ID,但是用戶可關閉、可重置 |
AAID | 應用匿名設備標識符,最長64爲,每個應用獲取到各自的ID |
VAID | 開發者匿名設備標識符,最長64爲,同一開發者不同應用獲取到的一致 |
缺點就是:並不是所有的品牌商都兼容了, 而且需要導入他們對應的包 。 這部分可參考 Android 10獲取設備標識方案探究 這篇文章
樓主的做法
androidId + 序列號+ 硬件信息(品牌+型號)
特點: 如果格式化或者刷機,這個設備ID會更改(這個也是合理的)。
完善:可以在第一次生成後放入到內部存儲和外部存儲,下次進入先從內部存儲獲取,如果沒有在去外部存儲比較(App卸載,內部存儲就沒了)。 如果在沒有就生成一個
public class SystemUtils {
/**
* ANDROID_ID(恢復出廠+刷機會變) + 序列號(android 10會unknown/android 9需要設備權限)+品牌 +機型
* @return
*/
@SuppressLint("MissingPermission")
public static String getUniqueIdentificationCode(FragmentActivity context){
String androidId = Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
String uniqueCode ;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
/** 需要權限 且僅適用9.0。 10.0後又不能獲取了*/
uniqueCode = androidId + Build.getSerial()+Build.BRAND+ Build.MODEL;
}else{
uniqueCode = androidId + Build.SERIAL+Build.BRAND+ Build.MODEL;
}
return toMD5(uniqueCode);
}
/**
* MD5加密 格式一致
*/
private static String toMD5(String text){
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
byte[] digest = messageDigest.digest(text.getBytes());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
int digestInt = digest[i] & 0xff;
//將10進制轉化爲較短的16進制
String hexString = Integer.toHexString(digestInt);
if (hexString.length() < 2) {
sb.append(0);
}
sb.append(hexString);
}
return sb.toString().substring(8,24);
}
}