Есть ли уникальный идентификатор устройства Android?

avatar
Tyler
7 мая 2010 в 00:47
1112012
51
2923

Имеют ли устройства Android уникальный идентификатор, и если да, то каков простой способ получить к нему доступ с помощью Java?

Источник
Dheeraj Vepakomma
16 января 2013 в 08:16
43

Если вы используете ANDROID_ID, обязательно прочтите этот ответ и эту ошибку.

Mujahid Khan
19 августа 2020 в 06:42
0

Ваше решение здесь: coderhelper.com/a/63481350/7135685

Ответы (51)

avatar
Anthony Forloney
7 мая 2010 в 00:49
2133

Settings.Secure#ANDROID_ID возвращает идентификатор Android в виде , уникального для каждого пользователя 64-битная строка 50960.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID);

Также прочтите Рекомендации для уникальных идентификаторов : https://developer.android.com/training/articles/user-data-ids

Seva Alekseyev
23 июня 2010 в 14:21
502

Иногда известно, что он имеет нулевое значение, но это задокументировано как «может измениться после сброса настроек». Используйте на свой страх и риск, и его можно легко изменить на рутированном телефоне.

user604363
5 февраля 2011 в 17:06
20

Я думаю, что нам нужно быть осторожными при использовании ANDROID_ID в хэше в первом ответе, потому что он может не быть установлен при первом запуске приложения, может быть установлен позже или может даже измениться теоретически, поэтому уникальный идентификатор может измениться

emmby
7 апреля 2011 в 20:10
48

Имейте в виду, что это решение имеет огромные ограничения: android-developers.blogspot.com/2011/03/…

Girish Patel
30 сентября 2011 в 07:18
5

этот ANDROID_ID предназначен только для вкладки Android, если вы можете работать на телефоне, тогда вы получите null, если вы запустите вкладку, тогда вы можете получить уникальный идентификатор.-Girish

Tom
15 декабря 2012 в 19:36
39

ANDROID_ID больше не идентифицирует устройство однозначно (начиная с версии 4.2): coderhelper.com/a/13465373/150016

Dori
6 марта 2014 в 09:23
3

Кажется, это также может измениться, если пользователь очищает кэшированные данные Play Services. androidpolice.com/2013/11/20/… намекает на "Это изменяет основной идентификатор, по которому Google узнает ваше устройство. Что касается серверов, то в основном были сброшены настройки устройства. . " который, как я предполагаю, является ANDROID_ID - однако я не могу воспроизвести это при тестировании - в любом случае стоит знать ...

Sayed Abolfazl Fatemi
9 июля 2014 в 09:20
2

Салам. посмотрите ответ @Joe http://coderhelper.com/a/2853253/1676736

Iman Marashi
5 апреля 2017 в 21:05
3

Использование getString для получения идентификаторов устройств не рекомендуется. ПОЧЕМУ?

EpicPandaForce
12 апреля 2017 в 08:26
13

Android O изменит это android-developers.googleblog.com/2017/04/…

Naga
22 февраля 2019 в 08:26
2

Я использую Android ID в своем приложении, чтобы однозначно идентифицировать пользователей, потому что я чувствовал, что это проще, чем обычная регистрация с помощью идентификатора электронной почты, и до сих пор я не обнаружил никаких проблем с этим решением, ни один из наших подписчиков пока не жалуется, и мы знаем, что резервный вариант не будет таким разрушительным, если это произойдет снова, все зависит от типа приложения, если приложению не нужна строгая безопасность, я думаю, что идентификатор ANDROID не может быть проблемой

Malwinder Singh
24 июля 2019 в 07:28
2

Android Lint заявляет: «Использование getString для получения идентификаторов устройств не рекомендуется. Информация для проверки. Использование этих идентификаторов устройств не рекомендуется, кроме как для предотвращения крупного мошенничества и расширенных сценариев использования телефонии. Для рекламных сценариев использования используйте AdvertisingIdClient $ Info # getId, а для аналитики используйте InstanceId # getId.

Naga
3 сентября 2019 в 12:27
2

@AaronUllal, извините, немного поздно, нет, я так не думаю, в настройках About Phone есть такие вещи, как версия Android, imei и т. Д., В одном из проверенных мной телефонов Android, возможно, это не так актуально для пользователей, чем для приложений

André
24 июля 2020 в 18:52
6

Какая версия ответа на этот вопрос в 2020 году? Конечно, все изменилось.

Syed Arsalan Kazmi
20 ноября 2020 в 13:59
1

Этот идентификатор изменяется при изменении файла хранилища ключей. Я искал что-то более уникальное. Идентификатор, который остается постоянным для одного устройства.

famfamfam
5 марта 2021 в 14:30
0

@SyedArsalanKazmi я выбрал токен fcm

HellBaby
16 августа 2021 в 13:08
0

@ Энтони-Форлони. Это по каждому приложению, поставщику или оборудованию? ... спрашиваю, потому что я использую разные ценности и не могу их объяснить.

avatar
MD. Shafiul Alam Biplob
23 октября 2021 в 18:56
0

package com.aapbd.appbajarlib.common;

import android.os.Build;

import java.util.Locale;
import java.util.UUID;

public class DeviceID {



    public  static String getDeviceLanguage()
    {

        Locale locale=Locale.getDefault();
        return locale.getDisplayLanguage();

    }

    public  static String getDeviceCountry()
    {

        Locale locale=Locale.getDefault();
        return locale.getDisplayCountry();

    }


    public static String getDeviceName() {
        String manufacturer = Build.MANUFACTURER;
        String model = Build.MODEL;
        if (model.startsWith(manufacturer)) {
            return capitalize(model);
        } else {
            return capitalize(manufacturer) + " " + model;
        }
    }

    public static String getAndroidVersion() {

            String release = Build.VERSION.RELEASE;
            int sdkVersion = Build.VERSION.SDK_INT;
            return sdkVersion + " (" + release +")";

    }

    public static int getAndroidAPILevel() {

        int sdkVersion = Build.VERSION.SDK_INT;
        return sdkVersion;

    }




    private static String capitalize(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        char first = s.charAt(0);
        if (Character.isUpperCase(first)) {
            return s;
        } else {
            return Character.toUpperCase(first) + s.substring(1);
        }
    }


    /**
     * Return pseudo unique ID
     * @return ID
     */
    public static String getUniquePsuedoID() {
        // If all else fails, if the user does have lower than API 9 (lower
        // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
        // returns 'null', then simply the ID returned will be solely based
        // off their Android device information. This is where the collisions
        // can happen.
        // Thanks http://www.pocketmagic.net/?p=1662!
        // Try not to use DISPLAY, HOST or ID - these items could change.
        // If there are collisions, there will be overlapping data
        String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

        // Thanks to @Roman SL!
        // http://coderhelper.com/a/4789483/950427
        // Only devices with API >= 9 have android.os.Build.SERIAL
        // http://developer.android.com/reference/android/os/Build.html#SERIAL
        // If a user upgrades software or roots their device, there will be a duplicate entry
        String serial = null;
        try {
            serial = android.os.Build.class.getField("SERIAL").get(null).toString();

            // Go ahead and return the serial for api => 9
            return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
        } catch (Exception exception) {
            // String needs to be initialized
            serial = "serial"; // some value
        }

        // Thanks @Joe!
        // http://coderhelper.com/a/2853253/950427
        // Finally, combine the values we have found by using the UUID class to create a unique identifier
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    }

}

Я использую это, и он работает последние 6 лет.

Вот библиотека: https://github.com/nillbiplob/AppBajarLIB

avatar
Abdallah AlTaher
23 сентября 2020 в 16:07
-2

Вы получите MAC-адрес Wi-Fi, используя следующий код, независимо от того, использовали ли вы случайный адрес при попытке подключиться к Wi-Fi или нет, и независимо от того, был ли Wi-Fi включен или выключен.

Я использовал метод из приведенной ниже ссылки и добавил небольшую модификацию, чтобы получить точный адрес вместо рандомизированного:

Получение MAC-адреса в Android 6.0

public static String getMacAddr() {
StringBuilder res1 = new StringBuilder();
try {
List<NetworkInterface> all =     
Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {    
if (!nif.getName().equalsIgnoreCase("p2p0")) continue;

        byte[] macBytes = nif.getHardwareAddress();
        if (macBytes == null) {
            continue;
        }

        res1 = new StringBuilder();
        for (byte b : macBytes) {
            res1.append(String.format("%02X:",b));
        }

        if (res1.length() > 0) {
            res1.deleteCharAt(res1.length() - 1);
        }
    }
} catch (Exception ex) {
}
return res1.toString();

}

avatar
CodeInsideCoffee
7 июня 2020 в 09:08
4

Получите D UUID устройства, номер модели с фирменным наименованием и его номер версии с помощью функции ниже.

Отлично работает в Android 10 , и нет необходимости разрешать чтение состояния телефона.

Фрагменты кода:

private void fetchDeviceInfo() {
    String uniquePseudoID = "35" +
            Build.BOARD.length() % 10 +
            Build.BRAND.length() % 10 +
            Build.DEVICE.length() % 10 +
            Build.DISPLAY.length() % 10 +
            Build.HOST.length() % 10 +
            Build.ID.length() % 10 +
            Build.MANUFACTURER.length() % 10 +
            Build.MODEL.length() % 10 +
            Build.PRODUCT.length() % 10 +
            Build.TAGS.length() % 10 +
            Build.TYPE.length() % 10 +
            Build.USER.length() % 10;

    String serial = Build.getRadioVersion();
    String uuid=new UUID(uniquePseudoID.hashCode(), serial.hashCode()).toString();
    String brand=Build.BRAND;
    String modelno=Build.MODEL;
    String version=Build.VERSION.RELEASE;
    Log.e(TAG, "fetchDeviceInfo: \n "+
            "\n uuid is : "+uuid+
            "\n brand is: "+brand+
            "\n model is: "+modelno+
            "\n version is: "+version);
}

Вызовите вышеуказанную функцию и проверьте вывод вышеуказанного кода. , пожалуйста, посмотрите свой журнал в студии Android. Это выглядит следующим образом:

enter image description here

porya74
14 июня 2020 в 22:13
0

что означает% 10 и 35 + "..." в вашем коде? я имею в виду, почему вы используете этот подход для создания уникального идентификатора? почему бы просто не объединить эти строки и сгенерировать уникальный UUID? вывод этого метода полностью уникален для всех устройств в мире?

avatar
jai khambhayta
19 мая 2020 в 14:54
0

Android ограничивает идентификатор оборудования после Android O, поэтому Android_Id - это решение для уникального идентификатора, но у него есть проблема, когда отражатель устройство, которое будет генерировать новый android_id, чтобы преодолеть это проблема, мы можем использовать DRUMID.

val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
val drumIDByteArray = MediaDrm(WIDEVINE_UUID).getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID)

val drumID = android.util.Base64.encodeToString(drumIDByteArray,android.util.Base64.DEFAULT)
avatar
Nikita Kurtin
28 ноября 2019 в 17:10
81

Это простой вопрос, на который нет простого ответа.

Более того, все существующие здесь ответы устарели или ненадежны.

Итак, , если вы ищете решение в 2020 году .

Вот несколько вещей, о которых следует помнить:

Все аппаратные идентификаторы (SSAID, IMEI, MAC и т. Д.) Ненадежны для устройств, не принадлежащих Google (все, кроме пикселей и нексусов), которые составляют более 50% активных устройств во всем мире. Поэтому в официальном передовых методах работы с идентификаторами Android четко указано:

Избегайте использования аппаратных идентификаторов , таких как SSAID (Android ID), IMEI, MAC-адрес и т. Д.

