Compatible writing method for Android 8 and Android 9 to obtain the serial number of the mobile phone

With the update of the Android version, the way to obtain the serial number of the phone is also different. I saw it at work recently, and the information is summarized here.

1. Get the compatible writing of the serial number


public class MainActivity extends AppCompatActivity {
    
    


    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int CODE_READ_PHONE_STATE = 0x11;
    private String serialNumber = "UNKNOWN";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "current Build.VERSION.SDK_INT: "+Build.VERSION.SDK_INT);
        getSerialNumber();
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    public void checkPermission() {
    
    
        if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
    
    
            requestPermissions(new String[]{
    
    Manifest.permission.READ_PHONE_STATE}, CODE_READ_PHONE_STATE);
        } else {
    
    
            serialNumber = Build.getSerial();
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.O)
    @SuppressLint("MissingPermission")
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    
    
        if (requestCode == CODE_READ_PHONE_STATE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
    
            serialNumber = Build.getSerial();
        } else {
    
    
            Log.i(TAG, "you deny the permission:READ_PHONE_STATE");
        }
    }

    @SuppressLint("HardwareIds")
    public String getSerialNumber() {
    
    

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    
    // 版本>=android Q(安卓10)
            Log.i(TAG, "TODO use yourself style ");
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
    
     // android O_MR1(安卓8.1)、安卓9
            checkPermission();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    
    // android O(安卓 8.0)
            this.serialNumber = Build.SERIAL;
        }else {
    
    //below android 8.0
            try {
    
    
                // 方式1:执行adb 命令获得
                Runtime runtime = Runtime.getRuntime();
                Process process = null;
                process = runtime.exec("getprop ro.serialno");
                InputStream is = process.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                this.serialNumber = br.readLine();
                // 方式2:反射获得(不推荐使用)
//                Class<?> c = Class.forName("android.os.SystemProperties");
//                Method get = c.getMethod("get", String.class);
//                serialNumber = (String) get.invoke(c, "ro.serialno");
//                Log.i(TAG, "  sdk version low android O ,reflect get" + serialNumber);
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        return serialNumber;
    }
}

2. The test process and its conclusion

1. How to obtain the Build.SERIAL field

1. This field appeared in Android api 9, Api26 (8.0) began to be abandoned. But 8.0 (api 26) can still be used on 8.1 and can not use this field to obtain.
2. Android 8.1 and above will return the UNKNOWN string when obtained in this way.
3. 8.0 is obsolete, and it is recommended to use Build.getSerial() instead of 8.0 and above.

Insert picture description here
Personal conclusion:

  • 8.0 can also be obtained in this way, because the getSerial() method requires the "read phone state" permission, and the user must always decide when reading the mobile phone permission, which is relatively restrictive.
2. About the acquisition method of Build.getSerial()

(1) Test conclusion:

  • Android Q (api 29) crashes directly on the mobile phone, that is, the user implements the method of obtaining the serial number from Q, such as querying from a database defined by himself.
  • Available on Android 8.1 (O, api 27), Android 9 (P, api 28), need "read phone state" permission, otherwise it will crash
  • Build.getSerial() is a deprecated alternative to Build.SERIAL on Android 8.1-9.0.

(2) Alternatives on Android 10 (ie Android Q, api 29)

The official document says this: Android 10 began to obtain the persistence indicator, which was restricted by Google. It is recommended to use a resettable identifier. But the following situations are excluded (available):
1. The app is a pre-installed app in the system and has been granted the READ_PRIVILEGED_PHONE_STATE permission.
2. If the app is the owner of the device or configuration file and has been granted Manifest.permission to read the phone status permission. A profile owner is an application that has a managed profile on the device; for more details, see Work Profile. Profile owner access is deprecated and will be removed in a future version.
3. If the call app has operator privileges for any activity subscription.
4. If the app is the default SMS role holder (refer to RoleManager.isRoleHeld(String) for understanding),
if it is not the above four cases:
1. Android 8.1 and above, use Build.SERIAL to return Build#UNKNOWN
2. Android 8.0 to Use Build.getSerial on Android 9.0 and throw a security exception without the READ_PHONE_STATE permission system
3. Android 10 starts to use Build.getSerial system and throw a security exception

3. Thinking about the acquisition method below 8.0 in the code

(1) Obtained by Build.SERIAL

This method of acquisition supports up to 8.0 and below, but many online articles below 8.0 are obtained using reflection or executing commands. I think this method is probably added by api 9. Although almost no one uses machines below api9, this This is not compatible. Using reflection or executing commands is truly compatible!

(2) Execute command or reflection to obtain test

1. The value obtained in the 8.0 (>=8.0) version of the two is empty, and it can be obtained below 8.0.
2. It is not recommended to use reflection to obtain it. Reflection affects performance, and it is still unsafe (as shown below)

Insert picture description here

References:
1. Best practices for unique identifiers
2. Build.SERIAL
3. Build.getSerial

The end

Gives a plan that I summarized,,,,, Yo-Yo.

Guess you like

Origin blog.csdn.net/qq_38350635/article/details/105420185