Питання Є унікальний ідентифікатор пристрою Android?


У пристроїв Android є унікальний ідентифікатор, і якщо так, то який простий спосіб отримати доступ до нього за допомогою Java?


2312
2018-05-07 00:47


походження


Якщо ви використовуєте ANDROID_ID обов'язково прочитайте ця відповідь і ця помилка. - Dheeraj V.S.
Ось інформативна відповідь. - Eng.Fouad
Я знайшов ідеальний: stackoverflow.com/a/16929647/1318946 - Pratik Butani
Я виявив, що це дуже корисно, оскільки він обговорює всі доступні унікальні ідентифікатори та важить в кожному, і робить висновок про найкращі stackoverflow.com/q/27233518/5252270 - sathishkumar_kingmaker


Відповіді:


Settings.Secure#ANDROID_ID повертає ідентифікатор Android як унікальний для кожного користувача 64-розрядний шістнадцятковий рядок.

import android.provider.Settings.Secure;

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

1699
2018-05-07 00:49



Відомо, що інколи він нульовий, він задокументований як "може змінюватися після скидання заводських налаштувань". Використовуйте на свій страх і ризик, і його можна легко змінити на кореневому телефоні. - Seva Alekseyev
groups.google.com/group/android-developers/browse_thread/thread/... - Erdal
Я думаю, що ми повинні бути обережними щодо використання ANDROID_ID в хеш у першій відповіді, оскільки воно не може бути встановлено, коли пристрій вперше запускається, може бути встановлений пізніше або навіть може змінюватися в теорії, тому унікальний ідентифікатор може змінюватися
Майте на увазі, що з цим рішенням існують величезні обмеження: android-developers.blogspot.com/2011/03/... - emmby
ANDROID_ID більше не однозначно ідентифікує пристрій (згідно з 4.2): stackoverflow.com/a/13465373/150016 - Tom


UPDATE: З останніх версій Android багато проблем з ANDROID_ID були вирішені, і я вважаю, що цей підхід більше не потрібний. Будь ласка, подивіться на це Відповідь Ентоні.

Повне розкриття інформації: моя програма використовувала нижчий підхід спочатку, але більше не використовує цей підхід, і ми зараз використовуємо підхід, викладений в Блог розробника Android вхід, що відповідь еммбі посилання на (а саме, створення та збереження 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;

1056
2018-05-17 22:12



Ідентифікатор на базі телефонії там не буде на планшетних пристроях, чи не так? - Seva Alekseyev
Тому я вже сказав, що більшість з них не працюватимуть весь час :) Я ще не бачив відповіді на це питання, що є надійним для всіх пристроїв, всіх типів пристроїв та всіх апаратних конфігурацій. Ось чому це питання тут спочатку. Цілком очевидно, що для цього не існує кінцевого рішення. Виробники окремих пристроїв можуть мати серійні номери пристрою, але вони не піддаються нам використанню, і це не є вимогою. Таким чином, нам залишається те, що є для нас доступним. - Joe
Зразок коду працює чудово. Не забудьте додати <uses-permission android:name="android.permission.READ_PHONE_STATE" /> до файлу маніфесту. Якщо зберігати в базі даних, то повернений рядок становить 36 символів. - Richard
Майте на увазі, що з цим рішенням існують величезні обмеження: android-developers.blogspot.com/2011/03/... - emmby
@softarn: Я вважаю, що те, що ви маєте на увазі, - це блог розробника Android, в якому emmby вже зв'язаний, який пояснює, що ви намагаюся сказати, так що, мабуть, ви повинні просто спростили свій коментар. Так чи інакше, як зазначає Еммбі у своїй відповіді, існують проблеми навіть із інформацією про блог. Питання вимагає унікального ПРИСТРІЙ ідентифікатор (не ідентифікатор установки), тому я не згоден з вашим твердженням. Блог робить припущення, що ви хочете не обов'язково щоб відстежувати пристрій, тоді як запитання про це саме так. Я погоджуюсь з блогом іншим способом. - Joe