Это делает большинство приведенных выше ответов недействительными. Также из-за различных обновлений безопасности Android для некоторых из них требуются более новые и более строгие разрешения времени выполнения, которые могут быть просто отклонены пользователем.

В качестве примера CVE-2018-9489, который влияет на все упомянутые выше методы на основе WIFI.

Это делает эти идентификаторы не только ненадежными, но и недоступными во многих случаях.

Проще говоря: не используйте эти методы .

Многие другие ответы здесь предлагают использовать AdvertisingIdClient, который также несовместим, так как его дизайн должен использоваться только для профилирования рекламы. Это также указано в официальном справочнике

Используйте рекламный идентификатор только для профилей пользователей или вариантов использования рекламы

Это не только ненадежно для идентификации устройства, но вы также должны соблюдать политику конфиденциальности пользователей в отношении отслеживания рекламы, в которой четко указано, что пользователь может сбросить или заблокировать ее в любой момент.

Итак, не используйте его также .

Поскольку у вас не может быть желаемого статического глобально уникального и надежного идентификатора устройства. Официальная ссылка Android предлагает:

По возможности используйте FirebaseInstanceId или GUID , хранящийся в частном порядке, для всех других вариантов использования, кроме предотвращения мошенничества с платежами и телефонной связи.

Это уникально для установки приложения на устройстве, поэтому, когда пользователь удаляет приложение - оно стирается, поэтому оно не на 100% надежно, но это лучший вариант.

Чтобы использовать FirebaseInstanceId, добавьте последнюю зависимость обмена сообщениями firebase в свой gradle

implementation 'com.google.firebase:firebase-messaging:20.2.4'

И используйте приведенный ниже код в фоновом потоке:

String reliableIdentifier = FirebaseInstanceId.getInstance().getId();

Если вам нужно сохранить идентификатор устройства на удаленном сервере, сохраняйте его не как есть (обычный текст), а хеш-код с солью.

Сегодня это не только лучшая практика, вы фактически должны делать это по закону в соответствии с GDPR - идентификаторы и аналогичными правилами.

b2mob
22 января 2020 в 09:15
14

На данный момент это лучший ответ, а первое предложение - лучшее резюме: «Это простой вопрос без простого ответа - просто полюбите его.

Nikita Kurtin
8 марта 2020 в 06:22
2

@ M.UsmanKhan, ответ написан сразу после этого: " Сегодня это не только лучшая практика, вы фактически должны делать это по закону в соответствии с GDPR - идентификаторами и аналогичными правилами. "

David Schneider
21 июля 2020 в 09:55
0

Не могли бы вы указать, в каком разделе опубликованной вами ссылки GDPR упоминается требование хеширования идентификаторов?

Nikita Kurtin
21 июля 2020 в 10:39
1

@DavidSchneider веб-контент является динамичным по своей природе, и GDPR является лишь одним из примеров, обратите внимание, что я написал « GDPR и аналогичные правила », поскольку существует множество местных и глобальных правил, которые влияют на ваш продукт / система / поле. В любом случае разделы GDPR, которые вы ищете: Идентификация , Онлайн-идентификаторы и Принципы защиты данных

william gouvea
3 января 2021 в 19:54
0

proandroiddev.com/…

famfamfam
23 февраля 2021 в 10:18
0

Уникальный идентификатор firebase изменится, если приложение будет переустановлено

Nikita Kurtin
25 февраля 2021 в 08:50
0

@famfamfam, именно поэтому я написал, что: " Он уникален для установки приложения на устройстве, поэтому, когда пользователь удаляет приложение, оно стирается, поэтому оно не на 100% надежно, но это лучший вариант. вещь. "

famfamfam
25 февраля 2021 в 10:06
0

спасибо, мне интересно, почему Android не может сделать ANDROID_ID для uuid устройства, чтобы усложнить код разработчика Android

Nikita Kurtin
25 февраля 2021 в 13:40
0

@famfamfam По-моему, это из-за открытой природы Android и UUID.randomUUID() псевдослучайной платформы Java, зависящей от времени.

Michael Paccione
3 июля 2021 в 19:33
0

Подождите, разве не так много обстоятельств, которые заставили бы это изменить с одного значения на другое?

avatar
Anubhav
25 сентября 2019 в 11:05
2
android.telephony.TelephonyManager.getDeviceId()

Это вернет любую строку, однозначно идентифицирующую устройство (IMEI в GSM, MEID для CDMA).

Вам понадобится следующее разрешение в вашем AndroidManifest.xml:

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

Googlian
23 октября 2019 в 07:22
2

Устарело

avatar
Stephan John
11 сентября 2019 в 14:09
1

Да, каждое устройство Android имеет уникальный серийный номер, который можно узнать с помощью этого кода. Build.SERIAL. Обратите внимание, что он был добавлен только в API уровня 9 и может присутствовать не на всех устройствах. Чтобы получить уникальный идентификатор на более ранних платформах, вам нужно будет прочитать что-то вроде MAC-адреса или IMEI.

avatar
Vitaly Zinchenko
3 августа 2019 в 12:41
0

Чтобы получить идентификатор пользователя, вы можете использовать библиотеку лицензирования Google Play.

Чтобы загрузить эту библиотеку, откройте SDK Manager => SDK Tools. Путь к загруженным файлам библиотеки:

путь_к_android_sdk_on_your_pc / extras / google / market_licensing / library

Включите библиотеку в свой проект (вы можете просто скопировать ее файлы).

Далее вам понадобится некоторая реализация интерфейса Policy (вы можете просто использовать один из двух файлов из библиотеки: ServerManagedPolicy или StrictPolicy).

ID пользователя будет предоставлен вам внутри функции processServerResponse():

public void processServerResponse(int response, ResponseData rawData) {
    if(rawData != null) {
        String userId = rawData.userId
        // use/save the value
    }
    // ...
}

Затем вам нужно создать LicenseChecker с политикой и вызвать функцию checkAccess(). Используйте MainActivity.java в качестве примера того, как это сделать. MainActivity.java находится внутри этой папки:

путь_к_android_sdk_on_your_pc / extras / google / market_licensing / sample / src / com / example / android / market / licensing

Не забудьте добавить разрешение CHECK_LICENSE к вашему AndroidManifest.xml.

Подробнее о библиотеке лицензирования: https://developer.android.com/google/play/licensing

avatar
Malwinder Singh
24 июля 2019 в 07:34
3

Если добавить:

Settings.Secure.getString(context.contentResolver,
    Settings.Secure.ANDROID_ID)

Android Lint выдаст следующее предупреждение:

Использование getString для получения идентификаторов устройств не рекомендуется. Информация для проверки: использование этих идентификаторов устройств не рекомендуется кроме защиты от мошенничества и расширенной телефонии случаи применения. Для рекламных сценариев использования используйте AdvertisingIdClient $ Info # getId, а для аналитики используйте InstanceId # getId.

Итак, вам следует избегать этого.

Как указано в документации разработчика Android:

1: Избегайте использования идентификаторов оборудования.

В большинстве случаев вы можете избегать использования аппаратных идентификаторов, таких как SSAID (Android ID) и IMEI, без ограничения требуемой функциональности.

2: Используйте рекламный идентификатор только для профилей пользователей или вариантов использования рекламы.

При использовании рекламного идентификатора всегда уважайте выбор пользователей. относительно отслеживания рекламы. Также убедитесь, что идентификатор не может быть связаны с информацией, позволяющей установить личность (PII), и избегать мостовой рекламный идентификатор сбрасывается.

3: По возможности используйте идентификатор экземпляра или GUID, хранящийся в частном порядке, для всех других случаев использования, за исключением предотвращения мошенничества с платежами и телефонной связи.

Для подавляющего большинства случаев использования без рекламы идентификатор экземпляра или GUID должно быть достаточно.

4: Используйте API-интерфейсы, подходящие для вашего варианта использования, чтобы минимизировать риск конфиденциальности.

Используйте DRM API для защиты ценных материалов и API-интерфейсы SafetyNet для защиты от злоупотреблений. API SafetyNet - это самый простой способ определить подлинность устройства без риск для конфиденциальности.

avatar
Raj
11 июня 2019 в 16:55
4

Вот простой ответ, чтобы получить AAID, , протестированный и работающий правильно июнь 2019 г.

 AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            String token = null;
            Info adInfo = null;
            try {
                adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
            } catch (IOException e) {
                // ...
            } catch ( GooglePlayServicesRepairableException e) {
                // ...
            } catch (GooglePlayServicesNotAvailableException e) {
                // ...
            }
            String android_id = adInfo.getId();
            Log.d("DEVICE_ID",android_id);

            return android_id;
        }

        @Override
        protected void onPostExecute(String token) {
            Log.i(TAG, "DEVICE_ID Access token retrieved:" + token);
        }

    };
    task.execute();

прочитайте подробный полный ответ здесь:

avatar
Waheed Nazir
3 мая 2019 в 22:09
8

Чтобы понять, какие уникальные идентификаторы доступны на устройствах Android. Используйте это официальное руководство.

Рекомендации для уникальных идентификаторов:

IMEI, адреса Mac, идентификатор экземпляра, идентификаторы GUID, SSAID, идентификатор рекламы, API сети безопасности для проверки устройств.

https://developer.android.com/training/articles/user-data-ids

avatar
Jens Vesti
31 января 2019 в 15:27
3

Чтобы включить Android 9 , у меня есть только одна идея, которая (вероятно) не нарушает никаких условий, не требует разрешений и работает в разных установках и приложениях.

Дактилоскопия с участием сервера должна позволять однозначно идентифицировать устройство. Сочетание информации об оборудовании + установленных приложений и времени установки должно помочь. Время первой установки не изменится, если приложение не будет удалено и снова установлено. Но это необходимо сделать для всех приложений на устройстве, чтобы они не могли идентифицировать устройство (например, после сброса настроек).

Я бы сказал об этом так:

  1. Извлечь информацию об оборудовании, имена пакетов приложений и время первой установки.

Вот как вы извлекаете все приложения из Android (разрешения не требуются):

final PackageManager pm = application.getPackageManager();
List<ApplicationInfo> packages = 
pm.getInstalledApplications(PackageManager.GET_META_DATA);

