Android:如何以编程方式访问AVD管理器中显示的设备序列号(API版本8)

时间:2012-06-14 08:25:30

标签: android serial-number

如何以编程方式访问下图中显示的值?

enter image description here

5 个答案:

答案 0 :(得分:68)

这是硬件序列号。

访问它

它对任何设备都是独一无二的。如果您正在寻找获取/使用唯一设备ID的可能性,请阅读here

对于涉及反射但无需许可的解决方案,请参阅this answer

答案 1 :(得分:32)

高达Android 7.1(SDK 25)

在Android 7.1之前,您将获得:

Build.SERIAL

来自Android 8(SDK 26)

在Android 8(SDK 26)及更高版本上,此字段将返回UNKNOWN,必须使用以下网址进行访问:

Build.getSerial()

需要dangerous permission  android.permission.READ_PHONE_STATE

来自Android Q(SDK 29)

由于使用Build.getSerial()的Android Q因要求而变得更加复杂:

android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE(只能由系统应用获取),,以便将调用包作为设备或个人资料所有者并拥有{{ 3}}权限。这意味着大多数应用都无法使用此功能。请参阅Google的READ_PHONE_STATE

请参阅Android Q announcement

唯一设备标识符的最佳实践

如果您只需要一个唯一标识符,最好避免使用硬件标识符,因为Google会出于隐私原因不断尝试访问它们。您可以生成UUID.randomUUID().toString();并在第一次需要访问时保存它。共享偏好。或者,您可以使用Android SDK reference,这是一个8字节长的十六进制字符串,对于设备,用户和(仅限Android 8+)应用程序安装是唯一的。有关该主题的更多信息,请参阅ANDROID_ID

答案 2 :(得分:7)

Build.SERIAL can be empty,或者有时返回的值(proof 1proof 2)不同于您在设备设置中看到的值。

如果您想要一个更完整,更强大的解决方案,我已经在一个gist中汇编了所有可能找到的解决方案。这是它的简化版本:

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;
}

只要能在新设备或Android版本上进行测试,我都会定期更新要点。也欢迎捐款。

答案 3 :(得分:0)

在Android P中,仅在AndroidManifest中定义READ_PHONE_STATE权限将不起作用。我们必须实际请求许可。下面的代码对我有用:

@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);
    }
}

在AndroidManifest.xml中添加此权限

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

希望这会有所帮助。

谢谢, MJ

答案 4 :(得分:0)

我喜欢我的解决方案:

/**
 * Checks some permission
 *
 * @return true - If have any of the permissions sent by parameter
 * @return true - If you do not have any of the permissions sent by parameter
 */
fun Context.hasPermissionSome(vararg permissions: String): Boolean {
    permissions.forEach { permission ->
        if (hasPermission(permission)) {
            return true
        }
    }
    return false
}

@CheckResult
fun validateValue(value: String?, valueToCompare: String? = null): Boolean {
    if (!value.isNullOrEmpty() && value != Build.UNKNOWN && value != valueToCompare)
        return true

    return false
}

/**
 * @see: https://developer.android.com/about/versions/10/privacy/changes#data-ids
 *
 * Retrieve SerialNumber with system commands:
 *   adb shell getprop ro.serialno
 *   adb shell getprop ro.boot.serialno
 *   adb shell getprop ril.serialnumber
 * @return device Serial Number obtained with SystemProperties
 */
@SuppressLint("PrivateApi")
private fun serialNumberBySysProp(): String? {
    var sn: String? = null

    val readPhonePermissions = arrayOf(
        Manifest.permission.READ_PHONE_STATE,
        "android.permission.READ_PRIVILEGED_PHONE_STATE"
    )

    if (!this.context.hasPermissionSome(*readPhonePermissions))
        return sn

    try {
        val systemProps = Class.forName("android.os.SystemProperties")
        val getProp = systemProps.getMethod("get", String::class.java)
        
        // 1ª tentativa
        sn = getProp("ril.serialnumber") as String?
        if (validateValue(sn)) {
            return sn
        }

        // 2ª tentativa
        sn = getProp("ro.serialno") as String?
        if (validateValue(sn)) {
            return sn
        }

        // 3ª tentativa
        sn = getProp("ro.boot.serialno") as String?
        if (validateValue(sn)) {
            return sn
        }

        // 4ª tentativa
        sn = getProp("sys.serialnumber") as String?
        if (validateValue(sn)) {
            return sn
        }

    } catch (e: Exception) { }

    return if (validateValue(sn))
        sn
    else
        null
}

/**
 * @return device Serial Number obtained with Build Class
 */
@SuppressLint("HardwareIds")
private fun serialNumberByBuild(): String? {
    var sn: String? = null
    MediaDrm.PROPERTY_DEVICE_UNIQUE_ID
    if (!this.context.hasPermissionSome(
            Manifest.permission.READ_PHONE_STATE,
            "android.permission.READ_PRIVILEGED_PHONE_STATE"
        ))
        return sn

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        sn = Build.getSerial()
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        sn = Build.getSerial()
    } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
        sn = Build.getSerial()

        if (!validateValue(sn))
            sn = Build.SERIAL
    }

    return if (validateValue(sn))
        sn
    else
        null
}

val serialNumber: String
    @SuppressLint("HardwareIds", "PrivateApi", "MissingPermission", "StaticFieldLeak")
    get() {
        var serial: String = serialNumberByBuild() ?: ""

        if (!validateValue(serial)) {
            serial = serialNumberBySysProp() ?: ""
        }

        return serial
    }

在 AndroidManifest.xml 中添加此权限

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