Останнє оновлення: 2.06.15


Прочитавши всі повідомлення про переповнення стака про створення унікального ідентифікатора, блог розробника Google і документації для Android, я вважаю, що "Pseudo ID" є найкращим варіантом.

Основний випуск: обладнання проти програмного забезпечення

Обладнання

  • Користувачі можуть змінювати своє обладнання, таблетку Android або телефон, тому унікальні ідентифікатори на базі апаратного забезпечення не є гарними ідеями Відслідковувати користувачів
  • Для ПЕРЕШКОДЖЕННЯ АПАРАТУ, це чудова ідея

Програмне забезпечення

  • Користувачі можуть витирати / змінювати ПЗУ, якщо вони мають коріння
  • Ви можете відстежувати користувачів на різних платформах (iOS, Android, Windows і Web).
  • Краще хочеться ПЕРЕЙТИ ІНДИВІДУАЛЬНИЙ ПОСИЛАННЯ з їх згода це просто зробити їх логіном (зробити це безперервним за допомогою 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 unique ID of build information (may overlap data - API < 9)

Завдяки @stansult для публікації всі наші варіанти (у цьому записі переповнення стека).

Список параметрів - причини чому / чому не використовувати їх:

  • Електронна пошта користувача - програмне забезпечення

  • Номер телефону користувача - програмне забезпечення

    • Користувачі можуть змінювати номери телефонів - Дуже малоймовірно
    • <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 - апаратне забезпечення (може бути нульовим, змінюватися після скидання заводських налаштувань, можна змінити на пристрої з коренем)

    • Оскільки це може бути "нульовим", ми можемо перевірити "нуль" та змінити його значення, але це означає, що він більше не буде унікальним.
    • Якщо у вас є користувач із пристроєм для скидання заводських налаштувань, це значення, можливо, змінилося або змінилося на встановленому пристрої, тому що ви можете відслідковувати встановлення користувача.
  • WLAN MAC Address - Обладнання (потреби 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)

    • Дуже можливо, може містити колізії - Див мой метод розміщений нижче!
    • Це дозволяє вам мати "майже унікальний" ідентифікатор від користувача, не приймаючи нічого, що є приватним. Ви можете створити власний анонімний ідентифікатор із інформації про пристрій.

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

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

API> = 9:

Якщо їхній пристрій Android має API 9 або пізніше, це гарантується унікальним через поле "Build.SERIAL".

Пам'ятай, ви технічно втрачаєте лише 0,5% користувачів які мають API <9. Таким чином, ви можете зосередити увагу на інших: це 99,5% користувачів!

API <9:

Якщо пристрій Android для користувача нижчий за API 9; ми сподіваємося, що вони не зробили фабричного скидання, і їх "Secure.ANDROID_ID" буде збережено або не "нульовим". (побачити http://developer.android.com/about/dashboards/index.html)

Якщо все інше не вдається:

Якщо все інше не вдається, якщо користувач має нижчий, ніж API 9 (нижче, ніж Gingerbread), він скидає їхній пристрій або «Secure.ANDROID_ID» повертає «нуль», тоді просто ідентифікатор повертається виключно на основі інформації про пристрій 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://stackoverflow.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://stackoverflow.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();
}

Новий (для додатків з оголошеннями та службами 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   у розділі "Настройки.Захист"), коли доступні служби Google Play. Справи   де служби Google Play недоступні, позначаються символи a   GooglePlayServicesNotAvailableException викидається   getAdvertisingIdInfo ().

Застереження. Користувачі можуть скинути:

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

Я намагався навести посилання на кожне посилання, яке я отримав від. Якщо вам не вистачає і потрібно включити його, будь ласка, коментар!

Служба Google Play Services InstanceID

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


365
2017-07-12 23:58



Але не буде це Build зміни класу після оновлення ОС? Особливо, якщо API оновлено? Якщо так, то як ви гарантуєте, що це унікальне? (Говорячи про метод, який ви написали) - LuckyMe
Я використовував ваш метод у моєму додатку для надсилання коментарів. У мене погані новини. На жаль, PsuedoID не є унікальним повністю. мій сервер записав більше 100 для 5 ідентифікаторів і більше 30 для майже 30 ідентифікаторів. найбільш часто повторювані ідентифікатори - 'ffffffff-fc8f-6093-ffff-ffffd8' (159 записів) і 'ffffffff-fe99-b334-ffff-ffffef' (154 разів). також на основі часу та коментарів очевидно, що існують різні народи. загальна кількість записів до цих пір складає 10 000. будь ласка, дайте мені знати, чому це сталося. танки - hojjat reyhane
Я написав це 1,5 + років тому. Я не знаю, чому це не є унікальним для вас. Ви можете спробувати рекламний ідентифікатор. Якщо ні, ви можете запропонувати власне рішення. - Jared Burrows
Сорта .. Я дуже вдячний, якщо ви пройдете через це питання і подумайте про це - Durai Amuthan.H
@ user1587329 Дякую. Я намагаюся його оновлювати для всіх. Це питання складне, коли справа доходить до апаратного забезпечення проти програмного забезпечення та крос-платформи. - Jared Burrows


Як згадує Дейв Вебб, Блог розробника Android містить статтю що охоплює це. Їх найкращим рішенням є відстеження встановлень додатків, а не пристроїв, і це буде добре працювати для більшості випадків використання. Поле блогу покаже вам потрібний код для виконання цієї роботи, і я рекомендую перевірити його.

Однак публікація блогу продовжує обговорювати рішення, якщо вам потрібен ідентифікатор пристрою, а не ідентифікатор встановлення додатка. Я спілкувався з когось у Google, щоб отримати додаткові роз'яснення щодо кількох елементів у випадку, якщо вам це потрібно. Ось що я дізнався про ідентифікатори пристроїв, які НЕ згадані в вищезгаданому блозі:

  • ANDROID_ID - це найкращий ідентифікатор пристрою. Android-версія ANDROID_ID абсолютно надійна на версіях Android <= 2.1 або> = 2.3. Тільки на 2.2 виникають проблеми, згадані в повідомленні.
  • Деякі пристрої кількох виробників впливають на помилку ANDROID_ID в 2.2.
  • Наскільки я зміг визначити, у всіх зачеплених пристроях є той самий ANDROID_ID, який 9774d56d682e549c. Який же такий ідентифікатор пристрою, який повідомляється емулятором, btw.
  • Google вважає, що OEM вирішили цю проблему для багатьох або більшості своїх пристроїв, але я зміг перевірити, що принаймні з початку квітня, все ще досить легко знайти пристрої з розбитими 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;
    }
}

