Android: How to programmatically access the device serial number shown in the AVD manager (API Version 8)

前端 未结 4 736
孤街浪徒
孤街浪徒 2020-11-28 07:54

How do I programmatically access the value shown in the image below ?

\"enter

相关标签:
4条回答
  • 2020-11-28 08:29

    Up to Android 7.1 (SDK 25)

    Until Android 7.1 you will get it with:

    Build.SERIAL
    

    From Android 8 (SDK 26)

    On Android 8 (SDK 26) and above, this field will return UNKNOWN and must be accessed with:

    Build.getSerial()
    

    which requires the dangerous permission android.permission.READ_PHONE_STATE.

    From Android Q (SDK 29)

    Since Android Q using Build.getSerial() gets a bit more complicated by requiring:

    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE (which can only be acquired by system apps), or for the calling package to be the device or profile owner and have the READ_PHONE_STATE permission. This means most apps won't be able to uses this feature. See the Android Q announcement from Google.

    See Android SDK reference


    Best Practice for Unique Device Identifier

    If you just require a unique identifier, it's best to avoid using hardware identifiers as Google continuously tries to make it harder to access them for privacy reasons. You could just generate a UUID.randomUUID().toString(); and save it the first time it needs to be accessed in e.g. shared preferences. Alternatively you could use ANDROID_ID which is a 8 byte long hex string unique to the device, user and (only Android 8+) app installation. For more info on that topic, see Best practices for unique identifiers.

    0 讨论(0)
  • 2020-11-28 08:37

    This is the hardware serial number. To access it on

    • Android Q (>= SDK 29) android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required. Only system apps can require this permission. If the calling package is the device or profile owner then the READ_PHONE_STATE permission suffices.

    • Android 8 and later (>= SDK 26) use android.os.Build.getSerial() which requires the dangerous permission READ_PHONE_STATE. Using android.os.Build.SERIAL returns android.os.Build.UNKNOWN.

    • Android 7.1 and earlier (<= SDK 25) and earlier android.os.Build.SERIAL does return a valid serial.

    It's unique for any device. If you are looking for possibilities on how to get/use a unique device id you should read here.

    For a solution involving reflection without requiring a permission see this answer.

    0 讨论(0)
  • 2020-11-28 08:38

    Build.SERIAL can be empty or sometimes return a different value (proof 1, proof 2) than what you can see in your device's settings.

    If you want a more complete and robust solution, I've compiled every possible solution I could found in a single gist. Here's a simplified version of it :

    public static String getSerialNumber() {
        String serialNumber;
    
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class);
    
            serialNumber = (String) get.invoke(c, "gsm.sn1");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "ril.serialnumber");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "ro.serialno");
            if (serialNumber.equals(""))
                serialNumber = (String) get.invoke(c, "sys.serialnumber");
            if (serialNumber.equals(""))
                serialNumber = Build.SERIAL;
    
            // If none of the methods above worked
            if (serialNumber.equals(""))
                serialNumber = null;
        } catch (Exception e) {
            e.printStackTrace();
            serialNumber = null;
        }
    
        return serialNumber;
    }
    

    I try to update the gist regularly whenever I can test on a new device or Android version. Contributions are welcome too.

    0 讨论(0)
  • 2020-11-28 08:38

    From Android P, defining the READ_PHONE_STATE permission in AndroidManifest only, will not work. We have to actually request for the permission. Below code works for me:

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 101);
        }
    }
    
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onResume() {
        super.onResume();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        Log.d(TAG,Build.getSerial());
    }
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 101:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
            } else {
                //not granted
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    

    Add this permissions in AndroidManifest.xml

    <uses-permission android:name = "android.permission.INTERNET"/>
    <uses-permission android:name = "android.permission.READ_PHONE_STATE" />
    

    Hope this helps.

    Thank You, MJ

    0 讨论(0)
提交回复
热议问题