Czy istnieje unikalny identyfikator urządzenia z Androidem?

Odpowiedzi:

2024

Settings.Secure#ANDROID_IDzwraca identyfikator Androida jako unikalny dla każdego 64-bitowego ciągu szesnastkowego użytkownika.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 
Anthony Forloney
źródło
476
Czasami wiadomo, że ma wartość zero, co jest udokumentowane jako „może ulec zmianie po przywróceniu ustawień fabrycznych”. Używaj na własne ryzyko i można go łatwo zmienić na zrootowanym telefonie.
Seva Alekseyev
18
Myślę, że musimy zachować ostrożność przy używaniu ANDROID_ID w haszu w pierwszej odpowiedzi, ponieważ może nie być ustawiony przy pierwszym uruchomieniu aplikacji, może być ustawiony później, a nawet może ulec zmianie w teorii, dlatego unikalny identyfikator może się zmienić
46
Należy pamiętać, że są ogromne ograniczenia z tego rozwiązania: android-developers.blogspot.com/2011/03/...
emmby
35
ANDROID_ID nie identyfikuje już jednoznacznie urządzenia (od 4.2): stackoverflow.com/a/13465373/150016
Tom
1144

AKTUALIZACJA : Od najnowszych wersji Androida wiele problemów ANDROID_IDzostało rozwiązanych i uważam, że to podejście nie jest już konieczne. Proszę spojrzeć na odpowiedź Anthony'ego .

Pełne ujawnienie: moja aplikacja początkowo stosowała poniższe podejście, ale już nie stosuje tego podejścia, a teraz korzystamy z podejścia opisanego we wpisie na blogu programisty Androida, do którego prowadzi link odpowiedzi emmby (a mianowicie, generowanie i zapisywanie a UUID#randomUUID()).


Istnieje wiele odpowiedzi na to pytanie, z których większość będzie działać tylko „przez pewien czas”, i niestety to nie wystarczy.

Na podstawie moich testów urządzeń (wszystkich telefonów, z których przynajmniej jeden nie jest aktywowany):

  1. Wszystkie testowane urządzenia zwróciły wartość dla TelephonyManager.getDeviceId()
  2. Wszystkie urządzenia GSM (wszystkie przetestowane na karcie SIM) zwróciły wartość dla TelephonyManager.getSimSerialNumber()
  3. Wszystkie urządzenia CDMA zwróciły wartość NULL dla getSimSerialNumber()(zgodnie z oczekiwaniami)
  4. Wszystkie urządzenia z dodanym kontem Google zwróciły wartość dla ANDROID_ID
  5. Wszystkie urządzenia CDMA zwróciły tę samą wartość (lub wyprowadzenie tej samej wartości) zarówno ANDROID_IDi TelephonyManager.getDeviceId()- o ile konto Google zostało dodane podczas instalacji.
  6. Nie miałem jeszcze okazji przetestować urządzeń GSM bez karty SIM, urządzenia GSM bez dodanego konta Google ani żadnego z urządzeń w trybie samolotowym.

Więc jeśli chcesz czegoś wyjątkowego dla samego urządzenia, TM.getDeviceId() powinno wystarczyć. Oczywiście niektórzy użytkownicy są bardziej paranoiczni niż inni, więc może być użyteczne zaszyfrowanie 1 lub więcej takich identyfikatorów, tak aby ciąg znaków był praktycznie unikalny dla urządzenia, ale nie identyfikował wyraźnie rzeczywistego urządzenia użytkownika. Na przykład przy użyciu String.hashCode()w połączeniu z 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();

może spowodować coś takiego jak: 00000000-54b3-e7c7-0000-000046bffd97

Działa dla mnie wystarczająco dobrze.

Jak Richard wspomina poniżej, nie zapominaj, że potrzebujesz pozwolenia na odczytanie TelephonyManagerwłaściwości, więc dodaj to do swojego manifestu:

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

importuj biblioteki lib

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
Joe
źródło
151
Identyfikatora opartego na telefonii nie będzie na tablecie, prawda?
Seva Alekseyev
22
Dlatego powiedziałem, że większość nie będzie działać cały czas :) Jeszcze nie widziałem odpowiedzi na to pytanie, która byłaby wiarygodna dla wszystkich urządzeń, wszystkich typów urządzeń i wszystkich konfiguracji sprzętowych. Dlatego na początek jest to pytanie. Jest całkiem jasne, że nie ma rozwiązania tego typu. Poszczególni producenci urządzeń mogą mieć numery seryjne urządzeń, ale nie są one nam ujawniane i nie jest to wymagane. Zatem pozostaje nam to, co jest dla nas dostępne.
Joe
31
Próbka kodu działa świetnie. Pamiętaj, aby dodać <uses-permission android:name="android.permission.READ_PHONE_STATE" />do pliku manifestu. W przypadku przechowywania w bazie danych zwracany ciąg ma 36 znaków.
Richard
10
Pamiętaj, że z tym rozwiązaniem wiążą
emmby,
18
@softarn: Wydaje mi się, że to, o czym mówisz, to blog programisty Androida, z którym emmby już się łączy, co wyjaśnia, co próbujesz powiedzieć, więc być może powinieneś po prostu wyrazić opinię na jego komentarz. Tak czy inaczej, jak wspomina Emmby w swojej odpowiedzi, nadal występują problemy nawet z informacjami na blogu. Pytanie wymaga unikalnego identyfikatora URZĄDZENIA (nie identyfikatora instalacji), więc nie zgadzam się z tym stwierdzeniem. Blog zakłada, że ​​to, czego chcesz, niekoniecznie musi śledzić urządzenie, podczas gdy pytanie dotyczy właśnie tego. W przeciwnym razie zgadzam się z blogiem.
Joe
438

Ostatnia aktualizacja: 6/2/15


Po przeczytaniu każdego wpisu przepełnienia stosu dotyczącego tworzenia unikalnego identyfikatora, blogu programisty Google i dokumentacji Androida, wydaje mi się, że „Pseudo-identyfikator” jest najlepszą możliwą opcją.

Główny problem: sprzęt kontra oprogramowanie

Sprzęt komputerowy

  • Użytkownicy mogą zmienić swój sprzęt, tablet lub telefon z Androidem, więc unikalne identyfikatory oparte na sprzęcie nie są dobrym pomysłem dla ŚLEDZENIA UŻYTKOWNIKÓW
  • W przypadku ŚLEDZENIA SPRZĘTU jest to świetny pomysł

Oprogramowanie

  • Użytkownicy mogą wyczyścić / zmienić pamięć ROM, jeśli są zrootowani
  • Możesz śledzić użytkowników na różnych platformach (iOS, Android, Windows i Internet)
  • Najlepszym sposobem na ŚLEDZENIE INDYWIDUALNEGO UŻYTKOWNIKA za ich zgodą jest po prostu zalogowanie się (bezproblemowe korzystanie z OAuth)

Ogólny podział na Androida