314
2018-04-11 19:06



Чи не повинні ви хэшировать різні ідентифікатори, щоб вони були однаковими розмірами? Окрім того, вам слід перемістити ідентифікатор пристрою, щоб не випадково виставляти приватну інформацію. - Steve Pomeroy
Добре, Стів. Я оновив код, щоб завжди повертати UUID. Це гарантує, що а) створені ідентифікатори завжди однакового розміру, а б) ідентифікатори Android та пристроїв хешувати перед тим, як вони будуть повернуті, щоб уникнути випадкового виявлення особистої інформації. Я також оновив опис, щоб відзначити, що ідентифікатор пристрою зберігатиметься після скидання заводських налаштувань, і це може бути небажаним для деяких користувачів. - emmby
Я вірю, що ви неправильні; найкращим рішенням є відстеження установок, а не ідентифікаторів пристрою. Ваш код суттєво довший і складніший, ніж у публікації блогу, і для мене це не очевидно, що він додає будь-яку цінність. - Tim Bray
Хороший момент, я оновив коментар, щоб настійно рекомендував користувачам використовувати ідентифікатори встановлення додатків, а не ідентифікатори пристрою. Однак, я думаю, що це рішення залишається цінним для людей, яким потрібен пристрій, а не ідентифікатор інсталяції. - emmby
ANDROID_ID може змінюватися після скидання заводських налаштувань, тому він також не може ідентифікувати пристрої - Samuel