for (ApplicationInfo packageInfo : packages) {
    try {
        Log.d(TAG, "Installed package :" + packageInfo.packageName);
        Log.d(TAG, "Installed :" + pm.getPackageInfo(packageInfo.packageName, 0).firstInstallTime);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
}
  1. Вы можете захотеть создать хэш для каждой комбинации имени пакета и отметки времени установки, прежде чем отправлять ее на сервер, поскольку это может или не может быть связано с вашим бизнесом, что пользователь установил на устройстве.
  2. Некоторые приложения (на самом деле их много) являются системными. Скорее всего, они будут иметь одинаковую метку времени установки, соответствующую последнему обновлению системы после сброса к заводским настройкам. Поскольку они имеют одинаковую метку времени установки, они не могут быть установлены пользователем и могут быть отфильтрованы.
  3. Отправьте информацию на сервер и позвольте ему найти ближайшее совпадение среди ранее сохраненной информации. Вам необходимо установить порог при сравнении с ранее сохраненной информацией об устройстве по мере установки и удаления приложений. Но я предполагаю, что этот порог может быть очень низким, поскольку любое сочетание имени пакета и отметки времени первой установки само по себе будет довольно уникальным для устройства, а приложения не так часто устанавливаются и удаляются. Наличие нескольких приложений только увеличивает вероятность быть уникальным.
  4. Вернуть сгенерированный уникальный идентификатор для соответствия или сгенерировать уникальный идентификатор, сохранить с информацией об устройстве и вернуть этот новый идентификатор.

Примечание: Это непроверенный и непроверенный метод! Я уверен, что это сработает, но я также почти уверен, что, если это приживется, они так или иначе закроют его.

avatar
Martin Zikmund
21 января 2019 в 07:13
2

Для полноты картины можно получить Id в Xamarin.Android и C #:

var id = Settings.Secure.GetString(ContentResolver, Settings.Secure.AndroidId);

Или, если вы не в пределах Activity:

var id = Settings.Secure.GetString(context.ContentResolver, Settings.Secure.AndroidId);

Где context ​​- переданный в контексте.

avatar
Kiran Maniya
5 октября 2018 в 05:55
8

1. Используйте диспетчер телефонии, который предоставляет уникальный идентификатор (например, IMEI). См. Пример:

import android.telephony.TelephonyManager;
import android.content.Context;
// ...
TelephonyManager telephonyManager;
telephonyManager = (TelephonyManager) getSystemService(Context.
                TELEPHONY_SERVICE);
/*
* getDeviceId() returns the unique device ID.
* For example,the IMEI for GSM and the MEID or ESN for CDMA phones.
*/
String deviceId = telephonyManager.getDeviceId();
/*
* getSubscriberId() returns the unique subscriber ID,
*/
String subscriberId = telephonyManager.getSubscriberId();

Для этого вашему пользователю требуется android.permission.READ_PHONE_STATE, что может быть трудно оправдать типом приложения, которое вы сделали.

  1. Устройства без услуг телефонии, например планшеты, должны сообщать уникальный идентификатор устройства, доступный через android.os.Build.SERIAL начиная с Android 2.3 Gingerbread. Некоторые телефоны с услугами телефонии также могут определять серийный номер. Подобно тому, как не все устройства Android имеют серийный номер, это решение ненадежно.

  2. При первой загрузке устройства генерируется и сохраняется случайное значение. Это значение доступно через Settings.Secure.ANDROID_ID. Это 64-битное число, которое должно оставаться постоянным на протяжении всего срока службы устройства. ANDROID_ID кажется хорошим выбором для уникального идентификатора устройства, поскольку он доступен для смартфонов и планшетов. Чтобы получить значение, вы можете использовать следующий код,

    Строка androidId = Settings.Secure.getString (getContentResolver (), Settings.Secure.ANDROID_ID);

Однако значение может измениться, если на устройстве будет выполнен сброс к заводским настройкам. Также существует известная ошибка в популярном телефоне от производителя, где у каждого экземпляра одинаковый ANDROID_ID. Ясно, что это решение не на 100% надежно.

  1. Использовать UUID. Поскольку требование для большинства приложений - идентифицировать конкретную установку, а не физическое устройство, хорошее решение для получения уникального идентификатора для пользователя, если использовать класс UUID. Следующее решение было представлено Рето Мейером из Google в презентации Google I / O:
SharedPreferences sharedPrefs = context.getSharedPreferences(
         PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

Обновление : параметры # 1 и # 2 больше не доступны после Android 10 в качестве обновлений конфиденциальности от Google. поскольку для вариантов 2 и 3 требуется критическое разрешение.

viper
26 августа 2019 в 05:38
2

В каком телефоне у каждого экземпляра одинаковый ANDROID_ID?

Kiran Maniya
26 августа 2019 в 06:37
0

обратитесь к официальной документации developer.android.com/reference/android/provider/…

user924
6 февраля 2020 в 11:15
2

DeviceInfoProvider не является частью Android SDK

Kiran Maniya
6 февраля 2020 в 12:51
0

Спасибо, @ user924 за указание на это. Если у вас есть дополнительные сведения, вы можете отредактировать ответ, чтобы улучшить его.

jerinho.com
25 апреля 2020 в 15:20
0

@KiranManiya Отредактируйте придуманный ответ. Как люди могут знать, как это редактировать, если вы это придумали? Это вы должны его редактировать. Не отвечайте здесь на вопрос своей иллюзией

Kiran Maniya
26 апреля 2020 в 06:58
0

@jerinho Большое спасибо. Думаю, вы прошли оба моих ответа.

avatar
Ege Kuzubasioglu
28 декабря 2017 в 08:36
4

Не рекомендуется, поскольку deviceId может использоваться для отслеживания сторонними лицами, но это другой способ.

@SuppressLint("HardwareIds")
private String getDeviceID() {
    deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(),
                    Settings.Secure.ANDROID_ID);
    return deviceId;
}
Jeff Padgett
22 июня 2018 в 07:12
0

Android вносит некоторые изменения в: Settings.Secure.ANDROID_ID; В Android 8.0 (уровень API 26) и более поздних версиях платформы - 64-битное число (выраженное в виде шестнадцатеричной строки), уникальное для каждой комбинации ключа подписи приложения, пользователя и устройства. Это означает, что Settings.Secure.ANDROID_ID теперь возвращает идентификаторы, уникальные для комбинации приложение / устройство, что делает вещи более безопасными для пользователя.

avatar
shivampip
14 декабря 2017 в 15:02
2

Серийный номер - это уникальный идентификатор устройства, доступный через android.os.Build.SERIAL.

public static String getSerial() {
    String serial = "";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        serial = Build.getSerial();
    }else{ 
        serial = Build.SERIAL;    
    }
    return serial;
}

Перед вызовом getSerial () убедитесь, что у вас есть разрешение READ_PHONE_STATE .

ПРИМЕЧАНИЕ : - Это Недоступно для устройств без телефонии (например, планшетов только с Wi-Fi).

Ted Hopp
14 декабря 2017 в 20:42
3

Обратите внимание, что в документации говорится, что это вернет серийный номер оборудования «если доступно» , предполагая, что Build.SERIAL (или Build.getSerial()) не всегда доступен. Дополнительная информация доступна в сообщении блога Изменения идентификаторов устройств в Android O. Также стоит прочитать: Лучшие практики для уникальных идентификаторов.

avatar
Cheok Yan Cheng
7 ноября 2017 в 19:00
4

Я столкнулся с этим вопросом несколько лет назад и научился реализовывать обобщенное решение, основанное на различных ответах.

Я использовал обобщенное решение в течение нескольких лет в реальном продукте. Пока он мне служит очень хорошо. Вот фрагмент кода, основанный на различных ответах.

Обратите внимание: getEmail большую часть времени будет возвращать null, поскольку мы не запрашивали разрешение явно.

