如何以编程方式访问下图中显示的值?
5 回答
这是硬件序列号。访问它
需要Android Q (>= SDK 29)
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
。只有系统应用程序可以要求此权限。如果调用包是设备或配置文件所有者,则READ_PHONE_STATE
权限就足够了。Android 8 及更高版本(>= SDK 26) 使用
android.os.Build.getSerial()
需要危险权限READ_PHONE_STATE。使用android.os.Build.SERIAL
返回android.os.Build.UNKNOWN。Android 7.1 及更早版本(<= SDK 25) 及更早版本
android.os.Build.SERIAL
会返回有效的序列号。
它对于任何设备都是独一无二的。如果您正在寻找有关如何获取/使用唯一设备 ID 的可能性,您应该阅读此处。
有关无需许可而涉及反射的解决方案,请参阅此答案。
高达 Android 7.1 (SDK 25)
在 Android 7.1 之前,您将获得它:
Build.SERIAL
从 Android 8 (SDK 26)
在 Android 8 (SDK 26) 及更高版本上,此字段将返回UNKNOWN
并且必须通过以下方式访问:
Build.getSerial()
这需要危险的许可
android.permission.READ_PHONE_STATE
。
来自 Android Q (SDK 29)
由于 Android Q 的使用Build.getSerial()
变得有点复杂,需要:
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
(只能由系统应用获取),或者调用包为设备或配置文件所有者并具有READ_PHONE_STATE
权限。这意味着大多数应用程序将无法使用此功能。请参阅 Google 的Android Q 公告。
唯一设备标识符的最佳实践
如果您只需要一个唯一标识符,最好避免使用硬件标识符,因为 Google 出于隐私原因不断尝试使其更难访问它们。UUID.randomUUID().toString();
您可以在第一次需要在共享首选项中访问它时生成并保存它。或者,您可以使用ANDROID_ID
设备、用户和(仅限 Android 8+)应用程序安装唯一的 8 字节长十六进制字符串。有关该主题的更多信息,请参阅唯一标识符的最佳实践。
Build.SERIAL
可以为空或有时返回与您在设备设置中看到的值不同的值(证明 1、证明 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 版本上进行测试时,我都会尝试定期更新要点。也欢迎投稿。
从 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
我喜欢我的解决方案:
/**
* 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" />