- Gwarancja wyjątkowości (w tym zrootowanych urządzeń) dla API> = 9/10 (99,5% urządzeń z Androidem)

- Bez dodatkowych uprawnień

Kod Psuedo:

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)

Dzięki @stansult za opublikowanie wszystkich naszych opcji (w tym pytaniu Przepełnienie stosu).

Lista opcji - powody, dla których / dlaczego ich nie używać:

  • Adres e-mail użytkownika - oprogramowanie

    • Użytkownik może zmienić adres e-mail - BARDZO mało prawdopodobne
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />lub
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" />( Jak uzyskać główny adres e-mail urządzenia z systemem Android )
  • Numer telefonu użytkownika - oprogramowanie

    • Użytkownicy mogą zmieniać numery telefonów - BARDZO mało prawdopodobne
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - sprzęt (tylko telefony, potrzebne android.permission.READ_PHONE_STATE)

    • Większość użytkowników nie znosi faktu, że w zezwoleniu jest napisane „Połączenia telefoniczne”. Niektórzy użytkownicy oceniają źle, ponieważ uważają, że po prostu kradniesz ich dane osobowe, gdy naprawdę chcesz tylko śledzić instalacje urządzeń. Oczywiste jest, że gromadzisz dane.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - sprzęt (może być zerowy, może ulec zmianie po przywróceniu ustawień fabrycznych, może być zmieniony na zrootowanym urządzeniu)

    • Ponieważ może mieć wartość „null”, możemy sprawdzić wartość „null” i zmienić jej wartość, ale oznacza to, że nie będzie już unikalna.
    • Jeśli masz użytkownika z urządzeniem przywracającym ustawienia fabryczne, wartość mogła zostać zmieniona lub zmieniona na urządzeniu zrootowanym, więc w przypadku śledzenia instalacji użytkownika mogą pojawić się zduplikowane wpisy.
  • Adres MAC sieci WLAN - sprzęt (wymaga android.permission.ACCESS_WIFI_STATE)

    • To może być druga najlepsza opcja, ale nadal gromadzisz i przechowujesz unikalny identyfikator, który pochodzi bezpośrednio od użytkownika. To oczywiste, że zbierasz dane.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Adres MAC Bluetooth - sprzęt (urządzenia z Bluetooth, wymagają android.permission.BLUETOOTH)

    • Większość aplikacji na rynku nie korzysta z Bluetooth, więc jeśli Twoja aplikacja nie korzysta z Bluetooth, a ty to włączasz, użytkownik może stać się podejrzany.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-unikalny identyfikator - oprogramowanie (dla wszystkich urządzeń z Androidem)

    • Bardzo możliwe, może zawierać kolizje - Zobacz moją metodę opublikowaną poniżej!
    • Pozwala to na uzyskanie „prawie unikalnego” identyfikatora od użytkownika, bez zajmowania czegokolwiek, co jest prywatne. Możesz utworzyć własny anonimowy identyfikator na podstawie informacji o urządzeniu.

Wiem, że nie ma żadnego „idealnego” sposobu uzyskania unikalnego identyfikatora bez użycia uprawnień; Czasami jednak naprawdę musimy tylko śledzić instalację urządzenia. Jeśli chodzi o tworzenie unikalnego identyfikatora, możemy stworzyć „pseudo unikalny identyfikator” oparty wyłącznie na informacjach, które daje nam interfejs API Androida, bez korzystania z dodatkowych uprawnień. W ten sposób możemy okazywać szacunek użytkownikom i starać się oferować dobre wrażenia.

Dzięki pseudo-unikalnemu identyfikatorowi tak naprawdę napotykasz tylko na fakt, że mogą istnieć duplikaty na podstawie faktu, że istnieją podobne urządzenia. Możesz dostosować połączoną metodę, aby była bardziej unikalna; Jednak niektórzy programiści muszą śledzić instalacje urządzeń, a to zrobi sztuczkę lub wydajność w oparciu o podobne urządzenia.

API> = 9:

Jeśli ich urządzeniem z Androidem jest API 9 lub nowszy, gwarantuje to, że będzie unikalny ze względu na pole „Build.SERIAL”.

PAMIĘTAJ , że technicznie brakuje Ci tylko około 0,5% użytkowników, którzy mają API <9 . Możesz więc skupić się na reszcie: to 99,5% użytkowników!

API <9:

Jeśli urządzenie z Androidem użytkownika jest niższe niż API 9; mam nadzieję, że nie przywrócono ustawień fabrycznych, a ich „Secure.ANDROID_ID” zostanie zachowany lub nie będzie „zerowy”. (patrz http://developer.android.com/about/dashboards/index.html )

Jeśli wszystko inne zawiedzie:

Jeśli wszystko inne zawiedzie, jeśli użytkownik ma niższą niż API 9 (niższą niż Gingerbread), zresetował swoje urządzenie lub „Secure.ANDROID_ID” zwraca „null”, wówczas zwrócony identyfikator będzie wyłącznie oparty na informacjach o urządzeniu z Androidem. To tutaj mogą zdarzyć się kolizje.

Zmiany:

  • Usunięty „Android.SECURE_ID” z powodu resetów fabrycznych może spowodować zmianę wartości
  • Edytowałem kod do zmiany w interfejsie API
  • Zmieniono pseudo

Proszę spojrzeć na poniższą metodę:

/**
 * 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();
}

Nowość (dla aplikacji z reklamami I usługami Google Play):

Z konsoli programisty Google Play:

Począwszy od 1 sierpnia 2014 r., Zasady programu dla programistów Google Play wymagają, aby wszystkie nowe aplikacje i aktualizacje aplikacji używały identyfikatora reklamowego zamiast innych trwałych identyfikatorów do jakichkolwiek celów reklamowych. Ucz się więcej

Realizacja :

Pozwolenie:

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

Kod:

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();
}

Źródło / Dokumenty:

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

Ważny:

Zakłada się, że identyfikator reklamowy całkowicie zastąpi dotychczasowe użycie innych identyfikatorów do celów reklamowych (takich jak użycie ANDROID_ID w Settings.Secure), gdy Usługi Google Play są dostępne. Przypadki, w których Usługi Google Play są niedostępne, są wskazywane przez wyjątek GooglePlayServicesNotAvailableException przez getAdvertisingIdInfo ().

Ostrzeżenie: użytkownicy mogą zresetować:

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

Próbowałem odwoływać się do każdego linku, z którego wziąłem informacje. Jeśli brakuje i trzeba je uwzględnić, prosimy o komentarz!

Identyfikator wystąpienia Google Player Services

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

Jared Burrows
źródło
Ale czy Buildklasa nie zmieni się po aktualizacji systemu operacyjnego? Zwłaszcza jeśli interfejs API został zaktualizowany? Jeśli tak, w jaki sposób gwarantujesz, że jest to wyjątkowe? (Mówiąc o metodzie, którą napisałeś)
LuckyMe
2
Użyłem twojej metody w mojej aplikacji do wysyłania komentarzy. Mam złe wieści. niestety PsuedoID nie jest całkowicie wyjątkowy. mój serwer zarejestrował ponad 100 dla 5 ID i więcej niż 30 dla prawie 30 ID. najczęściej powtarzającymi się identyfikatorami są „ffffffff-fc8f-6093-ffff-ffffd8” (rekord 159) i „ffffffff-fe99-b334-ffff-ffffef” (czas 154). również na podstawie czasu i komentarzy oczywiste jest, że istnieją różne ludy. łączna liczba rekordów do tej pory wynosi 10 000. daj mi znać, dlaczego tak się stało. czołgi.
hojjat reyhane
1
Napisałem to ponad 1,5 roku temu. Nie jestem pewien, dlaczego nie jest dla ciebie wyjątkowy. Możesz wypróbować identyfikator reklamowy. Jeśli nie, możesz wymyślić własne rozwiązanie.
Jared Burrows,
2
tak naprawdę byłbym wdzięczny, gdybyś przejrzał pytanie i zastanowił się nad tym
Durai Amuthan.H
1
@ user1587329 Dziękujemy. Staram się na bieżąco informować wszystkich. To pytanie jest trudne, jeśli chodzi o sprzęt vs oprogramowanie i platformę.
Jared Burrows
340

Jak wspomina Dave Webb, blog programisty Androida zawiera artykuł na ten temat. Preferowanym przez nich rozwiązaniem jest śledzenie instalacji aplikacji, a nie urządzeń, i będzie to działać dobrze w większości przypadków użycia. Wpis na blogu zawiera kod niezbędny do tego, aby działał, i polecam go sprawdzić.

Jednak blog nadal omawia rozwiązania, jeśli potrzebujesz identyfikatora urządzenia zamiast identyfikatora instalacji aplikacji. Rozmawiałem z kimś z Google, aby uzyskać dodatkowe wyjaśnienia dotyczące kilku elementów na wypadek, gdybyś musiał to zrobić. Oto, co odkryłem na temat identyfikatorów urządzeń, o których NIE wspomniano w wyżej wspomnianym wpisie na blogu:

  • ANDROID_ID jest preferowanym identyfikatorem urządzenia. ANDROID_ID jest całkowicie niezawodny w wersjach Androida <= 2.1 lub> = 2.3. Tylko 2.2 ma problemy wymienione w poście.
  • Błąd ANDROID_ID w wersji 2.2 dotyczy kilku urządzeń różnych producentów.
  • O ile udało mi się ustalić, wszystkie urządzenia, których dotyczy problem, mają ten sam ANDROID_ID , czyli 9774d56d682e549c . Który jest również tym samym identyfikatorem urządzenia zgłaszanym przez emulator, btw.
  • Google uważa, że ​​producenci OEM załatali ten problem dla wielu lub większości swoich urządzeń, ale mogłem zweryfikować, że przynajmniej na początku kwietnia 2011 r. Nadal dość łatwo jest znaleźć urządzenia, które mają uszkodzony ANDROID_ID.

Opierając się na zaleceniach Google, zaimplementowałem klasę, która wygeneruje unikalny UUID dla każdego urządzenia, używając ANDROID_ID w razie potrzeby jako seed, w razie potrzeby odwołując się do TelephonyManager.getDeviceId (), a jeśli to się nie powiedzie, uciekając się do losowo generowanego unikalnego UUID jest to powtarzane po ponownym uruchomieniu aplikacji (ale nie ponownej instalacji aplikacji).

Należy pamiętać, że w przypadku urządzeń, które muszą mieć awarię identyfikatora urządzenia, unikatowy identyfikator BĘDZIE występował podczas resetowania do ustawień fabrycznych. Jest to coś, o czym należy pamiętać. Jeśli musisz upewnić się, że przywrócenie ustawień fabrycznych spowoduje zresetowanie unikalnego identyfikatora, możesz rozważyć powrót bezpośrednio do losowego identyfikatora UUID zamiast identyfikatora urządzenia.

Ponownie ten kod dotyczy identyfikatora urządzenia, a nie identyfikatora instalacji aplikacji. W większości sytuacji prawdopodobnie szukasz identyfikatora instalacji aplikacji. Ale jeśli potrzebujesz identyfikatora urządzenia, prawdopodobnie poniższy kod będzie dla Ciebie odpowiedni.

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;
    }
}
emmby
źródło
6
Czy nie powinieneś mieszać różnych identyfikatorów, aby wszystkie miały ten sam rozmiar? Ponadto należy zaszyfrować identyfikator urządzenia, aby przypadkowo nie ujawnić prywatnych informacji.
Steve Pomeroy
2
Dobre punkty, Steve. Zaktualizowałem kod, aby zawsze zwracał UUID. Zapewnia to, że a) wygenerowane identyfikatory są zawsze tego samego rozmiaru, oraz b) identyfikatory Androida i urządzeń są szyfrowane przed zwróceniem, aby uniknąć przypadkowego ujawnienia danych osobowych. Zaktualizowałem także opis, aby zauważyć, że identyfikator urządzenia będzie się utrzymywał w trakcie resetowania do ustawień fabrycznych i że może to nie być pożądane dla niektórych użytkowników.
emmby
1
Wierzę, że się mylisz; preferowanym rozwiązaniem jest śledzenie instalacji, a nie identyfikatorów urządzeń. Twój kod jest znacznie dłuższy i bardziej złożony niż w poście na blogu i nie jest dla mnie oczywiste, że wnosi on jakąkolwiek wartość.
Tim Bray,
7
Dobrze, zaktualizowałem komentarz, aby zdecydowanie sugerować użytkownikom używanie identyfikatorów instalacji aplikacji zamiast identyfikatorów urządzeń. Myślę jednak, że to rozwiązanie jest nadal cenne dla osób, które potrzebują urządzenia, a nie identyfikatora instalacji.
emmby
8
ANDROID_ID może zmienić się po przywróceniu ustawień fabrycznych, więc nie może również zidentyfikować urządzeń
Samuel
180

Oto kod, którego Reto Meier użył w tegorocznej prezentacji Google I / O, aby uzyskać unikalny identyfikator dla użytkownika:

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;
}

Jeśli para to z kopii zapasowej strategii wysyłania preferencje w chmurze (także opisane w Reto w rozmowie , trzeba mieć identyfikator, który więzi z użytkownikiem i kije wokół po urządzenie zostało wymazane, a nawet wymienić. Mam zamiar to wykorzystać w analityce w przyszłości (innymi słowy, jeszcze tego nie zrobiłem :).

Anthony Nolan
źródło
Użyłem metody @ Lenn Dolling z bieżącym czasem dołączonym do unikalnego identyfikatora. Ale wydaje się, że jest to prostszy i bardziej niezawodny sposób. Dzięki Reto Meier i Antony Nolan
Gökhan Barış Aker
To świetnie, ale co z zrootowanymi urządzeniami? Mogą uzyskać do nich dostęp i łatwo zmienić identyfikator użytkownika na inny.
tasomaniac
3
Świetna opcja, jeśli nie potrzebujesz unikalnego identyfikatora, aby zachować się po odinstalowaniu i ponownej instalacji (np. Impreza promocyjna / gra, w której masz trzy szanse na wygraną, kropka).
Kyle Clegg
2
Prezentacja Meiera opiera się na użyciu Android Backup Manager, który z kolei zależy od tego, czy użytkownik zdecyduje się włączyć tę funkcję. Jest to w porządku dla preferencji użytkownika aplikacji (użycie Meiera), ponieważ jeśli użytkownik nie wybrał tej opcji, po prostu nie otrzyma kopii zapasowej. Jednak pierwotne pytanie dotyczy generowania unikalnego identyfikatora dla urządzenia , a ten identyfikator jest generowany dla aplikacji, a nawet dla instalacji, a co dopiero dla każdego urządzenia, a ponieważ zależy on od wybrania przez użytkownika opcji kopii zapasowej, jego zastosowania wykraczają poza użytkownika preferencje (np. w przypadku ograniczonego czasowo okresu próbnego) są ograniczone.
Carl
12
To nie zadziała w przypadku odinstalowywania lub czyszczenia danych.
John Shelley,
106

Możesz również wziąć pod uwagę adres MAC karty Wi-Fi. Pobrano w ten sposób:

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

Wymaga zgody android.permission.ACCESS_WIFI_STATEw manifeście.

Zgłoszone jako dostępne, nawet gdy Wi-Fi nie jest podłączone. Jeśli Joe z powyższej odpowiedzi wypróbuje ten na wielu swoich urządzeniach, byłoby miło.

Na niektórych urządzeniach nie jest dostępny, gdy Wi-Fi jest wyłączone.

UWAGA: Z systemu Android 6.x zwraca spójny fałszywy adres mac:02:00:00:00:00:00

Seva Alekseyev
źródło
8
To wymagałoandroid.permission.ACCESS_WIFI_STATE
ohhorob
5
Myślę, że okaże się, że jest niedostępny, gdy Wi-Fi jest wyłączone, na prawie wszystkich urządzeniach z Androidem. Wyłączenie Wi-Fi usuwa urządzenie na poziomie jądra.
chrisdowney
12
@ Sanandrea - spójrzmy prawdzie w oczy, na zrootowanym urządzeniu WSZYSTKO może zostać sfałszowane.
ocodo
5
Dostęp do adresu MAC Wi-Fi został zablokowany na Androidzie M: stackoverflow.com/questions/31329733/...
breez
6
Z Androida 6.x zwraca spójny fałszywy adres 02:00:00:00:00:00
MAC
87

Jest raczej przydatna informacji tutaj .

Obejmuje pięć różnych typów identyfikatorów:

  1. IMEI (tylko dla urządzeń z Androidem z obsługą telefonu; potrzeby android.permission.READ_PHONE_STATE)
  2. Pseudo-unikalny identyfikator (dla wszystkich urządzeń z Androidem)
  3. Identyfikator Androida (może być zerowy, można go zmienić po przywróceniu ustawień fabrycznych, można zmienić na zrootowanym telefonie)
  4. Ciąg adresu MAC sieci WLAN (potrzeby android.permission.ACCESS_WIFI_STATE)
  5. Ciąg adresu MAC BT (urządzenia z Bluetooth, wymaga android.permission.BLUETOOTH)
stansult
źródło
2
Ważny punkt pominięty (tutaj i w artykule): nie można uzyskać sieci WLAN ani BT MAC, jeśli nie są włączone! W przeciwnym razie uważam, że MAC MAC byłby idealnym identyfikatorem. Nie masz gwarancji, że użytkownik kiedykolwiek włączy swoje Wi-Fi, i nie sądzę, aby „właściwe” było włączenie go samemu.
Tom
1
@Tom jesteś w błędzie. Nadal możesz odczytać WLAN lub BT MAC, nawet jeśli są wyłączone. Nie ma jednak gwarancji, że urządzenie ma dostępne moduły WLAN lub BT.
Marqs
2
W szczególności lokalne adresy WiFi i Bluetooth MAC nie są już dostępne. Metoda getMacAddress () obiektu aWifiInfo i metoda BluetoothAdapter.getDefaultAdapter (). Metoda getAddress () odtąd zwróci 02: 00: 00: 00: 00: 00 od teraz
sarika kate
4
@sarikakate To prawda tylko w wersji 6.0 Marshmallow i nowszych ... Nadal działa zgodnie z oczekiwaniami w wersji 6.0 Marshmallow.
Smeet,
@Smeet Tak, masz rację. Zapomniałem wspomnieć, że działa poniżej wersji 6.0
Sarika Kate,
51

Oficjalny blog programistów Androida zawiera teraz pełny artykuł na ten temat - Identyfikowanie instalacji aplikacji .

BoD
źródło
4
Kluczową kwestią tego argumentu jest to, że jeśli próbujesz uzyskać unikalny identyfikator ze sprzętu, prawdopodobnie popełniasz błąd.
Tim Bray,
3
A jeśli zezwalasz na resetowanie blokady urządzenia poprzez przywrócenie ustawień fabrycznych, Twój model oprogramowania próbnego jest tak dobry, jak martwy.
Seva Alekseyev
43

W Google I / O Reto Meier opublikował solidną odpowiedź na pytanie, jak podejść do tego, co powinno zaspokoić większość programistów potrzebujących śledzić użytkowników w różnych instalacjach. Anthony Nolan wskazuje kierunek w swojej odpowiedzi, ale pomyślałem, że wypiszę pełne podejście, aby inni mogli łatwo zobaczyć, jak to zrobić (zajęło mi trochę czasu, aby zrozumieć szczegóły).

Takie podejście da ci anonimowy, bezpieczny identyfikator użytkownika, który będzie trwały dla użytkownika na różnych urządzeniach (w oparciu o podstawowe konto Google) i we wszystkich instalacjach. Podstawowym podejściem jest wygenerowanie losowego identyfikatora użytkownika i zapisanie go we wspólnych preferencjach aplikacji. Następnie używasz agenta kopii zapasowej Google do przechowywania wspólnych preferencji powiązanych z kontem Google w chmurze.

Przejdźmy przez pełne podejście. Najpierw musimy utworzyć kopię zapasową naszych wspólnych preferencji za pomocą usługi Android Backup Service. Zacznij od zarejestrowania aplikacji za pośrednictwem http://developer.android.com/google/backup/signup.html.

Google da ci klucz usługi kopii zapasowej, który musisz dodać do manifestu. Musisz także powiedzieć aplikacji, aby korzystała z BackupAgent w następujący sposób:

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

Następnie musisz utworzyć agenta kopii zapasowej i powiedzieć mu, aby używał agenta pomocniczego do wspólnych preferencji:

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);
    }
}

Aby zakończyć tworzenie kopii zapasowej, musisz utworzyć instancję BackupManager w głównym działaniu:

BackupManager backupManager = new BackupManager(context);

Na koniec utwórz identyfikator użytkownika, jeśli jeszcze nie istnieje, i zapisz go w 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;
}

Ten identyfikator_użytkownika będzie teraz trwały w różnych instalacjach, nawet jeśli użytkownik przeniesie urządzenie.

Więcej informacji na temat tego podejścia można znaleźć w wykładzie Reto .

Aby uzyskać szczegółowe informacje na temat wdrażania agenta kopii zapasowej, zobacz Kopia zapasowa danych . Szczególnie polecam sekcję na dole dotyczącą testowania, ponieważ tworzenie kopii zapasowej nie następuje natychmiast, więc aby przetestować, musisz wymusić wykonanie kopii zapasowej.

TechnoTony
źródło
5
Czy to nie prowadzi do wielu urządzeń o tym samym identyfikatorze, gdy użytkownik ma wiele urządzeń? Na przykład tablet i telefon.
Tosa
Wymagany jest do tego minimalny cel 8.
halaksynat
Czy byłby to preferowany sposób na utworzenie ładunku weryfikacyjnego podczas zakupów w aplikacji? Z kodu przykładowego fakturowania w aplikacji komentarz: „Tak więc dobry ładunek programisty ma następujące cechy: 1. Jeśli dwóch różnych użytkowników kupuje produkt, ładunek jest inny między nimi, więc zakupu jednego użytkownika nie można odtworzyć innemu użytkownikowi. 2. Ładunek musi być taki, aby można go było zweryfikować, nawet jeśli aplikacja nie była tą, która zainicjowała proces zakupu (aby elementy zakupione przez użytkownika na jednym urządzeniu działały na innych urządzeniach należących do użytkownika). ”
TouchBoarder
@Tosa Miałem właśnie to samo pytanie. Ale czy nie moglibyśmy ponownie użyć tej samej techniki do tworzenia identyfikatorów urządzeń wirtualnych i po prostu nie tworzyć kopii zapasowej w ten sam sposób? Identyfikator urządzenia nie przetrwałby po wyczyszczeniu lub ponownej instalacji, ale jeśli mamy trwały identyfikator użytkownika, możemy nie potrzebować tyle z identyfikatora urządzenia.
jwehrle
39

Myślę, że to z pewnością ognisty sposób na zbudowanie szkieletu dla unikalnego ID ... sprawdź to.

Pseudo-unikalny identyfikator, który działa na wszystkich urządzeniach z Androidem Niektóre urządzenia nie mają telefonu (np. Tablety) lub z jakiegoś powodu nie chcesz dołączać uprawnienia READ_PHONE_STATE. Nadal możesz odczytać szczegóły, takie jak wersja ROM, nazwa producenta, typ procesora i inne szczegóły sprzętowe, które będą odpowiednie, jeśli chcesz użyć identyfikatora do sprawdzania klucza szeregowego lub do innych ogólnych celów. Obliczony w ten sposób identyfikator nie będzie unikalny: można znaleźć dwa urządzenia o tym samym identyfikatorze (oparte na tym samym sprzęcie i obrazie ROM), ale zmiany w rzeczywistych aplikacjach są nieistotne. W tym celu możesz użyć klasy 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

Większość członków Kompilacji to łańcuchy, a my tutaj zajmujemy ich długość i przekształcamy je za pomocą modulo w cyfrę. Mamy 13 takich cyfr i dodajemy dwie kolejne z przodu (35), aby mieć taki sam identyfikator rozmiaru jak IMEI (15 cyfr). Są tutaj inne możliwości, spójrz tylko na te struny. Zwraca coś takiego 355715565309247. Nie jest wymagane specjalne pozwolenie, dzięki czemu takie podejście jest bardzo wygodne.


(Dodatkowe informacje: technika podana powyżej została skopiowana z artykułu o Pocket Magic .)

Lenn Dolling
źródło
7
Ciekawe rozwiązanie Wygląda na to, że jest to sytuacja, w której naprawdę powinieneś po prostu mieszać wszystkie dane połączone, zamiast próbować wymyślić własną funkcję „mieszania”. Istnieje wiele przypadków kolizji, nawet jeśli istnieją znaczące dane, które są różne dla każdej wartości. Moja rekomendacja: użyj funkcji skrótu, a następnie przekształć wyniki binarne na dziesiętne i skróć je w razie potrzeby. Aby zrobić to dobrze, powinieneś jednak naprawdę użyć UUID lub pełnego ciągu mieszającego.
Steve Pomeroy
21
Powinieneś wspomnieć o swoich źródłach ... Zostało to usunięte bezpośrednio z następującego artykułu: pocketmagic.net/?p=1662
Steve Haley
8
Ten identyfikator jest otwarty na kolizje, jakbyś nie wiedział co. Jest praktycznie gwarantowane, że będzie taki sam na identycznych urządzeniach tego samego operatora.
Seva Alekseyev
7
Może się to również zmienić, jeśli urządzenie zostanie zaktualizowane.
David Biorąc pod uwagę
8
Bardzo, bardzo złe rozwiązanie. Testowany na dwóch Nexusach 5 ... Zwróć te same liczby.
Sinan Dizdarević
38

Poniższy kod zwraca numer seryjny urządzenia przy użyciu ukrytego interfejsu API Androida. Ale ten kod nie działa na Samsung Galaxy Tab, ponieważ „ro.serialno” nie jest ustawione na tym urządzeniu.

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) {

}
Roman SL
źródło
Właśnie przeczytałem na XDA Developer, że ro.serialnojest on używany do generowania Settings.Secure.ANDROID_ID. Są to w zasadzie różne reprezentacje o tej samej wartości.
Martin
@ Martin: ale prawdopodobnie numer seryjny nie zmienia się po zresetowaniu urządzenia. Czyż nie ANDROID_IDZ tego wynika tylko nowa wartość dla .
Ronnie
Właściwie na wszystkich urządzeniach przetestowałem je tam, gdzie są identyczne. A przynajmniej wartości skrótu, w których są takie same (ze względów prywatności nie zapisuję prawdziwych wartości w plikach dziennika).
Martin
Ta wartość jest taka sama jakandroid.os.Build.SERIAL
eugeneek
android.os.Build.SERIALbędzie przestarzałe w Androidzie O, patrz android-developers.googleblog.com/2017/04/…
EpicPandaForce
32

To proste pytanie, bez prostej odpowiedzi.

Co więcej, wszystkie istniejące odpowiedzi tutaj są nieaktualne lub niewiarygodne.

Więc jeśli szukasz rozwiązania w 2020 roku .

Oto kilka rzeczy, o których należy pamiętać:

Wszystkie identyfikatory sprzętowe (SSAID, IMEI, MAC itp.) Są niewiarygodne w przypadku urządzeń innych niż Google (wszystko oprócz pikseli i nexusów), które stanowią ponad 50% aktywnych urządzeń na całym świecie. Dlatego oficjalne najlepsze praktyki dotyczące identyfikatorów Androida wyraźnie stwierdzają:

Unikaj używania identyfikatorów sprzętowych , takich jak SSAID (Android ID), IMEI, adres MAC itp.

To sprawia, że ​​większość powyższych odpowiedzi jest nieważna. Również z powodu różnych aktualizacji zabezpieczeń Androida niektóre z nich wymagają nowszych i bardziej rygorystycznych uprawnień do wykonywania, których użytkownik może po prostu odmówić.

Jako przykład, CVE-2018-9489który wpływa na wszystkie wyżej wymienione techniki oparte na WIFI.

To sprawia, że ​​te identyfikatory są nie tylko zawodne, ale również niedostępne w wielu przypadkach.

Mówiąc prościej: nie używaj tych technik .

Wiele innych odpowiedzi tutaj sugeruje użycie AdvertisingIdClient, który jest również niezgodny, ponieważ z założenia należy go używać tylko do profilowania reklam. Jest to również określone w oficjalnym odnośniku

Używaj identyfikatora reklamowego tylko do profilowania użytkowników lub przypadków użycia reklam

Identyfikacja urządzenia jest nie tylko niewiarygodna, ale należy również przestrzegać zasad prywatności użytkownika dotyczących zasad śledzenia reklam , które wyraźnie stwierdzają, że użytkownik może je zresetować lub zablokować w dowolnym momencie.

Więc też go nie używaj .

Ponieważ nie można mieć żądanego statycznego, unikalnego globalnie i niezawodnego identyfikatora urządzenia. Oficjalne referencje Androida sugerują:

Używaj FirebaseInstanceId lub prywatnego GUID, o ile to możliwe, we wszystkich innych przypadkach użycia, z wyjątkiem zapobiegania oszustwom płatniczym i telefonii.

Jest unikalny w przypadku instalacji aplikacji na urządzeniu, więc gdy użytkownik odinstaluje aplikację - jest usuwana, więc nie jest w 100% niezawodna, ale jest następną najlepszą rzeczą.

Aby użyć, FirebaseInstanceIddodaj najnowszą zależność Firebase -Messaging do swojej oceny

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

I użyj poniższego kodu w wątku w tle:

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

Jeśli musisz zapisać identyfikator urządzenia na zdalnym serwerze, nie przechowuj go takim, jaki jest (zwykły tekst), ale skrót z solą .

Dzisiaj jest to nie tylko najlepsza praktyka, ale musisz to zrobić zgodnie z prawem zgodnie z RODO - identyfikatory i podobne regulacje.

Nikita Kurtin
źródło
3
Na razie jest to najlepsza odpowiedź, a pierwsze zdanie jest najlepszym streszczeniem: „To proste pytanie, bez prostej odpowiedzi - po prostu to uwielbiam.
b2mob
Należy docenić komentarz „z wyjątkiem zapobiegania oszustwom płatniczym i telefonii” bez odpowiedzi, jak rozwiązać ten przypadek użycia.
Eran Boudjnah
@EranBoudjnah Ten cytat z oficjalnej referencji, do której link znajduje się w odpowiedzi. Mogę spróbować rozwiązać ten przypadek użycia, ale ponieważ nie jest on specyficzny dla pytania PO, zgodnie z polityką stackoverflow - należy to zrobić w osobnym dedykowanym pytaniu.
Nikita Kurtin
Mówię tylko, że odpowiedź jest niepełna. Ale wiem, że to nie twoja wina, bo to cytat.
Eran Boudjnah
1
@ M.UsmanKhan, odpowiedź jest napisana zaraz po tym: „ Dziś jest to nie tylko najlepsza praktyka, w rzeczywistości musisz to zrobić zgodnie z prawem zgodnie z RODO - identyfikatory i podobne przepisy
Nikita Kurtin
27

Korzystając z poniższego kodu, możesz uzyskać unikatowy identyfikator urządzenia z systemem Android jako ciąg.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
Mohit Kanada
źródło
21

Seryjny pole dodano do Buildklasy poziomu API 9 (Mobile 2.3 - pierniki). Dokumentacja mówi, że reprezentuje numer seryjny sprzętu. Dlatego powinien być unikalny, jeśli istnieje na urządzeniu.

Nie wiem jednak, czy jest on faktycznie obsługiwany (= nie zerowy) przez wszystkie urządzenia z poziomem API> = 9.

Ron L.
źródło
2
Niestety jest to „nieznane”.
m0skit0
18

Dodam jeszcze jedną rzecz - mam jedną z tych wyjątkowych sytuacji.

Za pomocą:

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

Okazuje się, że chociaż mój tablet Viewsonic G zgłasza identyfikator urządzenia, który nie ma wartości NULL, każdy tablet G ma ten sam numer.

Sprawia, że ​​gra w „Pocket Empires” staje się interesująca, co zapewnia natychmiastowy dostęp do czyjegoś konta na podstawie „unikalnego” DeviceID.

Moje urządzenie nie ma radia komórkowego.

Tony Maro
źródło
Jaki jest identyfikator? czy to jest szansa 9774d56d682e549c?
Mr_and_Mrs_D
Wow, to było tak dawno temu Dawno temu rzuciłem ten tablet. Nie mogłem powiedzieć.
Tony Maro,
Pracuje. Ponadto jest o wiele bardziej zwarty niż identyfikator, który otrzymuję z losowego UUID.
Treewallie,
1
@Treewallie czy to działa? Czy możesz uzyskać ten sam identyfikator urządzenia z różnych aplikacji?
Arnold Brown
@ArnoldBrown Tak. Sprawdź to dokładnie. Miłego dnia: D
Treewallie
16

Szczegółowe instrukcje na temat uzyskiwania unikalnego identyfikatora dla każdego urządzenia z Androidem, z którego zainstalowana jest aplikacja, można znaleźć na oficjalnym blogu programistów Androida, w którym opisano instalacje aplikacji .

Wydaje się, że najlepszym sposobem jest wygenerowanie go samodzielnie podczas instalacji, a następnie przeczytanie go po ponownym uruchomieniu aplikacji.

Osobiście uważam to za dopuszczalne, ale nie idealne. Żaden identyfikator podany przez Androida nie działa we wszystkich przypadkach, ponieważ większość zależy od stanu radia telefonu (Wi-Fi wł. / Wył., Wł. / Wył. Komórkowy, wł. / Wył. Bluetooth). Inne, podobnie jak Settings.Secure.ANDROID_IDmuszą być wdrożone przez producenta i nie ma gwarancji, że będą unikalne.

Poniżej znajduje się przykład zapisu danych do pliku instalacyjnego , który byłby przechowywany wraz z wszelkimi innymi danymi zapisywanymi lokalnie przez aplikację.

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();
    }
}
Kevin Parker
źródło
Jeśli chcesz śledzić instalacje aplikacji, jest to idealne rozwiązanie. Urządzenia śledzące są jednak znacznie trudniejsze i wydaje się, że nie ma całkowicie hermetycznego rozwiązania.
Luca Spiller,
Co z zrootowanymi urządzeniami? Mogą łatwo zmienić ten identyfikator instalacji, prawda?
tasomaniac
Absolutnie. Root może zmienić identyfikator instalacji. Możesz sprawdzić rootowanie za pomocą tego bloku kodu: stackoverflow.com/questions/1101380/…
Kevin Parker
czy jeśli przywrócimy ustawienia fabryczne, plik zostanie usunięty?
Jamshid
W przypadku przywrócenia ustawień fabrycznych i usunięcia lub sformatowania partycji / data identyfikator UUID jest inny.
Kevin Parker,
12

Dodaj poniższy kod w pliku klasy:

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);

Dodaj w AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Android
źródło
10

Unikalny identyfikator urządzenia z systemem operacyjnym Android jako Ciąg, przy użyciu TelephonyManageri ANDROID_ID, jest uzyskiwany przez:

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);
}

Ale zdecydowanie zalecam metodę sugerowaną przez Google, patrz Identyfikacja instalacji aplikacji .

Jorgesys
źródło
9

Istnieje wiele różnych podejść do obejścia tych ANDROID_IDproblemów (mogą być nullczasami lub urządzenia określonego modelu zawsze zwracają ten sam identyfikator) z zaletami i wadami:

  • Implementowanie niestandardowego algorytmu generowania identyfikatorów (na podstawie właściwości urządzenia, które powinny być statyczne i nie ulegną zmianie -> kto wie)
  • Nadużywanie innych identyfikatorów, takich jak IMEI , numer seryjny, adres Wi-Fi / Bluetooth-MAC (nie będą one istnieć na wszystkich urządzeniach lub konieczne będą dodatkowe uprawnienia)

Sam wolę używać istniejącej implementacji OpenUDID (patrz https://github.com/ylechelle/OpenUDID ) dla Androida (patrz https://github.com/vieux/OpenUDID ). Jest łatwa do zintegrowania i wykorzystuje ANDROID_IDawarie w przypadku wyżej wymienionych problemów.

Andreas Klöber
źródło
8

Co powiesz na IMEI . Jest to unikalne rozwiązanie dla Androida lub innych urządzeń mobilnych.

Elzo Valugi
źródło
9
Nie dla moich tabletów, które nie mają IMEI, ponieważ nie łączą się z moim operatorem komórkowym.
Brill Pappin
2
Nie wspominając o urządzeniach CDMA, które mają ESN zamiast IMEI.
David Biorąc pod uwagę
@David Biorąc pod uwagę, czy istnieje CDMA z Androidem?
Elzo Valugi
1
To tylko zrobi to to jest telefon :) Tablet nie może.
Brill Pappin
3
@ElzoValugi To już „dziś” i wciąż nie wszystkie tablety mają karty SIM.
Matthew Quiros,
8

Oto jak generuję unikalny identyfikator:

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;
}
Eng.Fouad
źródło
jeśli korzystamy z ReadPhoneState w wersji 6.0 z prośbą o zezwolenie na środowisko uruchomieniowe
Harsha,
8

Moje dwa centy - NB, to jest za unikatowy identyfikator urządzenia - nie ten instalacyjny, jak omówiono na blogu programistów Androida .

Należy zauważyć, że rozwiązanie dostarczone przez @emmby ma identyfikator ID aplikacji, ponieważ SharedPreferences nie są synchronizowane między procesami (patrz tutaj i tutaj ). Więc całkowicie tego uniknąłem.

Zamiast tego hermetyzowałem różne strategie uzyskiwania identyfikatora (urządzenia) w wyliczeniu - zmiana kolejności stałych wyliczania wpływa na priorytet różnych sposobów uzyskiwania identyfikatora. Zwracany jest pierwszy niepusty identyfikator lub generowany jest wyjątek (zgodnie z dobrymi praktykami Java, aby nie nadawać null znaczenia). Na przykład mam najpierw TELEPHONY - ale dobrym wyborem domyślnym byłaby wersja ANDROID_ID beta:

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);
        }
    }
}
Mr_i_Mrs_D
źródło
8

Tutaj jest ponad 30 odpowiedzi, a niektóre są takie same, a niektóre są wyjątkowe. Ta odpowiedź jest oparta na kilku z tych odpowiedzi. Jednym z nich jest odpowiedź @Lenn Dolling.

Łączy 3 identyfikatory i tworzy 32-cyfrowy ciąg szesnastkowy. To działało dla mnie bardzo dobrze.

3 identyfikatory to:
Pseudo-identyfikator - jest generowany na podstawie fizycznych specyfikacji urządzenia
ANDROID_ID - Settings.Secure.ANDROID_ID
adres Bluetooth - adres adaptera Bluetooth

Zwróci coś takiego: 551F27C060712A72730B0A0F734064B1

Uwaga: Zawsze możesz dodać więcej identyfikatorów do longIdłańcucha. Na przykład numer seryjny. adres adaptera wifi. IMEI. W ten sposób czynisz go bardziej unikalnym dla każdego urządzenia.

@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 "";
}
ᴛʜᴇᴘᴀᴛᴇʟ
źródło
1
Dodanie UUID do longIdpliku i zapisanie go w pliku sprawi, że będzie on najbardziej unikalnym identyfikatorem:String uuid = UUID.randomUUID().toString();
Mousa Alfhaily 11.04.17
1
Jeśli wszystko inne zawiedzie, jeśli użytkownik ma niższy niż API 9 (niższy niż Piernik), zresetował swój telefon lub „Secure.ANDROID_ID”. jeśli zwróci „null”, wówczas zwrócony identyfikator będzie oparty wyłącznie na informacjach o urządzeniu z Androidem. To tutaj mogą zdarzyć się kolizje. Staraj się nie używać DISPLAY, HOST lub ID - te elementy mogą ulec zmianie. Jeśli wystąpią kolizje, dane będą się nakładać. Źródło: gist.github.com/pedja1/fe69e8a80ed505500caa
Mousa Alfhaily
Jeśli spróbujemy uzyskać unikalny numer za pomocą tego wiersza kodu, czy możemy powiedzieć, że jest to unikatowy identyfikator i nigdy nie będzie w konflikcie z żadnym innym urządzeniem?
Ninja
1
@Ninja Ponieważ adres BLE mac jest unikalny, tak, wygenerowany identyfikator zawsze będzie unikalny. Jeśli jednak naprawdę chcesz być pewien, sugeruję dodanie UUID do pliku longId. Zmień tę jedną linię w ten sposób: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString();Gwarantuje to, że wygenerowany identyfikator będzie unikalny.
ᴛʜᴇᴘᴀᴛᴇʟ
@ ᴛʜᴇᴘᴀᴛᴇʟ Dziękuję bardzo za tę ogromną pomoc. W rzeczywistości moja aplikacja jest bardzo wrażliwa na dane, więc muszę się upewnić, dlatego właśnie potwierdzam to.
Ninja
7

Innym sposobem jest korzystanie /sys/class/android_usb/android0/iSerialz aplikacji bez żadnych uprawnień.

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

Aby to zrobić w Javie, wystarczy użyć FileInputStream, aby otworzyć plik iSerial i odczytać znaki. Tylko upewnij się, że umieścisz go w module obsługi wyjątków, ponieważ nie wszystkie urządzenia mają ten plik.

Wiadomo, że przynajmniej następujące urządzenia mają ten plik do odczytu na całym świecie:

  • Galaxy Nexus
  • Nexus S.
  • Motorola Xoom 3G
  • Toshiba AT300
  • HTC One V.
  • Mini MK802
  • Samsung Galaxy S II

Możesz także zobaczyć mój wpis na blogu Wyciekający numer seryjny sprzętu Android do nieuprzywilejowanych aplikacji, w którym omawiam, jakie inne pliki są dostępne do informacji.

insitusec
źródło
Właśnie przeczytałem twój post na blogu. Uważam, że nie jest to unikalne: Build.SERIAL jest również dostępny bez jakichkolwiek uprawnień i jest (teoretycznie) unikalnym sprzętowym numerem seryjnym.
Tom
1
Masz rację. To tylko jeden ze sposobów, w jaki można śledzić urządzenie, i jak powiedziałeś, oba te sposoby nie wymagają uprawnień aplikacji.
insitusec
7

TelephonyManger.getDeviceId () Zwraca unikalny identyfikator urządzenia, na przykład IMEI dla GSM i MEID lub ESN dla telefonów CDMA.

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

Ale polecam użyć:

Settings.Secure.ANDROID_ID, który zwraca identyfikator Androida jako unikalny 64-bitowy ciąg szesnastkowy.

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

Czasami TelephonyManger.getDeviceId () zwraca null, więc aby zapewnić unikalny identyfikator, użyjesz tej metody:

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;
}
Jorgesys
źródło
Niedawno odkryłem, że urządzenie klienta typu SM-G928F / Galaxy S6 edge + dostarcza tylko 15 zamiast 16 cyfr szesnastkowych dla identyfikatora Androida.
Holger Jakobs
7

Aby rozpoznać sprzętowo określone urządzenie z Androidem, możesz sprawdzić adresy MAC.

możesz to zrobić w ten sposób:

w AndroidManifest.xml

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

teraz w kodzie:

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

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

Na każdym urządzeniu z Androidem ich interfejs jest co najmniej „wlan0”, a układ WI-FI. Ten kod działa nawet wtedy, gdy WI-FI nie jest włączony.

PS Ich jest wiele innych interfejsów, które otrzymasz z listy zawierającej MACS Ale to może się zmieniać między telefonami.

Ilan.b
źródło
7

Używam następującego kodu, aby uzyskać IMEIlub użyć Bezpieczne. ANDROID_IDalternatywnie, gdy urządzenie nie ma możliwości telefonu:

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);
Asaf Pinhassi
źródło
7

Dokładniej Settings.Secure.ANDROID_ID. Jest to 64-bitowa ilość, która jest generowana i przechowywana przy pierwszym uruchomieniu urządzenia. Jest resetowany po wyczyszczeniu urządzenia.

ANDROID_IDwydaje się dobrym wyborem dla unikalnego identyfikatora urządzenia. Są wady: Po pierwsze, nie jest w 100% wiarygodny w wersjach Androida wcześniejszych niż 2.2. (“Froyo”).Ponadto w popularnym telefonie od jednego z głównych producentów pojawił się co najmniej jeden powszechnie obserwowany błąd, w którym każda instancja ma ten sam ANDROID_ID.

mumu123
źródło
1
ta odpowiedź jest kopią pasty ze starego bloga google android-developers.googleblog.com/2011/03/… . Więc błąd został już rozwiązany?
Sergii
7

Aby zrozumieć dostępne unikalne identyfikatory na urządzeniach z Androidem. Skorzystaj z tego oficjalnego przewodnika.

Najlepsze praktyki dotyczące unikalnych identyfikatorów:

IMEI, adresy Mac, identyfikator wystąpienia, identyfikatory GUID, identyfikator SSAID, identyfikator reklamowy, interfejs API sieci bezpieczeństwa do weryfikacji urządzeń.

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

Waheed Nazir
źródło
6

Identyfikator wystąpienia Google

Wydany na I / O 2015; na Androida wymaga usług Play 7.5.

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

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

Wygląda na to, że Google zamierza użyć tego identyfikatora do identyfikacji instalacji na Androidzie, Chrome i iOS.

Identyfikuje instalację, a nie urządzenie, ale z drugiej strony ANDROID_ID (który jest akceptowaną odpowiedzią) nie rozpoznaje już urządzeń. W środowisku wykonawczym ARC generowany jest nowy ANDROID_ID dla każdej instalacji ( szczegóły tutaj ), podobnie jak ten nowy identyfikator instancji. Myślę też, że identyfikacja instalacji (a nie urządzeń) jest tym, czego tak naprawdę szuka większość z nas.

Zalety identyfikatora instancji

Wydaje mi się, że Google zamierza używać go w tym celu (identyfikując twoje instalacje), jest wieloplatformowy i może być wykorzystywany do wielu innych celów (patrz linki powyżej).

Jeśli używasz GCM, w końcu będziesz musiał użyć tego identyfikatora instancji, ponieważ jest on potrzebny, aby uzyskać token GCM (który zastępuje stary identyfikator rejestracji GCM).

Wady / problemy

W bieżącej implementacji (GPS 7.5) identyfikator instancji jest pobierany z serwera na żądanie aplikacji. Oznacza to, że powyższe połączenie jest połączeniem blokującym - w moich testach nienaukowych zajmuje 1-3 sekund, jeśli urządzenie jest w trybie online, i 0,5 - 1,0 sekundy, jeśli jest w trybie off-line (przypuszczalnie tyle czasu czeka przed rezygnacją i wygenerowaniem losowy identyfikator). Zostało to przetestowane w Ameryce Północnej na Nexusie 5 z Androidem 5.1.1 i GPS 7.5.

Jeśli używasz identyfikatora do celów, które zamierzają - np. uwierzytelnianie aplikacji, identyfikacja aplikacji, GCM - Myślę, że 1-3 sekundy mogą być uciążliwe (oczywiście w zależności od aplikacji).

Tomek
źródło
1
Innym znaczącym minusem instanceID jest to, że zostanie wygenerowany nowy identyfikator instanceID, jeśli użytkownik wyczyści dane aplikacji.
idanakav
Ciekawe, ale nie sądzę, że tak naprawdę zmienia potencjalne przypadki użycia: identyfikator instancji, taki jak android_id, nie nadaje się do identyfikacji urządzenia. Twój serwer zobaczy więc, że dane użytkownika są usuwane, podobnie jak odinstalowanie i ponowna instalacja aplikacji - co nie jest nierozsądne.
Tom