private static UniqueId getUniqueId() {
    MyApplication app = MyApplication.instance();

    // Our prefered method of obtaining unique id in the following order.
    // (1) Advertising id
    // (2) Email
    // (2) ANDROID_ID
    // (3) Instance ID - new id value, when reinstall the app.

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ADVERTISING ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    AdvertisingIdClient.Info adInfo = null;
    try {
        adInfo = AdvertisingIdClient.getAdvertisingIdInfo(app);
    } catch (IOException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e(TAG, "", e);
    } catch (GooglePlayServicesRepairableException e) {
        Log.e(TAG, "", e);
    }

    if (adInfo != null) {
        String aid = adInfo.getId();
        if (!Utils.isNullOrEmpty(aid)) {
            return UniqueId.newInstance(aid, UniqueId.Type.aid);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // EMAIL
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String email = Utils.getEmail();
    if (!Utils.isNullOrEmpty(email)) {
        return UniqueId.newInstance(email, UniqueId.Type.eid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // ANDROID ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String sid = Settings.Secure.getString(app.getContentResolver(), Settings.Secure.ANDROID_ID);
    if (!Utils.isNullOrEmpty(sid)) {
        return UniqueId.newInstance(sid, UniqueId.Type.sid);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////
    // INSTANCE ID
    ////////////////////////////////////////////////////////////////////////////////////////////
    final String iid = com.google.android.gms.iid.InstanceID.getInstance(MyApplication.instance()).getId();
    if (!Utils.isNullOrEmpty(iid)) {
        return UniqueId.newInstance(iid, UniqueId.Type.iid);
    }

    return null;
}

public final class UniqueId implements Parcelable {
    public enum Type implements Parcelable {
        aid,
        sid,
        iid,
        eid;

        ////////////////////////////////////////////////////////////////////////////
        // Handling Parcelable nicely.

        public static final Parcelable.Creator<Type> CREATOR = new Parcelable.Creator<Type>() {
            public Type createFromParcel(Parcel in) {
                return Type.valueOf(in.readString());
            }

            public Type[] newArray(int size) {
                return new Type[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel parcel, int flags) {
            parcel.writeString(this.name());
        }

        // Handling Parcelable nicely.
        ////////////////////////////////////////////////////////////////////////////
    }

    public static boolean isValid(UniqueId uniqueId) {
        if (uniqueId == null) {
            return false;
        }
        return uniqueId.isValid();
    }

    private boolean isValid() {
        return !org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) && type != null;
    }

    private UniqueId(String id, Type type) {
        if (org.yccheok.jstock.gui.Utils.isNullOrEmpty(id) || type == null) {
            throw new java.lang.IllegalArgumentException();
        }
        this.id = id;
        this.type = type;
    }

    public static UniqueId newInstance(String id, Type type) {
        return new UniqueId(id, type);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + id.hashCode();
        result = 31 * result + type.hashCode();
        return result;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof UniqueId)) {
            return false;
        }

        UniqueId uniqueId = (UniqueId)o;
        return this.id.equals(uniqueId.id) && this.type == uniqueId.type;
    }

    @Override
    public String toString() {
        return type + ":" + id;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Handling Parcelable nicely.

    public static final Parcelable.Creator<UniqueId> CREATOR = new Parcelable.Creator<UniqueId>() {
        public UniqueId createFromParcel(Parcel in) {
            return new UniqueId(in);
        }

        public UniqueId[] newArray(int size) {
            return new UniqueId[size];
        }
    };

    private UniqueId(Parcel in) {
        this.id = in.readString();
        this.type = in.readParcelable(Type.class.getClassLoader());
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(this.id);
        parcel.writeParcelable(this.type, 0);
    }

    // Handling Parcelable nicely.
    ////////////////////////////////////////////////////////////////////////////

    public final String id;
    public final Type type;
}

public static String getEmail() {
    Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
    AccountManager accountManager = AccountManager.get(MyApplication.instance());
    Account[] accounts = accountManager.getAccountsByType("com.google");
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    accounts = accountManager.getAccounts();
    for (Account account : accounts) {
        if (emailPattern.matcher(account.name).matches()) {
            String possibleEmail = account.name;
            return possibleEmail;
        }
    }

    return null;
} 
G3n1t0
9 марта 2021 в 19:09
0

Но работает ли это, когда пользователь перезагружает свой телефон? В этом случае идентификатор Android будет изменен, идентификатор рекламы и электронная почта тоже будут сброшены.

avatar
Jeffy
7 сентября 2017 в 14:31
2
String SERIAL_NUMER = Build.SERIAL;

Возвращает СЕРИЙНЫЙ НОМЕР в виде строки, уникальной для каждого устройства.

avatar
Zin Win Htet
19 июня 2017 в 15:25
4

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

, чтобы получить IMEI ( международный идентификатор мобильного оборудования )

public String getIMEI(Activity activity) {
    TelephonyManager telephonyManager = (TelephonyManager) activity
            .getSystemService(Context.TELEPHONY_SERVICE);
    return telephonyManager.getDeviceId();
}

, чтобы получить уникальный идентификатор устройства

public String getDeviceUniqueID(Activity activity){
    String device_unique_id = Secure.getString(activity.getContentResolver(),
            Secure.ANDROID_ID);
    return device_unique_id;
}
avatar
bugraoral
11 апреля 2017 в 08:51
4

Напоминаем всем, кто читает более актуальную информацию. В Android O внесены некоторые изменения в то, как система управляет этими идентификаторами.

https://android-developers.googleblog.com/2017/04/changes-to-device-identifiers-in.html

tl; dr Serial потребует разрешения ТЕЛЕФОНА, а идентификатор Android будет изменяться для разных приложений в зависимости от имени пакета и подписи.

А также Google составил хороший документ, в котором даются предложения о том, когда использовать идентификаторы оборудования и программного обеспечения.

https://developer.android.com/training/articles/user-data-ids.html

avatar
ᴛʜᴇᴘᴀᴛᴇʟ
8 марта 2017 в 14:01
12

Здесь более 30 ответов, и некоторые из них одинаковы, а некоторые уникальны. Этот ответ основан на немногих из этих ответов. Один из них - ответ @Lenn Dolling.

Он объединяет 3 идентификатора и создает 32-значную шестнадцатеричную строку. У меня это сработало очень хорошо.

3 идентификатора:
Псевдо-ID - он создается на основе технических характеристик физического устройства
ANDROID_ID <3683214314314813323> - - адрес адаптера Bluetooth

Он вернет что-то вроде этого: 551F27C060712A72730B0A0F734064B1

Примечание. Вы всегда можете добавить дополнительные идентификаторы в строку longId. Например, серийный номер. адрес адаптера Wi-Fi. IMEI. Таким образом, вы делаете его более уникальным для каждого устройства.

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                Build.BOARD.length() % 10 +
                Build.BRAND.length() % 10 +
                Build.CPU_ABI.length() % 10 +
                Build.DEVICE.length() % 10 +
                Build.DISPLAY.length() % 10 +
                Build.HOST.length() % 10 +
                Build.ID.length() % 10 +
                Build.MANUFACTURER.length() % 10 +
                Build.MODEL.length() % 10 +
                Build.PRODUCT.length() % 10 +
                Build.TAGS.length() % 10 +
                Build.TYPE.length() % 10 +
                Build.USER.length() % 10;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}
Mousa Alfhaily
11 апреля 2017 в 07:08
2

Добавление UUID к longId и сохранение его в файле сделает его наиболее уникальным идентификатором: String uuid = UUID.randomUUID().toString();

Mousa Alfhaily
11 апреля 2017 в 07:17
3

Если все остальное не помогает, если у пользователя ниже API 9 (ниже, чем Gingerbread), он сбросил свой телефон или «Secure.ANDROID_ID». если возвращается значение «null», то просто возвращаемый идентификатор будет основан исключительно на информации об их устройстве Android. Вот где могут произойти столкновения. Старайтесь не использовать DISPLAY, HOST или ID - эти элементы могут измениться. Если есть коллизии, данные будут перекрываться. Источник: gist.github.com/pedja1/fe69e8a80ed505500caa

ᴛʜᴇᴘᴀᴛᴇʟ
3 апреля 2019 в 12:38
2

@Ninja Поскольку MAC-адрес BLE уникален, да, сгенерированный идентификатор всегда будет уникальным. Однако, если вы действительно хотите быть уверены, я бы предложил добавить UUID в longId. Измените эту строку следующим образом: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString(); Это гарантирует, что сгенерированный идентификатор будет уникальным.

avatar
Baskaran Veerabathiran
3 октября 2016 в 11:02
6

Идентификатор Mac устройства Android также является уникальным идентификатором. Он не изменится, даже если само устройство отформатировано.

Используйте следующий код, чтобы получить идентификатор Mac:

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

Также не забудьте добавить соответствующие разрешения в свой AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Ted Hopp
5 октября 2016 в 00:32
3

К сожалению, это не сработает, если нет текущего Wi-Fi-соединения. Из документы (курсив добавлен): «Возвращает динамическую информацию о текущем Wi-Fi-соединении, , если оно активно

user6796473
3 июля 2017 в 16:33
2

Также, предоставив root-доступ на устройстве, можно подделать MAC-адрес

Saddan
23 мая 2020 в 06:02
0

Устройства под управлением Android 10 (уровень API 29) и выше сообщают рандомизированные MAC-адреса всем приложениям, которые не являются приложениями владельца устройства, поэтому он не будет уникальным, если вы используете Android версии 10 или выше.

avatar
Ilan.b
1 сентября 2015 в 12:32
9

Для аппаратного распознавания определенного устройства Android вы можете проверить MAC-адреса.

вы можете сделать это так:

в AndroidManifest.xml

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

теперь в вашем коде:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

В каждом устройстве Android есть как минимум интерфейс "wlan0", а также чип WI-FI. Этот код работает, даже если WI-FI не включен.

П.С. Это множество других интерфейсов, которые вы получите из списка, содержащего MACS, но это может меняться между телефонами.

avatar
Tom
19 июня 2015 в 22:22
9

Идентификатор экземпляра Google

Выпущено на I / O 2015; на Android требуются игровые сервисы 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation<624196 >

InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
String id = iid.getId();  // blocking call

Похоже, Google намеревается использовать этот идентификатор для идентификации установок в Android, Chrome и iOS.

Он идентифицирует установку, а не устройство, но, опять же, ANDROID_ID (который является принятым ответом) теперь также больше не идентифицирует устройства. В среде выполнения ARC новый ANDROID_ID создается для каждой установки ( подробности здесь), точно так же, как этот новый идентификатор экземпляра. Кроме того, я думаю, что идентификация установок (а не устройств) - это то, что на самом деле ищет большинство из нас.

Преимущества идентификатора экземпляра

Мне кажется, что Google намеревается использовать его для этой цели (для идентификации ваших установок), он является кроссплатформенным и может использоваться для ряда других целей (см. Ссылки выше).

Если вы используете GCM, то в конечном итоге вам понадобится использовать этот идентификатор экземпляра, потому что он понадобится вам для получения токена GCM (который заменяет старый регистрационный идентификатор GCM).

Недостатки / проблемы

В текущей реализации (GPS 7.5) идентификатор экземпляра извлекается с сервера, когда ваше приложение запрашивает его. Это означает, что приведенный выше вызов является блокирующим - в моем ненаучном тестировании он занимает 1-3 секунды, если устройство подключено к сети, и 0,5 - 1,0 секунды, если устройство отключено (предположительно, это то время, которое он ждет, прежде чем сдаться и генерировать случайный идентификатор). Это было протестировано в Северной Америке на Nexus 5 с Android 5.1.1 и GPS 7.5.

Если вы используете идентификатор для целей, которые они намереваются - например. аутентификация приложения, идентификация приложения, GCM - я думаю, что эти 1-3 секунды могут доставлять неудобства (конечно, в зависимости от вашего приложения).

idanakav
8 июля 2015 в 16:13
3

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

Tom
8 июля 2015 в 20:11
0

Интересно, но я не думаю, что это действительно меняет потенциальные варианты использования: идентификатор экземпляра, например android_id, не подходит для идентификации устройства. Таким образом, ваш сервер будет видеть данные, очищаемые пользователем, как будто пользователь удаляет и повторно устанавливает ваше приложение, что не является необоснованным.

avatar
Jorgesys
6 февраля 2015 в 15:00
9

TelephonyManger.getDeviceId () Возвращает уникальный идентификатор устройства, например IMEI для GSM и MEID или ESN для телефонов CDMA.

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

Но я рекомендую использовать:

Settings.Secure.ANDROID_ID , который возвращает идентификатор Android в виде уникальной 64-битной шестнадцатеричной строки.

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

Иногда TelephonyManger.getDeviceId () возвращает значение null, поэтому для обеспечения уникального идентификатора вы будете использовать этот метод:

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}
Holger Jakobs
13 марта 2016 в 16:16
0

Недавно я обнаружил, что клиентское устройство типа SM-G928F / Galaxy S6 edge + предоставляет только 15 шестнадцатеричных цифр вместо 16 для идентификатора Android.

avatar
Jorgesys
13 января 2014 в 00:30
12

Уникальный идентификатор устройства с ОС Android в виде строки с использованием TelephonyManager и ANDROID_ID получается следующим образом:

String deviceId;
final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
    deviceId = mTelephony.getDeviceId();
}
else {
    deviceId = Secure.getString(
                   getApplicationContext().getContentResolver(),
                   Secure.ANDROID_ID);
}

Но я настоятельно рекомендую метод, предложенный Google, см. Определение установок приложения .

avatar
Ciul
6 января 2014 в 22:30
0

Проверить наличие SystemInfo.deviceUniqueIdentifier

Документация: http://docs.unity3d.com/Documentation/ScriptReference/SystemInfo-deviceUniqueIdentifier.html

Уникальный идентификатор устройства. Гарантия уникальности для каждого устройства (только чтение).

iOS: на устройствах до iOS7 возвращается хэш MAC-адреса. На устройствах iOS7 это будет UIDevice identifierForVendor или, если это не удается по какой-либо причине, ASIdentifierManager AdvertisingIdentifier.

avatar
Hertzel Guinness
2 ноября 2013 в 13:23
7

Google теперь имеет рекламный идентификатор.
Это также можно использовать, но учтите, что:

Рекламный идентификатор - это индивидуальный для пользователя уникальный сбрасываемый идентификатор

и

позволяет пользователям сбросить свой идентификатор или отказаться от рекламы на основе интересов в приложениях Google Play.

Итак, хотя этот идентификатор может измениться, похоже, что скоро у нас может не быть выбора, в зависимости от цели этого идентификатора.

Дополнительная информация @ develper.android

Скопируйте и вставьте код здесь

HTH

Jared Burrows
6 ноября 2013 в 14:37
0

Его можно сбросить: рекламный идентификатор - это уникальный, но сбрасываемый пользователем строковый идентификатор, который позволяет рекламным сетям и другим приложениям анонимно идентифицировать пользователя.

Hertzel Guinness
6 ноября 2013 в 17:04
2

(@JaredBurrows да, это упоминается в посте ...)

avatar
TootsieRockNRoll
21 октября 2013 в 10:04
0

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

Ted Hopp
21 октября 2013 в 12:17
7

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

avatar
Mr_and_Mrs_D
18 сентября 2013 в 19:12
10

Мои два цента - NB, это для устройства (err) с уникальным идентификатором , а не для установочного, как описано в блоге разработчиков Android.

Следует отметить, что решение, предоставляемое @emmby, возвращается к каждому идентификатору приложения, поскольку SharedPreferences не синхронизируются между процессами (см. Здесь и здесь). Так что я этого вообще избегал.

Вместо этого я инкапсулировал различные стратегии получения идентификатора (устройства) в перечисление - изменение порядка констант перечисления влияет на приоритет различных способов получения идентификатора. Возвращается первый ненулевой идентификатор или генерируется исключение (в соответствии с хорошими практиками Java, не придающими значения null). Так, например, у меня сначала есть ТЕЛЕФОНИЯ, но хорошим выбором по умолчанию будет ANDROID_ID. бета:

import android.Manifest.permission;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

// TODO : hash
public final class DeviceIdentifier {

    private DeviceIdentifier() {}

    /** @see http://code.google.com/p/android/issues/detail?id=10603 */
    private static final String ANDROID_ID_BUG_MSG = "The device suffers from "
        + "the Android ID bug - its ID is the emulator ID : "
        + IDs.BUGGY_ANDROID_ID;
    private static volatile String uuid; // volatile needed - see EJ item 71
    // need lazy initialization to get a context

    /**
     * Returns a unique identifier for this device. The first (in the order the
     * enums constants as defined in the IDs enum) non null identifier is
     * returned or a DeviceIDException is thrown. A DeviceIDException is also
     * thrown if ignoreBuggyAndroidID is false and the device has the Android ID
     * bug
     *
     * @param ctx
     *            an Android constant (to retrieve system services)
     * @param ignoreBuggyAndroidID
     *            if false, on a device with the android ID bug, the buggy
     *            android ID is not returned instead a DeviceIDException is
     *            thrown
     * @return a *device* ID - null is never returned, instead a
     *         DeviceIDException is thrown
     * @throws DeviceIDException
     *             if none of the enum methods manages to return a device ID
     */
    public static String getDeviceIdentifier(Context ctx,
            boolean ignoreBuggyAndroidID) throws DeviceIDException {
        String result = uuid;
        if (result == null) {
            synchronized (DeviceIdentifier.class) {
                result = uuid;
                if (result == null) {
                    for (IDs id : IDs.values()) {
                        try {
                            result = uuid = id.getId(ctx);
                        } catch (DeviceIDNotUniqueException e) {
                            if (!ignoreBuggyAndroidID)
                                throw new DeviceIDException(e);
                        }
                        if (result != null) return result;
                    }
                    throw new DeviceIDException();
                }
            }
        }
        return result;
    }

    private static enum IDs {
        TELEPHONY_ID {

            @Override
            String getId(Context ctx) {
                // TODO : add a SIM based mechanism ? tm.getSimSerialNumber();
                final TelephonyManager tm = (TelephonyManager) ctx
                        .getSystemService(Context.TELEPHONY_SERVICE);
                if (tm == null) {
                    w("Telephony Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.READ_PHONE_STATE);
                return tm.getDeviceId();
            }
        },
        ANDROID_ID {

            @Override
            String getId(Context ctx) throws DeviceIDException {
                // no permission needed !
                final String andoidId = Secure.getString(
                    ctx.getContentResolver(),
                    android.provider.Settings.Secure.ANDROID_ID);
                if (BUGGY_ANDROID_ID.equals(andoidId)) {
                    e(ANDROID_ID_BUG_MSG);
                    throw new DeviceIDNotUniqueException();
                }
                return andoidId;
            }
        },
        WIFI_MAC {

            @Override
            String getId(Context ctx) {
                WifiManager wm = (WifiManager) ctx
                        .getSystemService(Context.WIFI_SERVICE);
                if (wm == null) {
                    w("Wifi Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess
                // getMacAddress() has no java doc !!!
                return wm.getConnectionInfo().getMacAddress();
            }
        },
        BLUETOOTH_MAC {

            @Override
            String getId(Context ctx) {
                BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
                if (ba == null) {
                    w("Bluetooth Adapter not available");
                    return null;
                }
                assertPermission(ctx, permission.BLUETOOTH);
                return ba.getAddress();
            }
        }
        // TODO PSEUDO_ID
        // http://www.pocketmagic.net/2011/02/android-unique-device-id/
        ;

        static final String BUGGY_ANDROID_ID = "9774d56d682e549c";
        private final static String TAG = IDs.class.getSimpleName();

        abstract String getId(Context ctx) throws DeviceIDException;

        private static void w(String msg) {
            Log.w(TAG, msg);
        }

        private static void e(String msg) {
            Log.e(TAG, msg);
        }
    }

    private static void assertPermission(Context ctx, String perm) {
        final int checkPermission = ctx.getPackageManager().checkPermission(
            perm, ctx.getPackageName());
        if (checkPermission != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission " + perm + " is required");
        }
    }

    // =========================================================================
    // Exceptions
    // =========================================================================
    public static class DeviceIDException extends Exception {

        private static final long serialVersionUID = -8083699995384519417L;
        private static final String NO_ANDROID_ID = "Could not retrieve a "
            + "device ID";

        public DeviceIDException(Throwable throwable) {
            super(NO_ANDROID_ID, throwable);
        }

        public DeviceIDException(String detailMessage) {
            super(detailMessage);
        }

        public DeviceIDException() {
            super(NO_ANDROID_ID);
        }
    }

    public static final class DeviceIDNotUniqueException extends
            DeviceIDException {

        private static final long serialVersionUID = -8940090896069484955L;

        public DeviceIDNotUniqueException() {
            super(ANDROID_ID_BUG_MSG);
        }
    }
}
avatar
Jared Burrows
12 июля 2013 в 23:58
451

# Последнее обновление: 02.06.15


Прочитав все сообщения Stack Overflow о создании уникального идентификатора, блог разработчиков Google и документацию по Android, я чувствую, что «Псевдоидентификатор» - лучший из возможных вариантов.

Основная проблема: аппаратное обеспечение и программное обеспечение

Аппаратное обеспечение

  • Пользователи могут менять свое оборудование, планшет Android или телефон, поэтому уникальные идентификаторы, основанные на оборудовании, не подходят для ПОЛЬЗОВАТЕЛЕЙ ОТСЛЕЖИВАНИЯ
  • Для ОБОРУДОВАНИЕ ОТСЛЕЖИВАНИЯ , это отличная идея

Программное обеспечение

  • Пользователи могут стереть / изменить свое ПЗУ, если они рутированы
  • Вы можете отслеживать пользователей на разных платформах (iOS, Android, Windows и Интернет)
  • Лучшее, что нужно для ОТСЛЕЖИВАТЬ ИНДИВИДУАЛЬНОГО ПОЛЬЗОВАТЕЛЯ с его согласием , - просто попросить их войти (сделать это без проблем с помощью OAuth)

# Общая поломка с Android

### - Гарантия уникальности (включая корневые устройства) для API> = 9/10 (99,5% устройств Android) ### - Без дополнительных разрешений

Псевдокод:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return the unique ID of build information (may overlap data - API < 9)

Спасибо @stansult за публикацию всех наших вариантов (в этом вопросе о переполнении стека).

## Список опций - причины, почему / почему их не использовать:

  • Электронная почта пользователя - Программное обеспечение

  • Пользователь может изменить адрес электронной почты - Маловероятно

  • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> или

  • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> (Как получить основной адрес электронной почты устройства Android)

  • Телефонный номер пользователя - программное обеспечение

  • Пользователи могут менять номера телефонов - ВНИМАНИЕ!

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

  • IMEI - оборудование (только телефоны, требуется android.permission.READ_PHONE_STATE )

  • Большинство пользователей ненавидят то, что в разрешении написано «Телефонные звонки». Некоторые пользователи дают плохие оценки, потому что считают, что вы просто крадете их личную информацию, тогда как все, что вам действительно нужно, - это отслеживать установки устройств. Очевидно, что вы собираете данные.

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

  • Android ID - Аппаратное обеспечение (может быть нулевым, может быть изменено при сбросе настроек, может быть изменено на корневом устройстве)

  • Поскольку он может иметь значение «null», мы можем проверить наличие «null» и изменить его значение, но это означает, что оно больше не будет уникальным.

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

  • MAC-адрес WLAN - оборудование (требуется android.permission.ACCESS_WIFI_STATE )

  • Это может быть второй лучший вариант, но вы по-прежнему собираете и храните уникальный идентификатор, который исходит непосредственно от пользователя. Очевидно, что вы собираете данные.

  • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>

  • MAC-адрес Bluetooth - оборудование (для устройств с Bluetooth требуется android.permission.BLUETOOTH )

  • Большинство приложений на рынке не используют Bluetooth, поэтому, если ваше приложение не использует Bluetooth и вы его включаете, пользователь может заподозрить подозрение.

  • <uses-permission android:name="android.permission.BLUETOOTH "/>

  • Псевдоуникальный идентификатор - программное обеспечение (для всех устройств Android)

  • Очень возможно, может содержать коллизии - см. Мой метод, опубликованный ниже!

  • Это позволяет вам получить «почти уникальный» идентификатор пользователя, не принимая ничего личного. Вы можете создать свой собственный анонимный идентификатор на основе информации об устройстве.


Я знаю, что не существует «идеального» способа получить уникальный идентификатор без использования разрешений; однако иногда нам действительно нужно только отслеживать установку устройства. Когда дело доходит до создания уникального идентификатора, мы можем создать «псевдоуникальный идентификатор» исключительно на основе информации, которую предоставляет нам Android API, без использования дополнительных разрешений. Таким образом, мы можем проявить уважение к пользователю и попытаться предложить ему хороший опыт.

С псевдоуникальным идентификатором вы действительно столкнетесь только с тем фактом, что могут быть дубликаты, основанные на том факте, что существуют похожие устройства. Вы можете настроить комбинированный метод, чтобы сделать его более уникальным; однако некоторым разработчикам необходимо отслеживать установку устройств, и это поможет или повысит производительность на основе аналогичных устройств.

## API> = 9:

Если их устройство Android имеет API 9 или более поздней версии, это гарантированно будет уникальным из-за поля "Build.SERIAL".

ПОМНИТЕ , технически вы упускаете из виду только около 0,5% пользователей с API <9. Так что можете сосредоточиться на остальном: это 99,5% пользователей!

## API <9:

Если устройство Android пользователя ниже API 9; Надеюсь, они не сбросили настройки до заводских, и их Secure.ANDROID_ID будет сохранен или не будет иметь значение null. (см. http://developer.android.com/about/dashboards/index.html)

## Если ничего не помогает:

Если все остальное не помогает, если у пользователя ниже API 9 (ниже, чем Gingerbread), он сбросил свое устройство или Secure.ANDROID_ID возвращает значение null, тогда просто возвращаемый идентификатор будет основан исключительно на их Информация об устройстве Android. Здесь могут произойти столкновения.

Изменения:

  • Удален "Android.SECURE_ID", поскольку заводские сбросы могут привести к изменению значения
  • Отредактировал код для изменения в API
  • Изменено псевдо

Воспользуйтесь приведенным ниже методом:

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // If all else fails, if the user does have lower than API 9 (lower
    // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
    // returns 'null', then simply the ID returned will be solely based
    // off their Android device information. This is where the collisions
    // can happen.
    // Thanks http://www.pocketmagic.net/?p=1662!
    // Try not to use DISPLAY, HOST or ID - these items could change.
    // If there are collisions, there will be overlapping data
    String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

    // Thanks to @Roman SL!
    // https://coderhelper.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://coderhelper.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

#New (для приложений с рекламой И сервисов Google Play):

Из консоли разработчика Google Play:

Начиная с 1 августа 2014 г., Правила программы для разработчиков Google Play. требует загрузки новых приложений и обновлений для использования рекламного идентификатора в вместо любых других постоянных идентификаторов для любых рекламных целей. Узнать больше

Реализация :

Разрешение:

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

Код:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g. 
    // the old version of the service doesn't support getting AdvertisingId).
 
  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

Источник / документы:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

## Важно:

Предполагается, что рекламный идентификатор полностью заменит существующие использование других идентификаторов в рекламных целях (например, использование ANDROID_ID в Настройках.Secure), когда доступны Сервисы Google Play. Случаи недоступные сервисы Google Play отмечены значком Исключение GooglePlayServicesNotAvailableException выбрасывается getAdvertisingIdInfo ().

## Предупреждение, пользователи могут сбросить:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

Я попытался сослаться на каждую ссылку, по которой я брал информацию. Если вас что-то не хватает, и вы должны быть включены, прокомментируйте!

Идентификатор экземпляра служб Google Player

https://developers.google.com/instance-id/

hojjat reyhane
17 марта 2015 в 16:36
6

Я использовал ваш метод в своем приложении для отправки комментариев. У меня плохие новости. к сожалению, PsuedoID не является полностью уникальным. мой сервер записал более 100 для 5 ID и более 30 для почти 30 ID. наиболее часто повторяющимися идентификаторами являются «ffffffff-fc8f-6093-ffff-ffffd8» (159 записей) и «ffffffff-fe99-b334-ffff-ffffef» (154 раза). также судя по времени и комментариям, очевидно, что есть разные народы. общее количество записей до сих пор составляет 10 000. пожалуйста, дайте мне знать, почему это произошло. танки.

Jared Burrows
17 марта 2015 в 17:35
2

Я написал это 1,5+ года назад. Я не уверен, почему это не уникально для вас. Вы можете попробовать рекламный идентификатор. Если нет, вы можете предложить собственное решение.

Durai Amuthan.H
29 апреля 2015 в 17:41
3

вроде .. Буду очень признателен, если вы ответите на вопрос и поделитесь своим мнением по этому поводу

Jared Burrows
6 мая 2015 в 14:08
1

@ user1587329 Спасибо. Я стараюсь держать это в курсе для всех. Это сложный вопрос, когда речь идет об аппаратном обеспечении, программном обеспечении и кросс-платформе.

avatar
Eng.Fouad
27 мая 2013 в 18:34
10

Вот как я генерирую уникальный идентификатор:

public static String getDeviceId(Context ctx)
{
    TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

    String tmDevice = tm.getDeviceId();
    String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
    String serial = null;
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;

    if(tmDevice != null) return "01" + tmDevice;
    if(androidId != null) return "02" + androidId;
    if(serial != null) return "03" + serial;
    // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}
Harsha
17 ноября 2016 в 14:06
0

если мы используем ReadPhoneState в версии 6.0, запрашивая разрешение на выполнение

avatar
Asaf Pinhassi
15 апреля 2013 в 13:01
9

Я использую следующий код, чтобы получить IMEI или использовать Secure. ANDROID_ID в качестве альтернативы, когда у устройства нет возможностей телефона:

String identifier = null;
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
if (tm != null)
      identifier = tm.getDeviceId();
if (identifier == null || identifier .length() == 0)
      identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);
avatar
Android
27 февраля 2013 в 10:03
14

Добавьте код ниже в файл класса:

final TelephonyManager tm = (TelephonyManager) getBaseContext()
            .getSystemService(SplashActivity.TELEPHONY_SERVICE);
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    Log.v("DeviceIMEI", "" + tmDevice);
    tmSerial = "" + tm.getSimSerialNumber();
    Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.ANDROID_ID);
    Log.v("androidId CDMA devices", "" + androidId);
    UUID deviceUuid = new UUID(androidId.hashCode(),
            ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
    String deviceModelName = android.os.Build.MODEL;
    Log.v("Model Name", "" + deviceModelName);
    String deviceUSER = android.os.Build.USER;
    Log.v("Name USER", "" + deviceUSER);
    String devicePRODUCT = android.os.Build.PRODUCT;
    Log.v("PRODUCT", "" + devicePRODUCT);
    String deviceHARDWARE = android.os.Build.HARDWARE;
    Log.v("HARDWARE", "" + deviceHARDWARE);
    String deviceBRAND = android.os.Build.BRAND;
    Log.v("BRAND", "" + deviceBRAND);
    String myVersion = android.os.Build.VERSION.RELEASE;
    Log.v("VERSION.RELEASE", "" + myVersion);
    int sdkVersion = android.os.Build.VERSION.SDK_INT;
    Log.v("VERSION.SDK_INT", "" + sdkVersion);

Добавьте в AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
avatar
insitusec
31 января 2013 в 15:40
9

Другой способ - использовать /sys/class/android_usb/android0/iSerial в приложении без каких-либо разрешений.

user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

Чтобы сделать это в Java, нужно просто использовать FileInputStream для открытия файла iSerial и считывания символов. Просто убедитесь, что вы заключили его в обработчик исключений, потому что не на всех устройствах есть этот файл.

Известно, что по крайней мере следующие устройства имеют этот файл доступным для чтения всем:

  • Galaxy Nexus
  • Nexus S
  • Motorola Xoom 3G
  • Toshiba AT300
  • HTC One V
  • Мини MK802
  • Samsung Galaxy S II

Вы также можете увидеть мое сообщение в блоге Утечка серийного номера оборудования Android в непривилегированных приложениях , где я обсуждаю, какие еще файлы доступны для информации.

Tom
30 апреля 2013 в 21:14
0

Я только что прочитал твое сообщение в блоге. Я считаю, что это не уникально: Build.SERIAL также доступен без каких-либо разрешений и (теоретически) является уникальным серийным номером оборудования.

insitusec
14 марта 2014 в 17:16
2

Ты прав. Это всего лишь еще один способ отслеживания вашего устройства, и, как вы сказали, оба эти способа не требуют разрешений приложений.

avatar
TechnoTony
22 декабря 2012 в 08:13
47

В Google I / O Рето Мейер представил надежный ответ на вопрос, как к этому подойти, что должно удовлетворить потребности большинства разработчиков в отслеживании пользователей в разных установках. Энтони Нолан показывает направление в своем ответе, но я подумал, что напишу полный подход, чтобы другие могли легко понять, как это сделать (мне потребовалось время, чтобы разобраться в деталях).

Этот подход предоставит вам анонимный, безопасный идентификатор пользователя, который будет постоянным для пользователя на разных устройствах (на основе основной учетной записи Google) и между установками. Базовый подход - создать случайный идентификатор пользователя и сохранить его в общих настройках приложений. Затем вы используете агент резервного копирования Google, чтобы сохранить общие настройки, связанные с учетной записью Google, в облаке.

Давайте рассмотрим полный подход. Во-первых, нам нужно создать резервную копию наших SharedPreferences с помощью Android Backup Service. Начните с регистрации своего приложения через http://developer.android.com/google/backup/signup.html.

Google предоставит вам резервный сервисный ключ, который вам нужно добавить в манифест. Вам также необходимо указать приложению использовать BackupAgent следующим образом:

<application android:label="MyApplication"
         android:backupAgent="MyBackupAgent">
    ...
    <meta-data android:name="com.google.android.backup.api_key"
        android:value="your_backup_service_key" />
</application>

Затем вам нужно создать агент резервного копирования и указать ему использовать вспомогательный агент для общих настроек:

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

Для завершения резервного копирования вам необходимо создать экземпляр BackupManager в основном действии:

BackupManager backupManager = new BackupManager(context);

Наконец, создайте идентификатор пользователя, если он еще не существует, и сохраните его в SharedPreferences:

  public static String getUserID(Context context) {
            private static String uniqueID = null;
        private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                MyBackupAgent.PREFS, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();

            //backup the changes
            BackupManager mBackupManager = new BackupManager(context);
            mBackupManager.dataChanged();
        }
    }

    return uniqueID;
}

Этот User_ID теперь будет постоянным для всех установок, даже если пользователь перемещает устройство.

Для получения дополнительной информации об этом подходе см. выступление Рето.

И для получения полной информации о том, как реализовать агент резервного копирования, см. Резервное копирование данных . Я особенно рекомендую раздел внизу, посвященный тестированию, поскольку резервное копирование не происходит мгновенно, и поэтому для тестирования вам нужно принудительно выполнить резервное копирование.

Tosa
13 марта 2013 в 02:25
7

Разве это не приводит к появлению нескольких устройств с одним и тем же идентификатором, когда у пользователя несколько устройств? Например, планшет и телефон.

avatar
Andreas Klöber
18 ноября 2012 в 10:26
13

Существует множество различных подходов к решению этих ANDROID_ID проблем (иногда может быть null или устройства определенной модели всегда возвращают один и тот же идентификатор) с плюсами и минусами:

  • Реализация алгоритма генерации пользовательского идентификатора (на основе свойств устройства, которые должны быть статичными и не изменяться -> кто знает)
  • Злоупотребление другими идентификаторами, такими как IMEI, серийный номер, MAC-адрес Wi-Fi / Bluetooth (они не будут существовать на всех устройствах, или потребуются дополнительные разрешения)

Я предпочитаю использовать существующую реализацию OpenUDID (см. https://github.com/ylechelle/OpenUDID) для Android (см. https://github.com/vieux/OpenUDID). Его легко интегрировать, и он использует ANDROID_ID с запасными вариантами для тех проблем, о которых говорилось выше.

avatar
stansult
8 февраля 2012 в 02:16
90

Здесь есть полезная информация здесь .

Он охватывает пять различных типов идентификаторов:

  1. IMEI (только для устройств Android с использованием телефона; требуется android.permission.READ_PHONE_STATE)
  2. Псевдоуникальный идентификатор (для всех устройств Android)
  3. Android ID (может быть нулевым, может измениться при сбросе настроек, может быть изменен на телефоне с рутированным доступом)
  4. MAC-адрес WLAN строка (требуется android.permission.ACCESS_WIFI_STATE)
  5. BT MAC-адрес строка (для устройств с Bluetooth требуется android.permission.BLUETOOTH)
Tom
7 октября 2012 в 22:44
3

Упущен важный момент (здесь и в статье): вы не можете получить WLAN или BT MAC, если они не включены! В противном случае я думаю, что MAC-адрес WLAN был бы идеальным идентификатором. У вас нет гарантии, что пользователь когда-либо включит свой Wi-Fi, и я действительно не думаю, что «уместно» включать его самостоятельно.

Marqs
4 августа 2014 в 10:20
2

@Tom ты ошибаешься. Вы все равно можете читать WLAN или BT MAC, даже когда они выключены. Однако нет гарантии, что в устройстве доступны модули WLAN или BT.

sarika kate
30 марта 2016 в 06:03
4

В частности, локальные MAC-адреса WiFi и Bluetooth больше не доступны. Метод getMacAddress () объекта aWifiInfo и метод BluetoothAdapter.getDefaultAdapter (). GetAddress () с этого момента будут возвращать 02: 00: 00: 00: 00: 00

Smeet
13 апреля 2016 в 10:22
5

@sarikakate Это правда только в 6.0 Marshmallow и выше ... Он все еще работает, как ожидалось, в версиях ниже 6.0 Marshmallow.

avatar
Anthony Nolan
28 октября 2011 в 13:19
185

Вот код, который Рето Мейер использовал в презентации Google I / O в этом году, чтобы получить уникальный идентификатор пользователя:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, Context.MODE_PRIVATE);
        uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
        if (uniqueID == null) {
            uniqueID = UUID.randomUUID().toString();
            Editor editor = sharedPrefs.edit();
            editor.putString(PREF_UNIQUE_ID, uniqueID);
            editor.commit();
        }
    }
    return uniqueID;
}

Если вы объедините это со стратегией резервного копирования для отправки настроек в облако (также описанной в докладе Reto , у вас должен быть идентификатор, который привязан к пользователю и остается после очистки устройства, или даже заменить. Я планирую использовать это в аналитике в будущем (другими словами, я еще не сделал этого :).

Kyle Clegg
15 мая 2012 в 21:52
4

Отличный вариант, если вам не нужен уникальный идентификатор для сохранения после удаления и повторной установки (например, рекламное мероприятие / игра, в которой у вас есть три шанса на победу, точка).

Carl
22 декабря 2012 в 11:15
3

Презентация Мейера основана на использовании Android Backup Manager, который, в свою очередь, зависит от выбора пользователем этой функции. Это нормально для пользовательских предпочтений приложения (использование Мейера), потому что, если пользователь не выбрал этот вариант, он просто не получит их резервные копии. Однако исходный вопрос касается создания уникального идентификатора для устройства , и этот идентификатор создается для каждого приложения, а не для каждой установки, не говоря уже о каждом устройстве, и поскольку он зависит от выбора пользователем резервной копии вариант, его использование, выходящее за рамки предпочтений пользователя (например, для ограниченного по времени пробного периода), ограничено.

John Shelley
2 сентября 2014 в 02:25
16

Это не сработает при удалении или очистке данных.

famfamfam
23 февраля 2021 в 10:17
0

очень плохое решение

vin shaba
25 апреля 2021 в 09:12
0

Я думаю, что это хорошее решение, на устройстве и на сервере есть уникальный идентификатор на случай удаления. Вы можете убедиться, что сохранили его по электронной почте клиента, чтобы он прилипал ;-p

avatar
Kevin Parker
2 августа 2011 в 03:21
18

Подробные инструкции по получению уникального идентификатора для каждого устройства Android, с которого установлено ваше приложение, см. В официальном блоге разработчиков Android: Определение установок приложения .

.

.

Кажется, лучший способ - создать его самостоятельно при установке и впоследствии прочитать его при повторном запуске приложения.

Лично я считаю это приемлемым, но не идеальным. Ни один идентификатор, предоставляемый Android, не работает во всех случаях, поскольку большинство из них зависит от состояния радиосвязи телефона (включение / выключение Wi-Fi, включение / выключение сотовой связи, включение / выключение Bluetooth). Остальные, такие как Settings.Secure.ANDROID_ID, должны быть реализованы производителем и не гарантируются уникальностью.

Ниже приведен пример записи данных в файл установки , который будет храниться вместе с любыми другими данными, которые приложение сохраняет локально.

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}
Luca Spiller
3 октября 2011 в 19:56
1

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

tasomaniac
9 мая 2012 в 21:24
0

А как насчет рутированных устройств? Они могут легко изменить этот установочный идентификатор, не так ли?

Kevin Parker
18 мая 2012 в 16:52
0

Абсолютно. Root может изменить ID установки. Проверить наличие root можно с помощью этого блока кода: coderhelper.com/questions/1101380/…

Jamshid
8 января 2015 в 10:26
0

если мы сбросим заводские настройки, файл будет удален?

Kevin Parker
12 января 2015 в 02:08
0

Если вы сбросите настройки и удалите или отформатируете раздел / data, UUID будет другим.

avatar
Elzo Valugi
14 июля 2011 в 20:01
11

Как насчет IMEI. Это уникально для Android и других мобильных устройств.

Brill Pappin
5 января 2012 в 16:54
11

Не для моих планшетов, у которых нет IMEI, поскольку они не подключаются к моему оператору мобильной связи.

David Given
25 января 2012 в 12:25
3

Не говоря уже об устройствах CDMA, у которых есть ESN вместо IMEI.

Brill Pappin
26 января 2012 в 19:39
2

Это только то, что это телефон :) Планшет не может.

MLQ
25 сентября 2012 в 09:42
4

@ElzoValugi Это уже "в наши дни" и еще не на всех планшетах есть SIM-карты.

avatar
Mohit Kanada
17 мая 2011 в 14:44
31

Используя приведенный ниже код, вы можете получить уникальный идентификатор устройства с ОС Android в виде строки.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
avatar
emmby
11 апреля 2011 в 19:06
347

Как упоминает Дэйв Уэбб, в блоге разработчиков Android есть статья, посвященная этому. Их предпочтительное решение - отслеживать установки приложений, а не устройств, и это хорошо работает для большинства случаев использования. Сообщение в блоге покажет вам код, необходимый для работы, и я рекомендую вам проверить его.

Однако в блоге обсуждаются решения, если вам нужен идентификатор устройства, а не идентификатор установки приложения. Я поговорил с кем-то в Google, чтобы получить дополнительные разъяснения по некоторым вопросам, если вам это понадобится. Вот что я обнаружил об идентификаторах устройств, которые НЕ упоминаются в вышеупомянутом сообщении блога:

  • ANDROID_ID - предпочтительный идентификатор устройства. ANDROID_ID идеально подходит для версий Android <= 2.1 или> = 2.3. Только 2.2 имеет проблемы, упомянутые в посте.
  • Несколько устройств от нескольких производителей подвержены ошибке ANDROID_ID в 2.2.
  • Насколько я смог определить, все затронутые устройства имеют одинаковый ANDROID_ID, который равен 9774d56d682e549c. Это тот же идентификатор устройства, который сообщил эмулятор, кстати.
  • Google считает, что OEM-производители исправили проблему для многих или большинства своих устройств, но я смог убедиться, что, по крайней мере, на начало апреля 2011 года все еще довольно легко найти устройства с неработающим идентификатором ANDROID_ID.

Основываясь на рекомендациях Google, я реализовал класс, который будет генерировать уникальный UUID для каждого устройства, используя ANDROID_ID в качестве начального значения, где это необходимо, при необходимости прибегая к TelephonyManager.getDeviceId (), а если это не удается, прибегая к случайному сгенерированный уникальный UUID, который сохраняется при перезапуске приложения (но не при повторной установке приложения).

Обратите внимание, что для устройств, которые должны использовать резервный идентификатор устройства, уникальный идентификатор БУДЕТ сохраняться при заводских сбросах. Об этом следует помнить. Если вам нужно убедиться, что при сбросе настроек к заводским настройкам ваш уникальный идентификатор будет сброшен, вы можете рассмотреть возможность возврата непосредственно к случайному UUID, а не к идентификатору устройства.

Опять же, этот код предназначен для идентификатора устройства, а не идентификатора установки приложения. В большинстве случаев вам, вероятно, нужен идентификатор установки приложения. Но если вам нужен идентификатор устройства, то, вероятно, вам подойдет следующий код.

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}
Steve Pomeroy
11 апреля 2011 в 20:10
7

Разве вы не должны хэшировать различные идентификаторы, чтобы они все были одного размера? Кроме того, вы должны хешировать идентификатор устройства, чтобы случайно не раскрыть личную информацию.

Steve Pomeroy
11 апреля 2011 в 20:12
0

Кроме того, устройство, конфигурация которого вызывает использование идентификатора устройства, привяжет идентификатор к устройству , не обязательно к пользователю. Этот идентификатор переживет сброс настроек до заводских, что потенциально может быть плохим. Может быть, идентификатор устройства может быть хеширован с помощью чего-то, что сообщает время последнего сброса настроек?

emmby
11 апреля 2011 в 21:53
3

Хорошие замечания, Стив. Я обновил код, чтобы всегда возвращать UUID. Это гарантирует, что а) сгенерированные идентификаторы всегда имеют одинаковый размер и б) идентификаторы Android и устройства хешируются перед возвратом, чтобы избежать случайного раскрытия личной информации. Я также обновил описание, чтобы отметить, что идентификатор устройства будет сохраняться при заводских сбросах и что это может быть нежелательно для некоторых пользователей.

