Android手機裝置唯一識別符號
在Android App開發過程中有時需要確定手機裝置的唯一性。但是Android 手機裝置的唯一標識的獲取並不能保持每次都能獲取成功,因而無法保持手機的唯一性。Android手機獲取唯一標識一直沒有統一標準,每個公司都有自己的一套規則。首先說一下幾種比較常用的作為手機裝置唯一標識的:
IMEI
範圍:只能支援擁有通話功能的裝置,對於平板不可以。
永續性:返廠,資料擦除的時候不徹底,保留了原來的標識。
許可權:需要許可權:Android.permission.READ_PHONE_STATE
bug: 有些廠家的實現有bug,返回一些不可用的資料Mac地址
範圍:有支援無限上網的裝置
許可權:需要ACCESS_WIFI_STATE許可權
永續性:有些裝置沒有WiFi,或者藍芽,就不可以,如果WiFi沒有開啟,硬體也不會返回Mac地址,不建議使用Android_ID
範圍:所有Android系統裝置
Bug:2.2(Froyo,8)版本系統會不可信,來自主要生產廠商的主流手機,至少有一個普遍發現的bug,這些有問題的手機相同的ANDROID_ID: 9774d56d682e549c但是如果返廠的手機,或者被root的手機,可能會變Serial Number
範圍:從android 2.3 (“Gingerbread”)開始可用,可以通過android.os.Build.SERIAL獲取,對於沒有通話功能的裝置,它會返回一個唯一的device ID,
驗證在手機Wifi關閉情況下獲取標識的情況:
品牌 | 型號 | 系統版本 | IMEI | Mac | Android id | Serial Number |
---|---|---|---|---|---|---|
Vivo | X5Pro V | 5.0.2 | 有 | 有 | 有 | 有 |
Oppo | R7s | 4.4.4 | 有 | 有 | 有 | 有 |
華為 | ALE-UL00 | 5.0.2 | 有 | 有 | 有 | 有 |
小米 | Redmi note2 | 5.0.2 | 有 | 有 | 有 | 有 |
小米 | 4LTE | 6.0.1 | 有 | 無 | 有 | 有 |
魅族 | M2 note | 5.1 | 有 | 有 | 有 | 有 |
HTC | m8sw | 5.0.2 | 有 | 有 | 有 | 有 |
華為 | MT7-TL10 | 5.1.1 | 有 | 有 | 有 | 有 |
三星 | SM-G9200 | 6.0.1 | 有 | 無 | 有 | 有 |
- 生成方案
常見手機裝置唯一表示碼選擇上面的一種或幾種,但是部分手機的Mac碼的獲取會與Wifi狀態有關,改動較大因此捨棄Mac碼。挑選出IMEI碼、Android ID、Serial Number拼接成一個字串,然後通過MD5加密生成一個唯一標識。
IMEI碼、Android ID、Serial Number的獲取:
String macId = getMacAddress(this);
Log.e("yushan", "macId:::" + macId);
String IMIESId = getIMIEStatus(this);
Log.e("yushan", "IMIESId:::" + IMIESId);
String AndroidId = getAndroidId(this);
Log.e("yushan", "AndroidId:::" + AndroidId);
String AndroidSerial = getAndroidSerial();
Log.e("yushan", "AndroidSerial:::" + AndroidSerial);
public static String getMacAddress(Context context) {
String macAddress = null;
WifiInfo wifiInfo = getWifiInfo(context);
if (wifiInfo != null) {
macAddress = wifiInfo.getMacAddress();
}
return macAddress;
}
/**
* 獲取WifiInfo
*/
public static WifiInfo getWifiInfo(Context context) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = null;
if (null != wifiManager) {
info = wifiManager.getConnectionInfo();
}
return info;
}
private static String getIMIEStatus(Context context) {
String deviceId = "";
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
} else {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
deviceId = tm.getDeviceId();
}
return deviceId;
}
private static String getAndroidId(Context context) {
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
return androidId;
}
private String getAndroidSerial() {
String serialNum = Build.SERIAL;
return serialNum;
}
通過MD5加密生成唯一標識:
String pseudoId = "21" + // 加鹽
getIMIEStatus(this) + // IMEI碼
getAndroidSerial() + // Serial num
getAndroidId(this); // Android Id
String md5Str = makeMD5(pseudoId);
Log.e("yushan", "md5Str:::" + md5Str);
// MD5加密
public static String makeMD5(String password) {
try {
// 生成一個MD5加密計算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 計算md5函式
md.update(password.getBytes());
// digest()最後確定返回md5 hash值,返回值為8為字串。因為md5 hash值是16位的hex值,實際上就是8位的字元
// BigInteger函式則將8位的字串轉換成16位hex值,用字串來表示;得到字串形式的hash值
return new BigInteger(1, md.digest()).toString(16);
} catch (Exception e) {
e.printStackTrace();
}
return password;
}
關於Android 手機裝置唯一識別符號的生成就到這裡,希望這篇部落格能夠為小夥伴們提供一些幫助。