Build.SERIALREAD_PHONE_STATE 權限"unknown" 或空值通過反射調用 Build.getString("ro.serialno"),該屬性在底層屬性系統中廣泛存在,兼容性極佳。
import android.os.Build;
import java.lang.reflect.Method;
public class DeviceIdUtils {
/**
* 獲取設備序列號,兼容 API 9 以下設備
* @return 序列號字符串,失敗返回 "unknown"
*/
public static String getDeviceSerial() {
String serial = "unknown";
try {
Class> buildClass = Class.forName("android.os.Build");
Class> stringClass = Class.forName("java.lang.String");
// 獲取隱藏方法:public String getString(String key)
Method getStringMethod = buildClass.getDeclaredMethod("getString", stringClass);
if (!getStringMethod.isAccessible()) {
getStringMethod.setAccessible(true); // 突破訪問限制
}
// 調用靜態方法,傳入屬性鍵
Object result = getStringMethod.invoke(null, "ro.serialno");
if (result instanceof String) {
serial = (String) result;
}
} catch (ClassNotFoundException | NoSuchMethodException |
IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return serial;
}
}
| 技術點 | 說明 |
|---|---|
Class.forName |
動態加載類,避免編譯期依賴不存在的 API |
getDeclaredMethod |
獲取聲明的方法(含 private/hidden),不查找父類 |
setAccessible(true) |
關鍵步驟:繞過 Java 訪問檢查,調用隱藏/私有方法 |
invoke(null, ...) |
靜態方法調用,第一個參數為 null |
ro.serialno |
Android 系統屬性鍵,對應 /default.prop 中的 ro.serialno |
public static String getSerialNumber(Context context) {
// 1. 標準 API (API 9+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
String serial = Build.SERIAL;
if (!"unknown".equals(serial) && !TextUtils.isEmpty(serial)) {
return serial;
}
}
// 2. 反射隱藏 API (全版本)
String serial = getDeviceSerialByReflection();
if (!"unknown".equals(serial)) return serial;
// 3. 讀取文件 (部分設備)
serial = readFromFile("/sys/class/android_usb/android0/iSerial");
if (serial != null) return serial;
// 4. 最後兜底:隨機生成並持久化
return generateAndSavePseudoId(context);
}
private static String readFromFile(String path) {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return null;
}
}
Build.SERIAL、getSerial() 均需 READ_PRIVILEGED_PHONE_STATE(系統應用專用)Settings.Secure.ANDROID_ID、廣告 ID (GAID) 或自生成 UUID掌握反射調用隱藏系統屬性,是 Android 開發處理碎片化、獲取設備唯一標識的核心技能之一。