Ось код, який Reto Meier використовує в 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;
}

Якщо ви зв'язали це зі стратегією резервного копіювання, щоб відправити переваги в хмару (також описано в рето говорити, вам слід мати ідентифікатор, який зв'язується з користувачем, і прикріплюється після того, як пристрій було знищено або навіть замінено. Я планую використовувати це в аналізі, що йде вперед (іншими словами, я ще цього не зробив :).


165
2017-10-28 13:19



Я використовував метод @Lenn Dolling з поточним часом, доданим для унікального ідентифікатора. Але це здається більш простим і надійним способом. Дякую Рето Мейер та Ентоні Нолан - Gökhan Barış Aker
Це чудово, але як щодо кореневих пристроїв? Вони можуть отримати доступ до цього і змінити UID на інший легко. - tasomaniac
Відмінний варіант, якщо вам не потрібно зберігати унікальний ідентифікатор після видалення та перевстановлення (наприклад, рекламна подія / гра, де ви отримуєте три шанси на виграш, період). - Kyle Clegg
Презентація "Мейер" спирається на використання диспетчера резервних копій Android, що, в свою чергу, залежить від того, чи вибрано користувач, щоб включити цю функцію. Це нормально для налаштувань користувача додатків (використання Meier), тому що якщо користувач не вибрав цей параметр, вона просто не отримає резервні копії. Проте оригінальне питання полягає в тому, щоб створити унікальний ідентифікатор для пристрій, і цей ідентифікатор створюється для кожного додатка, і навіть не для кожної інсталяції, не кажучи вже про кожен пристрій, і оскільки він покладається на те, що користувач вибирає опцію резервного копіювання, його використання за винятком користувацьких уподобань (наприклад, для випробувань, обмежених у часі) обмежено. - Carl
Це не спрацює при видаленні чи очищенні даних. - John Shelley


Також ви можете розглянути 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


98
2018-06-23 14:27



Це потрібно android.permission.ACCESS_WIFI_STATE - ohhorob
Вони існують? Я вважаю за краще передбачити бездротовий пристрій (планшет AKA) ... - Seva Alekseyev
Я знаю це питання старе, але це чудова ідея. Я використав ідентифікатор BT Mac в моєму додатку, але тільки тому, що він вимагає від BT функціонування. Покажіть мені Android-пристрій, який варто розробити для цього, не має WiFi. - Jack
Я думаю, ви виявите, що це недоступне, коли Wi-Fi вимкнено, майже на всіх пристроях Android. Вимкнення Wi-Fi видаляє пристрій на рівні ядра. - chrisdowney
@Sanandrea - давайте розглянемо це, на кореневому пристрої все може бути підробленим. - ocodo


Там досить корисна інформація тут.

Він охоплює п'ять різних типів ідентифікаторів:

  1. IMEI (лише для пристроїв Android із телефоном, потребами) android.permission.READ_PHONE_STATE)
  2. Псевдо-унікальний ідентифікатор (для всіх пристроїв Android)
  3. Ідентифікатор Android (може бути нульовим, може змінюватися при скиданнях заводських налаштувань, можна змінити на телефоні з підключенням)
  4. WLAN MAC Address рядок (потреби android.permission.ACCESS_WIFI_STATE)
  5. BT MAC Address рядок (пристрої з Bluetooth, потреби android.permission.BLUETOOTH)

78
2018-02-08 02:16