Tim Bray
12 апреля 2011 в 04:58
2

Я считаю, что вы ошибаетесь; предпочтительным решением является отслеживание установок, а не идентификаторов устройств. Ваш код значительно длиннее и сложнее, чем в сообщении в блоге, и для меня не очевидно, что он добавляет какую-либо ценность.

emmby
12 апреля 2011 в 12:25
8

Хороший момент, я обновил комментарий, чтобы настоятельно рекомендовать пользователям использовать идентификаторы установки приложений, а не идентификаторы устройств. Однако я думаю, что это решение по-прежнему полезно для людей, которым нужно устройство, а не идентификатор установки.

Samuel
19 мая 2011 в 08:12
10

ANDROID_ID может измениться при сбросе настроек, поэтому он также не может идентифицировать устройства

Mr_and_Mrs_D
18 сентября 2013 в 12:46
2

Как я заметил в вашем ответе здесь, нет никакой гарантии, что вы получите один и тот же сгенерированный UUID для всех процессов - копия SharedPrefs локальная !

avatar
BoD
6 апреля 2011 в 07:36
53

В официальном блоге разработчиков Android теперь есть полная статья именно по этой теме: Определение установок приложений .

Tim Bray
12 апреля 2011 в 04:57
6

Ключевым моментом этого аргумента является то, что если вы пытаетесь получить уникальный идентификатор оборудования, вы, вероятно, делаете ошибку.

