Как программно получить доступ к значению, показанному на изображении ниже?
Android: как программно получить доступ к серийному номеру устройства, указанному в диспетчере AVD (API версии 8)
Ответы (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
возвращает действительный серийный номер.
Он уникален для любого устройства. Если вы ищете возможности получения / использования уникального идентификатора устройства, вам следует прочитать здесь.
Решение, включающее отражение без разрешения, см. В этом ответе.
До Android 7.1 (SDK 25)
До Android 7.1 вы получите:
Build.SERIAL
Начиная с Android 8 (SDK 26)
В Android 8 (SDK 26) и выше в этом поле будет возвращено _2 _ и должен быть доступен с помощью:
Build.getSerial()
для которого требуется опасное разрешение _ 4_.
Из Android Q (SDK 29)
Поскольку Android Q с использованием Build.getSerial()
становится немного сложнее, требуя:
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
(который может быть получен только системными приложениями), или для вызывающего пакета, который должен быть владельцем устройства или профиля и иметь _ 7_ разрешение. Это означает, что большинство приложений не смогут использовать эту функцию. См. объявление об Android Q от Google.
См. справочник по Android SDK.
Лучшая практика для уникального идентификатора устройства
Если вам просто нужен уникальный идентификатор, лучше избегать использования аппаратных идентификаторов, поскольку Google постоянно пытается затруднить доступ к ним из соображений конфиденциальности. Вы можете просто создать UUID.randomUUID().toString();
и сохранить его при первом обращении, например, общие предпочтения. В качестве альтернативы вы можете использовать ANDROID_ID
, который представляет собой уникальную 8-байтовую шестнадцатеричную строку на устройство, пользователя и установку приложения (только для Android 8+). Для получения дополнительной информации по этой теме см. Рекомендации по уникальным идентификаторам.
UUID.randomUUID().toString()
всегда отличается - ›вот почему вы должны настаивать, но сброс к заводским настройкам, конечно, удаляет его. ANDROID_ID на самом деле не определен, но ожидайте, что он также будет другим.
- person Patrick Favre; 20.01.2020
Build.SERIAL
может быть пустым или иногда возвращать другое значение (доказательство 1, proof 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. Взносы тоже приветствуются.
null
с этим с помощью эмулятора?
- person Jasper de Vries; 03.06.2021
В Android P определение разрешения READ_PHONE_STATE только в AndroidManifest работать не будет. Мы действительно должны запросить разрешение. Ниже код работает для меня:
@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" />