Keywords: Android Serial Number | Device Identifier | API Version Compatibility
Abstract: This article provides an in-depth exploration of programmatic access methods for Android device serial numbers, covering the complete evolution from early versions to the latest Android Q (API 29). By analyzing permission requirements and technical implementation differences across various API levels, it详细介绍 the usage scenarios and limitations of core methods such as Build.SERIAL and Build.getSerial(). The article also discusses the feasibility of reflection techniques as alternative approaches and proposes best practice recommendations for using UUID or ANDROID_ID as device unique identifiers based on privacy protection trends. Combining official documentation with practical development experience, it offers comprehensive and reliable technical reference for Android developers.
In Android application development, obtaining the device serial number is a common requirement, particularly in scenarios such as device management, license validation, and statistical analysis. However, as the Android system continues to evolve, the methods and permission requirements for accessing the device serial number have undergone significant changes. This article systematically梳理 the implementation solutions across different API levels from a technical perspective, helping developers correctly address this challenge.
Android 7.1 and Earlier (API 25 and Below)
In Android 7.1 and earlier versions, developers can directly obtain the device serial number through the android.os.Build.SERIAL field. This is a static field that can be accessed without any special permissions. Example code is as follows:
String serialNumber = Build.SERIAL;
This method is straightforward, but it is important to note that on some devices, this field may return an empty string or inaccurate values. Therefore, in practical applications, it is recommended to add null checks and exception handling mechanisms.
Android 8 and Later (API 26 and Above)
Starting from Android 8 (Oreo), the behavior of the Build.SERIAL field has changed. According to official documentation, this field now returns android.os.Build.UNKNOWN. To obtain the actual serial number, the new Build.getSerial() method must be used.
Using Build.getSerial() requires the READ_PHONE_STATE dangerous permission. Developers must declare this permission in AndroidManifest.xml and request authorization from users at runtime. Below is a complete implementation example:
// Add permission declaration in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
// Request permission in Activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE},
REQUEST_CODE);
}
// Obtain serial number after permission is granted
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String serialNumber = Build.getSerial();
}
Android Q and Later (API 29 and Above)
Android Q further tightens access permissions for device identifiers. For the Build.getSerial() method, the READ_PRIVILEGED_PHONE_STATE permission is now required, which is restricted to system applications. For regular applications, serial number access is only possible under the following two conditions:
- The application is the device owner or profile owner
- The application has the
READ_PHONE_STATEpermission and runs in a device owner or profile owner environment
This change reflects Google's emphasis on user privacy protection. Developers need to reassess whether hardware serial number access is truly necessary or if alternative solutions can be used.
Alternative Approaches and Reflection Techniques
For situations where necessary permissions cannot be obtained, some developers attempt to access system properties using reflection techniques. Below is an example of obtaining the serial number through reflection:
public static String getSerialNumber() {
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method getMethod = c.getMethod("get", String.class);
String[] propertyKeys = {
"gsm.sn1",
"ril.serialnumber",
"ro.serialno",
"sys.serialnumber"
};
for (String key : propertyKeys) {
String value = (String) getMethod.invoke(c, key);
if (value != null && !value.trim().isEmpty()) {
return value;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return Build.SERIAL;
}
It is important to note that this method relies on undocumented system properties, which may vary across different devices and Android versions, and could become ineffective in future system updates. Therefore, it is not recommended to overly depend on this method in production environments.
Best Practice Recommendations
Considering privacy protection trends and technical feasibility, developers are advised to follow these best practices:
- Evaluate Actual Needs: Carefully consider whether the hardware serial number is truly necessary. In many cases, application-specific identifiers may be more appropriate.
- Use Alternative Identifiers: Consider the following alternative solutions:
UUID.randomUUID().toString(): Generate a unique identifier and store it in SharedPreferencesSettings.Secure.ANDROID_ID: On Android 8 and above, this ID is unique to the device, user, and application installation- Firebase Installation ID: Provides a stable cross-platform device identifier
- Progressive Feature Degradation: Implement multi-level fallback mechanisms, prioritizing officially recommended methods and attempting alternatives only when necessary.
- Clear User Notification: If access to sensitive information is required, clearly explain the purpose to users and obtain explicit consent.
By adhering to these best practices, developers can meet functional requirements while better protecting user privacy and ensuring long-term application compatibility.