Seva Alekseyev
4 мая 2011 в 18:54
4

И если вы разрешаете сброс блокировки устройства с помощью заводских настроек, ваша пробная модель практически мертва.

Bruno Bieri
16 сентября 2020 в 13:12
0

И сообщение в блоге уже ссылается на этот сайт: developer.android.com/training/articles/user-data-ids

avatar
Lenn Dolling
24 марта 2011 в 19:55
43

Я думаю, что это верный способ построения каркаса для уникального идентификатора ... проверьте это.

Псевдо-уникальный идентификатор, который работает на всех устройствах Android. На некоторых устройствах нет телефона (например, планшеты) или по какой-то причине вы не хотите включать разрешение READ_PHONE_STATE. Вы по-прежнему можете читать такие детали, как версия ПЗУ, название производителя, тип процессора и другие сведения об оборудовании, которые хорошо подойдут, если вы хотите использовать идентификатор для проверки серийного ключа или других общих целей. Вычисленный таким образом идентификатор не будет уникальным: можно найти два устройства с одинаковым идентификатором (на основе одного и того же оборудования и образа ПЗУ), но изменения в реальных приложениях незначительны. Для этого вы можете использовать класс Build:

String m_szDevIDShort = "35" + //we make this look like a valid IMEI
            Build.BOARD.length()%10+ Build.BRAND.length()%10 +
            Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
            Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
            Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
            Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
            Build.TAGS.length()%10 + Build.TYPE.length()%10 +
            Build.USER.length()%10 ; //13 digits