Важливе місце, що залишилося (тут і в статті): ви не можете отримати WLAN або BT MAC, якщо вони не ввімкнені! Інакше я думаю, WLAN MAC буде ідеальним ідентифікатором. У вас немає ніякої гарантії, що користувач ніколи не вмикає свій Wi-Fi, і я насправді не вважаю, що це "відповідне", щоб включити його на себе. - Tom
@Том ви помиляєтесь Ви все ще можете читати WLAN або BT MAC, навіть коли вони вимкнені. Однак немає гарантій, що пристрій має доступні модулі WLAN або BT. - Marqs
Найбільш помітно, що локальні WiFi та MAC-адреси Bluetooth більше не доступні. Метод getMacAddress () об'єкта aWifiInfo та BluetoothAdapter.getDefaultAdapter (). Метод getAddress () повернеться від 02: 00: 00: 00: 00: 00 відтепер - sarika kate
@sarikakate Це правда тільки в 6.0 Marshmallow і вище ... Він як і раніше працює, як очікується, внизу 6.0 Зефір. - Smeet
@ Зустрічайте, так, ви маєте рацію. Я забув згадати, що його робота нижче 6.0 - sarika kate


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


43
2018-04-06 07:36



І ключовим моментом цього аргументу є те, що, якщо ви намагаєтесь отримати унікальний ідентифікатор з апаратного забезпечення, ви, напевно, зробите помилку. - Tim Bray
І якщо ви дозволите скинути налаштування блокування пристрою за допомогою заводських налаштувань, ваша пробна версія настільки ж провальна. - Seva Alekseyev


В Google I / O Reto Meier випустив надійну відповідь на те, як підійти до цього, який повинен відповідати більшості розробників, щоб відстежувати користувачів по всій установці. Ентоні Нолан показує напрямок у своєму відповіді, але я думав, що я виписав повний підхід, щоб інші могли легко зрозуміти, як це зробити (мені довелося спокійно з'ясувати деталі).

Цей підхід дасть вам анонімний, безпечний ідентифікатор користувача, який буде стійким для користувача на різних пристроях (на основі основного облікового запису Google) та між встановленнями. Основний підхід полягає в тому, щоб створити випадковий ідентифікатор користувача та зберегти його в спільних налаштуваннях додатків. Потім ви використовуєте резервний агент Google для зберігання спільних налаштувань, пов'язаних із обліковим записом Google у хмарі.

Давайте пройдемо повний підхід. По-перше, нам потрібно створити резервну копію для наших Спільнихпослуг, використовуючи службу резервного копіювання Android. Почніть з реєстрації вашої програми через 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 тепер буде стійким у всіх установках, навіть якщо користувач переміщує пристрій.

Більш детальну інформацію про цей підхід див Розмова рето.

І для повної інформації про те, як реалізувати резервний агент див Резервне копіювання даних. Я особливо рекомендую розділ внизу на тестування, оскільки резервне копіювання не відбувається миттєво, і тому перевірити, чи потрібно змусити резервну копію.


36
2017-12-22 08:13



Чи не призведе це до кількох пристроїв з тим самим ідентифікатором, коли користувач має кілька пристроїв? Наприклад, планшет і телефон. - Tosa
Для цього потрібна мінімальна ціль 8. - halxinate
Чи буде це найкращим способом створення корисної перевірки під час здійснення покупок через додаток? З прикладу коду прикладу користування через додаток: "Таким чином, хороший корисне навантаження для розробника має такі характеристики: 1. Якщо два покупця купують елемент між різними користувачами, між ними корисне навантаження відрізняється таким чином, що покупка одного користувача не може бути відтворена іншому користувачеві. 2. Потрібна інформація повинна бути такою, щоб її можна було підтвердити, навіть якщо додаток не ініціював потік покупки (щоб товари, придбані користувачем на одному пристрої, працювали на інших пристроях, що належать користувачеві). " - TouchBoarder
@Тоса у мене було те саме питання. Але чи не могли б ми використати цю саму техніку ще раз, щоб створити ідентифікатори віртуального пристрою, а не просто так, щоб це було так само? Ідентифікатор пристрою не зберігатиметься після стирання чи перевстановлення, але якщо ми маємо постійний ідентифікатор користувача, можливо, нам знадобиться значно менше ідентифікатора пристрою. - jwehrle
Користувачі з кореневими правами можуть легко редагувати спільні налаштування - Redman