Android: как программно получить доступ к серийному номеру устройства, указанному в диспетчере AVD (API версии 8)

Как программно получить доступ к значению, показанному на изображении ниже?

введите описание изображения здесь


person Heshan Perera    schedule 14.06.2012    source источник
comment
возможный дубликат Как узнать серийный номер устройства Android?   -  person George Stocker    schedule 14.06.2012


Ответы (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 возвращает действительный серийный номер.

Он уникален для любого устройства. Если вы ищете возможности получения / использования уникального идентификатора устройства, вам следует прочитать здесь.

Решение, включающее отражение без разрешения, см. В этом ответе.

person thaussma    schedule 14.06.2012
comment
Почему вы говорите, что он меняется при сбросе к заводским настройкам? Я знаю, что это верно для Settings.Secure.ANDROID_ID, но я не слышал об этом для Build.Serial. - person Tom; 10.07.2012
comment
Том, ты прав! Я перепутал ANDROID_ID и SERIAL. Я отредактировал свой ответ. - person thaussma; 11.07.2012
comment
Обычно это тот же серийный номер, который производитель физически печатает на самом устройстве, или это серийный номер только для программного обеспечения? - person guidod; 24.04.2014
comment
Это как-то изменится в будущем? - person Pratik Butani; 25.04.2014
comment
этот ответ следует отредактировать, как с Android 8 (API26) и выше, Build.SERIAL работать не будет. Единственный способ получить серийный номер - вызвать метод Build.getSerial (), который требует разрешений READ_PHONE_STATE. - person alex_z; 28.01.2019
comment
когда меняется build_serial? изменить оборудование, корневое устройство, сброс к заводским настройкам меняет его? - person geosmart; 23.12.2019

До 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+). Для получения дополнительной информации по этой теме см. Рекомендации по уникальным идентификаторам.

person Patrick Favre    schedule 30.10.2017
comment
Не могли бы те, кто проголосовал против, объяснить, почему он / она считает, что это неверно? - person Patrick Favre; 21.11.2017
comment
Я проголосовал против, вероятно, по ошибке, теперь это явно правильный ответ. Я не могу удалить свой голос против, потому что он заблокирован до тех пор, пока ответ не будет отредактирован. - person peceps; 30.11.2017
comment
если телефон сброшен до заводских или сброшен привилегии, идентификатор получить из UUID.randomUUID (). toString () и ANDROID_ID изменится? - person TJCLK; 20.01.2020
comment
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. Взносы тоже приветствуются.

person flawyte    schedule 02.10.2018
comment
это наконец решает мою проблему, принятый ответ должен быть таким - person Hussain KMR Behestee; 10.12.2019
comment
Думаю, это лучший ответ здесь. Обратите внимание: если я использую этот код в своей студии Android и запустил 2 экземпляра Simulator, он вернет тот же идентификатор. - person panoet; 08.01.2020
comment
Вы должны получить 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

person MMJ    schedule 22.06.2020

Мне нравится мое решение:

/**
 * 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" />
person Andrè Straube    schedule 30.03.2021