Большинство элементов сборки являются строками, и мы здесь берем их длину и преобразуем ее по модулю в цифру. У нас есть 13 таких цифр, и мы добавляем еще две впереди (35), чтобы иметь идентификатор того же размера, что и IMEI (15 цифр). Здесь есть и другие возможности, просто взгляните на эти строки. Возвращает что-то вроде 355715565309247. Никакого специального разрешения не требуется, что делает этот подход очень удобным.


(Дополнительная информация: описанный выше метод был скопирован из статьи на Pocket Magic.)

Steve Pomeroy
12 апреля 2011 в 16:28
10

Интересное решение. Похоже, это ситуация, когда вы действительно должны просто хешировать все эти данные, объединенные, вместо того, чтобы пытаться придумать свою собственную «хеш-функцию». Есть много случаев, когда вы получите коллизии, даже если есть существенные данные, которые различаются для каждого значения. Моя рекомендация: используйте хеш-функцию, а затем преобразуйте двоичные результаты в десятичные и при необходимости усеките их. Чтобы сделать это правильно, вам действительно следует использовать UUID или полную хеш-строку.

Lenn Dolling
15 мая 2011 в 00:09
1

Я обнаружил, что Build.CPU_ABI и Build.MANUFACTURER присутствуют не во всех версиях .. Я получал серьезные ошибки сборки при работе с <2.2 :)

Steve Haley
16 мая 2011 в 12:07
25

Вы должны отдать должное своим источникам ... Это было поднято прямо из следующей статьи: pocketmagic.net/?p=1662

Seva Alekseyev
26 мая 2011 в 20:21
11

Этот идентификатор открыт для коллизий, как будто вы не знаете какие. Практически гарантированно будет то же самое на идентичных устройствах от одного и того же оператора.

David Given
25 января 2012 в 12:25
9

Это также может измениться при обновлении устройства.

Victor Ronin
26 июля 2012 в 17:26
5

Не думаю, что использовать это решение - хорошая идея. Насколько я понимаю, все поля сборки будут одинаковыми для всех телефонов, производимых вместе.

Carl
23 декабря 2012 в 05:40
2

Согласно комментарию Дэвида Гивена, это кажется серьезной проблемой. Следует провести тщательную инвентаризацию атрибутов сборки, чтобы определить, какие из них вряд ли изменятся в результате беспроводного обновления. Например, , Build.DISPLAY, приведенный выше, согласно Javadoc, - это «Строка идентификатора сборки, предназначенная для отображения пользователю», так что вряд ли она изменится при обновлении? Я все еще думаю, что этот подход может добавить полезные отличительные атрибуты в сочетании с другой информацией с устройства, но только если такие атрибуты, изменяемые OTA, могут быть тщательно отбракованы.

