/**
* 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
}
6条答案
按热度按时间cxfofazt1#
这是硬件序列号。要在
*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的可能性,你应该阅读here。
有关涉及反射而无需权限的解决方案,请参见this answer。
jvidinwx2#
最高支持安卓7.1(SDK 25)
在Android 7.1之前,您将获得以下功能:
来自Android 8(SDK 26)
在Android 8(SDK 26)及更高版本上,此字段将返回
UNKNOWN
,必须使用以下命令访问:这需要危险许可
android.permission.READ_PHONE_STATE
。来自Android Q(SDK 29)
由于使用
Build.getSerial()
的Android Q变得有点复杂,需要:android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
(只能由系统应用获取),或用于调用包成为 * 设备或配置文件所有者 * 并具有READ_PHONE_STATE
权限。这意味着大多数应用将无法使用此功能。请参阅Google的Android Q公告。查看Android SDK参考
设备唯一标识最佳实践
如果你只需要一个唯一的标识符,最好避免使用硬件标识符,因为谷歌出于隐私原因不断试图使访问它们变得更加困难。你可以只生成一个
UUID.randomUUID().toString();
,并在第一次需要访问时将其保存在例如共享首选项中。或者,你可以使用ANDROID_ID
,这是一个8字节长的十六进制字符串,对设备来说是唯一的。用户和(仅限Android 8+)应用程序安装。有关该主题的更多信息,请参阅Best practices for unique identifiers。xlpyo6sf3#
Build.SERIAL
can be empty或有时返回与设备设置中显示的值不同的值(proof 1,proof 2)。如果你想要一个更完整和健壮的解决方案,我已经编译了我在一个gist中找到的所有可能的解决方案。下面是它的简化版本:
每当我可以在新设备或Android版本上测试时,我都会定期更新要点。
06odsfpq4#
从Android P,只在AndroidManifest中定义READ_PHONE_STATE权限,将不起作用。我们必须实际请求权限。下面的代码对我来说很有效:
在AndroidManifest.xml中添加此权限
希望这个有用。
谢谢MJ
zvokhttg5#
我喜欢我的解决方案:
在AndroidManifest.xml中添加此权限
yx2lnoni6#
如果你想在较新的Android版本和Android模拟器上工作的东西,这可能会有所帮助:
注意:不要忘记给予必要的权限.(可能无法在Android 11和12没有系统级权限)