Carl
23 декабря 2012 в 05:48
2

Аналогичным образом Build.HOST определяется как «Строка, которая однозначно идентифицирует хост, на котором была ВСТРОЕНА сборка, в удобочитаемом формате». Вполне возможно, что для создания сборки для обновления OTA можно использовать разные машины BUILD.

Sinan Dizdarević
4 марта 2015 в 16:53
13

Очень и очень плохое решение. Проверено на двух Nexus 5 ... Возвращает одинаковые числа.

avatar
Tony Maro
21 марта 2011 в 20:46
21

Я добавлю одну вещь - у меня одна из тех уникальных ситуаций.

Использование:

deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);

Оказывается, даже несмотря на то, что мой планшет Viewsonic G Tablet сообщает DeviceID, который не равен NULL, каждый планшет G сообщает одно и то же число.

Делает интересной игру в "Pocket Empires", которая дает вам мгновенный доступ к чьей-либо учетной записи на основе "уникального" DeviceID.

В моем устройстве нет сотового радио.

Arnold Brown
4 февраля 2020 в 09:35
2

@ Treewallie это работает? Можно ли получить одинаковый идентификатор устройства из разных приложений?

avatar
rony l
6 марта 2011 в 15:28
23

Поле Serial было добавлено в класс Build на уровне API 9 (Android 2.3 - Gingerbread). В документации указано, что он представляет собой серийный номер оборудования. Таким образом, он должен быть уникальным, если он существует на устройстве.

Я не знаю, поддерживается ли он на самом деле (= не null) всеми устройствами с уровнем API> = 9.

m0skit0
15 апреля 2013 в 12:33
5

К сожалению, это «неизвестно».

avatar
Roman SL
25 января 2011 в 02:39
40

Следующий код возвращает серийный номер устройства с помощью скрытого Android API. Но этот код не работает на Samsung Galaxy Tab, потому что «ro.serialno» не установлен на этом устройстве.

String serial = null;

try {
    Class<?> c = Class.forName("android.os.SystemProperties");
    Method get = c.getMethod("get", String.class);
    serial = (String) get.invoke(c, "ro.serialno");
}
catch (Exception ignored) {

}
avatar
Seva Alekseyev
23 июня 2010 в 14:27
105

Также вы можете рассмотреть MAC-адрес адаптера Wi-Fi. Получено так:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

Требуется разрешение android.permission.ACCESS_WIFI_STATE в манифесте.

Сообщается, что он доступен, даже если Wi-Fi не подключен. Если бы Джо из приведенного выше ответа попробовал это на своих многочисленных устройствах, это было бы неплохо.

На некоторых устройствах он недоступен, когда Wi-Fi отключен.

ПРИМЕЧАНИЕ. Из Android 6.x он возвращает согласованный поддельный MAC-адрес: 02:00:00:00:00:00

ohhorob
1 ноября 2010 в 04:41
9

Это требуется android.permission.ACCESS_WIFI_STATE

Axarydax
22 декабря 2010 в 10:28
2

как насчет устройств без Wi-Fi?

Jack
29 августа 2011 в 21:27
5

Я знаю, что это старый вопрос, но это отличная идея. Я использовал идентификатор BT Mac в своем приложении, но только потому, что для его работы требуется BT. Покажите мне Android-устройство, которое стоит разработать, но без Wi-Fi.

chrisdowney
21 мая 2012 в 23:38
6

Я думаю, вы обнаружите, что он недоступен при отключенном Wi-Fi практически на всех устройствах Android. Отключение WiFi удаляет устройство на уровне ядра.

ocodo
4 сентября 2013 в 09:53
13

@Sanandrea - давайте посмотрим правде в глаза, на рутированном устройстве ВСЕ может быть подделано.

jiahao
1 июня 2014 в 13:55
3

Как сказано в блоге Google, MAC - не лучший вариант. «Возможно, можно получить Mac-адрес с оборудования Wi-Fi или Bluetooth устройства. Мы не рекомендуем использовать его в качестве уникального идентификатора. Начнем с того, что не все устройства имеют Wi-Fi. Кроме того, если Wi-Fi не включен, оборудование может не сообщать Mac-адрес ". android-developers.blogspot.com.es/2011/03/…

breez
22 декабря 2015 в 12:37
6

Доступ к MAC-адресу Wi-Fi заблокирован на Android M: coderhelper.com/questions/31329733/…

sarika kate
30 марта 2016 в 06:00
3

В частности, локальные MAC-адреса WiFi и Bluetooth больше не доступны. Метод getMacAddress () объекта aWifiInfo и метод BluetoothAdapter.getDefaultAdapter (). GetAddress () с этого момента будут возвращать 02: 00: 00: 00: 00: 00

Alberto M
31 мая 2016 в 11:03
2

некоторые устройства могут не иметь Wi-Fi (лично испытал)

Behrouz.M
10 июля 2016 в 09:14
8

Из Android 6.x он возвращает последовательный поддельный MAC-адрес: 02:00:00:00:00:00

Hari Shankar S
9 ноября 2020 в 09:24
0

android 10+ рандомизирует MAC-адрес, поэтому я не рекомендую это решение

avatar
Joe
17 мая 2010 в 22:12
1173

ОБНОВЛЕНИЕ : в последних версиях Android многие проблемы с ANDROID_ID были решены, и я считаю, что в таком подходе больше нет необходимости. Взгляните на ответ Энтони.

Полное раскрытие: в моем приложении изначально использовался подход, описанный ниже, но он больше не используется, и теперь мы используем подход, описанный в записи Android Developer Blog, на которую ссылается ответ emmby (а именно, создание и сохранение a UUID#randomUUID()).


На этот вопрос есть много ответов, большинство из которых сработает только «иногда», и, к сожалению, этого недостаточно.

На основании моих тестов устройств (всех телефонов, хотя бы один из которых не активирован):

  1. Все протестированные устройства вернули значение для TelephonyManager.getDeviceId()
  2. Все устройства GSM (все протестированы с SIM-картой) вернули значение для TelephonyManager.getSimSerialNumber()
  3. Все устройства CDMA вернули нулевое значение для getSimSerialNumber() (как и ожидалось)
  4. Все устройства с добавленной учетной записью Google вернули значение для ANDROID_ID
  5. Все устройства CDMA возвращали одно и то же значение (или производное одного и того же значения) для ANDROID_ID и TelephonyManager.getDeviceId() - , пока учетная запись Google была добавлена ​​во время настройки.
  6. У меня еще не было возможности протестировать устройства GSM без SIM-карты, устройство GSM без добавленной учетной записи Google или какое-либо из устройств в режиме полета.

Итак, если вам нужно что-то уникальное для самого устройства, TM.getDeviceId() должно быть . Очевидно, что некоторые пользователи более параноидальны, чем другие, поэтому может быть полезно хешировать 1 или несколько из этих идентификаторов, чтобы строка по-прежнему была фактически уникальной для устройства, но не определяла явным образом фактическое устройство пользователя. Например, используя String.hashCode() в сочетании с UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

может привести к примерно так: 00000000-54b3-e7c7-0000-000046bffd97

Меня это устраивает.

Как упоминает Ричард ниже, не забывайте, что вам нужно разрешение на чтение свойств TelephonyManager, поэтому добавьте это в свой манифест:

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

импортировать библиотеки

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
Seva Alekseyev
23 июня 2010 в 14:27
158

ID на основе телефонии не будет на планшетах, не так ли?

Joe
29 июня 2010 в 19:40
24

Поэтому я сказал, что большинство из них не будет работать постоянно :) Я еще не нашел ответа на этот вопрос, который был бы надежным для всех устройств, всех типов устройств и всех конфигураций оборудования. Вот почему этот вопрос здесь для начала. Совершенно очевидно, что здесь нет единого решения. У отдельных производителей устройств могут быть серийные номера устройств, но мы не можем их использовать, и это не является обязательным требованием. Таким образом, у нас остается то, что нам доступно.

liori
31 января 2011 в 20:12
3

Вы обновите свой ответ после дополнительных тестов? Было бы довольно интересно.

Richard
27 февраля 2011 в 22:28
33

Пример кода отлично работает. Не забудьте добавить <uses-permission android:name="android.permission.READ_PHONE_STATE" /> в файл манифеста. При хранении в базе данных возвращаемая строка имеет длину 36 символов.

emmby
7 апреля 2011 в 20:09
11

Имейте в виду, что это решение имеет огромные ограничения: android-developers.blogspot.com/2011/03/…

MusiGenesis
21 апреля 2011 в 16:19
2

К вашему сведению, TelephonyManager.getDeviceId () возвращает действительный уникальный идентификатор на моем Xoom, поэтому, похоже, это работает и для планшетов.

softarn
17 июля 2011 в 17:18
2

Этот ответ устарел и не должен использоваться. Не отслеживайте устройства, отслеживайте установки!

Joe
22 июля 2011 в 00:45
20

@softarn: Я считаю, что вы имеете в виду блог разработчиков Android, на который уже есть ссылка на emmby, в котором объясняется, что вы пытаетесь сказать , так что, возможно, вам следовало просто проголосовать за его комментарий. В любом случае, как упоминает Эмби в своем ответе, все еще есть проблемы даже с информацией в блоге. В вопросе запрашивается уникальный идентификатор УСТРОЙСТВА (не идентификатор установки), поэтому я не согласен с вашим утверждением. В блоге делается предположение, что то, что вы хотите , не обязательно для отслеживания устройства, тогда как вопрос требует именно этого. В противном случае я согласен с блогом.

Daniel Novak
4 августа 2011 в 07:10
6

Думаю, в этом методе есть один серьезный недостаток. Это зависит от информации о SIM-карте, пользователи иногда переключаются в режим полета = SIM-карта не подключена. В этом сценарии вам понадобится резервный механизм, возможно, для использования Android ID.

Joe
22 августа 2011 в 13:44
5

@ Даниэль Новак: справедливо. В моем случае это не было актуально, потому что идентификатор используется в обмене данными через API, поэтому режим полета = нет приложения :) Мы также разработали его таким образом, чтобы, например, если пользователь меняет SIM-карты, мы намеренно хотели "устройство". id "быть другим. Очевидно, что это относится не ко всем, поэтому спасибо, что указали на это.

Mathias
19 декабря 2011 в 21:54
5

Я немного удивлен, что никто еще не поднял это, но пример кода может быть действительно неудачным в некоторых обстоятельствах - он вернет другой идентификатор в зависимости от того, находится ли телефон, например, в режиме полета или нет, поскольку simSerialNumber будет нулевым, если сеть GSM устройства отключена. Если у вас есть приложение, которое использует уникальный идентификатор, но ему нужен только Интернет, а не обязательно сеть, может быть лучше убедиться, что код всегда возвращает один и тот же идентификатор независимо от текущего состояния сети телефона.

Behrouz.M
18 июня 2015 в 09:35
2

Я использую этот код 6 месяцев. Он не создает уникальный идентификатор. Я не рекомендую всем использовать этот код. В настоящее время я использую код из этого сообщения: coderhelper.com/a/17625641/365229

lavuy
30 июля 2015 в 06:48
3

Я настоятельно рекомендую вам не использовать этот код. В нем есть несколько критических ошибок: во-первых, нет гарантии, что и телефония, и Android ID существуют, и если они оба не существуют, ваши устройства будут сопоставлены только в соответствии с их моделью. Во-вторых, что более важно, , когда вы используете хэш-код Android ID, вы превращаете 64-битное строковое представление числа в 32-битное число, и, таким образом, вы теряете много уникальности.

abss
13 июля 2021 в 10:13
0

Идентификатор IMEI больше не может работать на Android 10 и выше.