Pytanie Czy istnieje unikalny identyfikator urządzenia z Androidem?


Czy urządzenia z Androidem mają unikalny identyfikator, a jeśli tak, to w jaki prosty sposób uzyskać do niego dostęp za pomocą Java?


2312
2018-05-07 00:47


pochodzenie


Jeśli używasz ANDROID_ID koniecznie przeczytaj ta odpowiedź i ten błąd. - Dheeraj V.S.
Oto odpowiedź informacyjna. - Eng.Fouad
Znalazłem idealne: stackoverflow.com/a/16929647/1318946 - Pratik Butani
Uważam, że jest to bardzo pomocne, ponieważ omawia wszystkie dostępne unikatowe identyfikatory i waży w każdym, a kończy najlepiej stackoverflow.com/q/27233518/5252270 - sathishkumar_kingmaker


Odpowiedzi:


Settings.Secure#ANDROID_ID zwraca identyfikator Androida jako unikalny dla każdego użytkownika 64-bitowy łańcuch szesnastkowy.

import android.provider.Settings.Secure;

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

1699
2018-05-07 00:49



Czasami wiadomo, że ma wartość null, jest to udokumentowane jako "może się zmienić po przywróceniu ustawień fabrycznych". Używaj na własne ryzyko i można je łatwo zmienić na zrootowanym telefonie. - Seva Alekseyev
groups.google.com/group/android-developers/browse_thread/thread/... - Erdal
Myślę, że musimy zachować ostrożność w używaniu ANDROID_ID w haszowaniu w pierwszej odpowiedzi, ponieważ może nie być ustawiona, gdy aplikacja jest uruchamiana po raz pierwszy, może być ustawiona później, lub może nawet zmienić się w teorii, dlatego unikalny identyfikator może się zmienić
Pamiętaj, że to rozwiązanie ma ogromne ograniczenia: android-developers.blogspot.com/2011/03/... - emmby
ANDROID_ID nie identyfikuje już jednoznacznie urządzenia (od wersji 4.2): stackoverflow.com/a/13465373/150016 - Tom


AKTUALIZACJA: Od niedawnych wersji Androida, wiele problemów z ANDROID_ID zostały rozwiązane i uważam, że takie podejście nie jest już konieczne. Proszę spojrzeć Odpowiedź Anthony'ego.

Pełne ujawnienie: moja aplikacja początkowo stosowała poniższe podejście, ale nie stosuje już tego podejścia, a teraz stosujemy podejście opisane w dokumencie Blog programisty Androida wejście to Odpowiedź Emmby'ego linki do (mianowicie generowanie i zapisywanie pliku UUID#randomUUID()).


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

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

  1. Wszystkie testowane urządzenia zwróciły wartość TelephonyManager.getDeviceId()
  2. Wszystkie urządzenia GSM (wszystkie przetestowane z kartą SIM) zwróciły wartość 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ść ANDROID_ID
  5. Wszystkie urządzenia CDMA zwróciły tę samą wartość (lub wyprowadzenie tej samej wartości) dla obu ANDROID_ID i TelephonyManager.getDeviceId() - tak długo jak 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()  powinien bądź wystarczający. Oczywiście niektórzy użytkownicy są bardziej paranoiści niż inni, więc może być użyteczne zaszyfrowanie 1 lub więcej z tych identyfikatorów, tak aby ciąg był nadal praktycznie unikalny dla urządzenia, ale nie identyfikuje jawnie rzeczywistego urządzenia użytkownika. Na przykład za pomocą 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: 00000000-54b3-e7c7-0000-000046bffd97

Działa to wystarczająco dobrze dla mnie.

Jak Richard wspomina poniżej, nie zapominaj, że potrzebujesz uprawnień do czytania TelephonyManager właściwości, dodaj to do swojego manifestu:

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

importuj biblioteki

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

1056
2018-05-17 22:12



Identyfikator oparty na telefonach nie będzie dostępny na tabletach, co? - Seva Alekseyev
Stąd dlaczego powiedziałem, że większość nie będzie działać cały czas :) Jeszcze nie widzę żadnej odpowiedzi na to pytanie, która jest niezawodna dla wszystkich urządzeń, wszystkich typów urządzeń i wszystkich konfiguracji sprzętowych. Właśnie dlatego to pytanie zaczyna się tutaj. Jest całkiem jasne, że nie ma na to rozwiązania typu "wszystko na wszystko". Poszczególni producenci urządzeń mogą mieć numery seryjne urządzeń, ale nie są one dla nas narażone na działanie i nie jest to wymagane. Tak więc pozostaje nam to, co jest dla nas dostępne. - Joe
Przykład 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 długość 36 znaków. - Richard
Pamiętaj, że to rozwiązanie ma ogromne ograniczenia: android-developers.blogspot.com/2011/03/... - emmby
@softarn: Wierzę, że to, o czym mówisz, to blog programisty Androida, z którym emmby już powiązane, co wyjaśnia, czym jesteś próbować powiedzieć, więc może powinieneś po prostu przegłosować swój komentarz. Tak czy inaczej, jak wspomina Emmby w swojej odpowiedzi, nadal istnieją problemy nawet z informacjami na blogu. Pytanie wymaga wyjątkowości URZĄDZENIE identyfikator (nie identyfikator instalacji), więc nie zgadzam się z twoim oświadczeniem. Blog zakłada, że ​​to, czego chcesz niekoniecznie do śledzenia urządzenia, podczas gdy pytanie to właśnie wymaga. Zgadzam się z tym blogiem inaczej. - Joe


Ostatnia aktualizacja: 6/2/15


Po przeczytaniu każdego postu dotyczącego przepełnienia stosu dotyczącego tworzenia unikalnego identyfikatora, bloga programisty Google i dokumentacji Androida, czuję, że "Pseudo ID" jest najlepszą możliwą opcją.

Główny problem: Sprzęt a oprogramowanie

Sprzęt komputerowy

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

Oprogramowanie

  • Użytkownicy mogą wymazywać / zmieniać swoje ROM, jeśli są zrootowane
  • Możesz śledzić użytkowników na różnych platformach (iOS, Android, Windows i Internet)
  • Najlepiej chcesz TRACK INDYWIDUALNY UŻYTKOWNIK z ich zgoda polega na tym, aby po prostu je logować (spraw, aby działał bezproblemowo przy użyciu OAuth)

Ogólny podział na Androida

- Unikalność gwarancji (w tym urządzenia zrootowane) dla API> = 9/10 (99,5% urządzeń z systemem Android)

- Brak 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 unique ID of build information (may overlap data - API < 9)

Dzięki @stansult do publikowania wszystkie nasze opcje (w tym pytaniu o przepełnienie stosu).

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

  • E-mail użytkownika - oprogramowanie

    • Użytkownik może zmienić e-mail - WYSOCE 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ć podstawowy adres e-mail urządzenia 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, potrzeby android.permission.READ_PHONE_STATE)

    • Większość użytkowników nienawidzi faktu, że w zezwoleniu jest napisane "Połączenia telefoniczne". Niektórzy użytkownicy podają złe oceny, ponieważ uważają, że po prostu kradną dane osobowe, gdy naprawdę chcesz tylko śledzić instalacje urządzeń. Oczywiste jest, że zbierasz dane.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Identyfikator Androida - sprzęt (może mieć wartość NULL, można zmienić po przywróceniu ustawień fabrycznych, można zmienić na urządzeniu zrootowanym)

    • 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 do przywracania ustawień fabrycznych, wartość mogła zostać zmieniona lub zmieniona na urządzeniu zrootowanym, więc mogą występować duplikaty wpisów, jeśli śledzisz instalacje użytkownika.
  • Adres MAC sieci WLAN - Sprzęt (wymagania android.permission.ACCESS_WIFI_STATE)

    • Może to być druga najlepsza opcja, ale nadal gromadzisz i przechowujesz niepowtarzalny identyfikator pochodzący bezpośrednio od użytkownika. Jest oczywiste, że zbierasz dane.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Adres MAC urządzenia Bluetooth - sprzęt (urządzenia z Bluetooth, potrzeby android.permission.BLUETOOTH)

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

    • Bardzo możliwe, mogą zawierać kolizje - Zobacz moją metodę zamieszczoną poniżej!
    • Pozwala to na posiadanie "prawie unikatowego" identyfikatora od użytkownika bez podejmowania niczego, co jest prywatne. Możesz utworzyć swój własny anonimowy identyfikator na podstawie informacji o urządzeniu.

Wiem, że nie ma żadnego "idealnego" sposobu na uzyskanie unikalnego identyfikatora bez używania uprawnień; jednak czasami naprawdę musimy tylko śledzić instalację urządzenia. Jeśli chodzi o tworzenie unikalnego identyfikatora, możemy utworzyć "pseudo unikatowy identyfikator" oparty wyłącznie na informacjach dostarczanych nam przez API Android bez korzystania z dodatkowych uprawnień. W ten sposób możemy okazywać szacunek użytkownikowi i starać się oferować również dobre wrażenia użytkownika.

Z pseudo-unikalnym identyfikatorem, naprawdę tylko spotkasz się z faktem, że mogą istnieć duplikaty oparte na tym, że są podobne urządzenia. Możesz poprawić łączoną metodę, aby była bardziej unikalna; jednak niektórzy programiści muszą śledzić instalacje urządzeń, a to spowoduje sztuczkę lub wydajność opartą na podobnych urządzeniach.

API> = 9:

Jeśli ich urządzenie z Androidem ma interfejs API 9 lub nowszy, jest to gwarantowane unikatowe ze względu na pole "Build.SERIAL".

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

API <9:

Jeśli urządzenie z systemem Android użytkownika jest niższe niż API 9; miejmy nadzieję, że nie przywróciły one ustawień fabrycznych, a ich "Secure.ANDROID_ID" zostanie zachowane, a nie "null". (widzieć http://developer.android.com/about/dashboards/index.html)

Jeśli wszystko inne zawiedzie:

Jeśli wszystko inne zawiedzie, jeśli użytkownik ma niższy niż API 9 (niższy niż Gingerbread), zresetował swoje urządzenie lub "Secure.ANDROID_ID" zwraca "null", a następnie po prostu zwrócony identyfikator będzie oparty wyłącznie na ich informacji o urządzeniu z systemem Android. Tutaj mogą zdarzyć się kolizje.

Zmiany:

  • Usunięcie "Android.SECURE_ID" z powodu resetów fabrycznych mogło spowodować zmianę wartości
  • Edytował kod, aby zmienić na 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();
}

Nowe (dla aplikacji z reklamami i usług Google Play):

Z konsoli programisty Google Play:

Od 1 sierpnia 2014 r. Zasady programu dla programistów Google Play   wymaga, aby wszystkie nowe przesłane aplikacje i aktualizacje korzystajĘ ... z identyfikatora wyświetlania reklam w   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:

Zamiarem jest, aby identyfikator reklamy całkowicie zastąpił istniejący   wykorzystanie innych identyfikatorów do celów reklamowych (np. użycie ANDROID_ID   w Settings.Secure), gdy usługi Google Play są dostępne. Przypadki   gdzie Usługi Google Play są niedostępne są oznaczone symbolem a   GooglePlayServicesNotAvailableWyjątek wyrzucania przez   getAdvertisingIdInfo ().

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

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

Próbowałem odnieść się do każdego linku, z którego otrzymałem informacje. Jeśli czegoś brakuje i trzeba go dołączyć, prosimy o komentarz!

Google Play Services InstanceID

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


365
2017-07-12 23:58



Ale czy nie Build zmiana klasy po aktualizacji OS? Zwłaszcza jeśli API zostało zaktualizowane? Jeśli tak, jak możesz zagwarantować, że jest to wyjątkowe? (Mówiąc o metodzie, którą napisałeś) - LuckyMe
Użyłem Twojej metody w mojej aplikacji do wysyłania komentarzy. Mam złe wieści. niestety PsuedoID nie jest całkowicie unikalny. mój serwer zarejestrował ponad 100 na 5 identyfikatorów i ponad 30 na prawie 30 identyfikatorów. najczęściej powtarzanymi identyfikatorami są "ffffffff-fc8f-6093-ffff-ffffd8" (159 rekordów) i "ffffffff-fe99-b334-ffff-ffffef" (154 razy). również na podstawie czasu i komentarzy jest oczywiste, że są różne narody. całkowita liczba rekordów do tej pory wynosi 10 000. proszę dać mi znać, dlaczego tak się stało. czołgi. - hojjat reyhane
Napisałem to 1,5+ lat temu. Nie jestem pewien, dlaczego nie jest to dla ciebie wyjątkowe. Możesz wypróbować identyfikator wyświetlania reklam. Jeśli nie, możesz wymyślić własne rozwiązanie. - Jared Burrows
sorta.. Naprawdę doceniam, jeśli przejdziesz przez to pytanie i podzielisz się swoimi przemyśleniami - Durai Amuthan.H
@ user1587329 Dziękuję. Staram się aktualizować te informacje dla wszystkich. To pytanie jest trudne, jeśli chodzi o sprzęt vs oprogramowanie i platformę. - Jared Burrows


Jak wspomina Dave Webb, Blog programisty Androida zawiera artykuł to obejmuje to. Ich preferowanym rozwiązaniem jest śledzenie instalacji aplikacji, a nie urządzeń, i to będzie działać dobrze w większości przypadków. W poście na blogu pojawi się kod niezbędny do wykonania tej pracy, a ja polecam to sprawdzić.

Jednak post na blogu omawia rozwiązania, jeśli potrzebujesz identyfikatora urządzenia, a nie identyfikatora instalacji aplikacji. Rozmawiałem z kimś z Google, aby uzyskać dodatkowe wyjaśnienia dotyczące kilku kwestii, jeśli zajdzie taka potrzeba. Oto, co odkryłem na temat identyfikatorów urządzeń, które NIE są wymienione we 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.
  • Kilka urządzeń kilku producentów jest dotkniętych przez błąd ANDROID_ID w 2.2.
  • O ile wiem, wszystkie wadliwe urządzenia mają ten sam identyfikator ANDROID_ID, który jest 9774d56d682e549c. Który jest również tym samym identyfikatorem urządzenia zgłoszonym przez emulator, btw.
  • Google wierzy, że producenci sprzętu naprawili problem dla wielu lub większości swoich urządzeń, ale udało mi się zweryfikować, że od początku kwietnia 2011 r. Wciąż jest dość łatwo znaleźć urządzenia, które mają zepsuty identyfikator ANDROID_ID.

Na podstawie zaleceń Google zaimplementowałem klasę, która wygeneruje unikalny identyfikator UUID dla każdego urządzenia, przy użyciu ANDROID_ID jako materiału źródłowego w razie potrzeby, w razie potrzeby odwołując się do usługi TelephonyManager.getDeviceId (), a jeśli to się nie powiedzie, odwołając się do losowo wygenerowanego unikalnego UUID to trwa po ponownym uruchomieniu aplikacji (ale nie po reinstalacji aplikacji).

Zwróć uwagę, że w przypadku urządzeń, które mają awarię w identyfikatorze urządzenia, unikalny identyfikator BĘDZIE utrzymują się przez reset fabryczny. Jest to coś, o czym należy pamiętać. Jeśli chcesz się upewnić, że przywrócenie ustawień fabrycznych spowoduje zresetowanie unikalnego identyfikatora, możesz rozważyć cofnięcie się bezpośrednio do losowego identyfikatora UUID zamiast identyfikatora urządzenia.

Ten kod dotyczy również identyfikatora urządzenia, a nie identyfikatora instalacji aplikacji. W większości sytuacji prawdopodobnie potrzebujesz identyfikatora instalacji aplikacji. Ale jeśli potrzebujesz identyfikatora urządzenia, poniższy kod prawdopodobnie zadziała.

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



Nie powinieneś mieszać różnych identyfikatorów, żeby miały taki sam rozmiar? Dodatkowo powinieneś mieszać identyfikator urządzenia, aby nie przypadkowo ujawnić prywatnych informacji. - Steve Pomeroy
Dobre punkty, Steve. Zaktualizowałem kod, aby zawsze zwracać identyfikator UUID. Gwarantuje to, że a) generowane identyfikatory są zawsze tego samego rozmiaru, oraz b) identyfikator Androida i urządzenia są mieszane przed zwróceniem, aby uniknąć przypadkowego ujawnienia danych osobowych. Zaktualizowałem również opis, aby pamiętać, że identyfikator urządzenia będzie nadal występował po resetach fabrycznych i że może to nie być pożądane dla niektórych użytkowników. - emmby
Uważam, że jesteś niepoprawny; 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 dodaje on jakąś wartość. - Tim Bray
Dobra uwaga, zaktualizowałem komentarz, aby zdecydowanie sugerować, że użytkownicy używają identyfikatorów instalacji aplikacji, a nie identyfikatorów urządzeń. Uważam jednak, że to rozwiązanie jest nadal przydatne dla osób, które potrzebują urządzenia zamiast identyfikatora instalacji. - emmby
ANDROID_ID może zmienić się po przywróceniu ustawień fabrycznych, więc nie może również identyfikować urządzeń - Samuel


Oto kod, który Reto Meier użył w Google I / O prezentacja w tym roku, 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 łączysz to ze strategią tworzenia kopii zapasowych, aby wysyłać preferencje do chmury (również opisane w Reto rozmowapowinieneś mieć identyfikator powiązany z użytkownikiem i trzymać go po tym, jak urządzenie zostało wyczyszczone lub nawet wymienione. Mam zamiar wykorzystać to w analitykach idących dalej (innymi słowy, jeszcze tego nie zrobiłem :).


165
2017-10-28 13:19



Używałem metody @Lenn Dolling z aktualnym czasem dołączonym do unikalnego identyfikatora. Ale wydaje się, że jest to prostszy i bardziej niezawodny sposób. Podziękowania dla Reto Meier i Antony'ego Nolana - Gökhan Barış Aker
Jest wspaniale, ale co z urządzeniami zrootowanymi? Mogą uzyskać do niego dostęp i łatwo zmienić uid na inny. - tasomaniac
Świetna opcja, jeśli nie potrzebujesz unikalnego identyfikatora, który będzie trwał po odinstalowaniu i ponownym zainstalowaniu (np. Impreza promocyjna / gra, w której masz trzy szanse na wygraną, okres). - Kyle Clegg
Prezentacja Meiera opiera się na Android Backup Manager, który z kolei zależy od tego, czy użytkownik 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 zapasowych. Jednak pierwotne pytanie dotyczy generowania unikalnego identyfikatora dla urządzenie, a ten identyfikator jest generowany dla każdej aplikacji, a nawet dla każdej instalacji, a tym bardziej dla każdego urządzenia, a ponieważ zależy od wyboru przez użytkownika opcji tworzenia kopii zapasowej, jej zastosowania wykraczające poza preferencje użytkownika (na przykład w przypadku próby ograniczonej czasowo) są ograniczone. - Carl
To nie zadziała po odinstalowaniu lub wyczyszczeniu danych. - John Shelley


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

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

Wymaga pozwolenia android.permission.ACCESS_WIFI_STATE w manifeście.

Zgłoszono, że będzie dostępny, nawet jeśli Wi-Fi nie jest połączone. Jeśli Joe z powyższej odpowiedzi sprawi, że spróbuje on swoich licznych urządzeń, byłoby to miłe.

Na niektórych urządzeniach nie jest on 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


98
2018-06-23 14:27



To wymagane android.permission.ACCESS_WIFI_STATE - ohhorob
Oni istnieją? Wolę wyobrazić sobie urządzenie bez telefonu (tablet AKA) ... - Seva Alekseyev
Wiem, że to pytanie jest stare - ale to świetny pomysł. Użyłem BT mac ID w mojej aplikacji, ale tylko dlatego, że wymaga funkcji BT. Pokaż mi urządzenie z Androidem, które warto rozwijać, ponieważ NIE ma Wi-Fi. - Jack
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 powoduje usunięcie urządzenia na poziomie jądra. - chrisdowney
@Sanandrea - spójrzmy prawdzie w oczy, na zrootowanym urządzeniu WSZYSTKO może zostać sfałszowane. - ocodo


Są raczej przydatne informacje tutaj.

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

  1. IMEI (tylko dla urządzeń z Androidem, z wykorzystaniem telefonu, potrzebami android.permission.READ_PHONE_STATE)
  2. Pseudo-unikalny identyfikator (dla wszystkich urządzeń z systemem Android)
  3. Identyfikator Androida (może mieć wartość zerową, może ulec zmianie po przywróceniu ustawień fabrycznych, można go zmienić na telefonie zrootowanym)
  4. Adres MAC sieci WLAN ciąg (potrzeby android.permission.ACCESS_WIFI_STATE)
  5. Adres MAC BT ciąg (urządzenia z Bluetooth, potrzeby android.permission.BLUETOOTH)

78
2018-02-08 02:16



Ważny punkt pominięty (tutaj i w artykule): nie można uzyskać dostępu do sieci WLAN lub BT MAC, chyba że są włączone! W przeciwnym razie uważam, że WLAN MAC będzie idealnym identyfikatorem. Nie masz żadnej gwarancji, że użytkownik kiedykolwiek włączy swoje Wi-Fi i naprawdę nie uważam, że "właściwe" jest włączenie go w sobie. - Tom
@Tom się mylisz. Nadal możesz czytać WLAN lub BT MAC, nawet gdy są wyłączone. Jednak nie ma gwarancji, że urządzenie ma dostępne moduły WLAN lub BT. - Marqs
Przede wszystkim lokalne adresy WiFi i Bluetooth MAC nie są już dostępne. Metoda getMacAddress () obiektu aWifiInfo i metoda BluetoothAdapter.getDefaultAdapter (). GetAddress () będą teraz obie powroty02: 00: 00: 00: 00: 00 - sarika kate
@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 6,0 - sarika kate


Oficjalny blog dla programistów Androida ma teraz pełny artykuł o tym właśnie temacie, Identyfikacja instalacji aplikacji.


43
2018-04-06 07:36



Kluczową kwestią tego argumentu jest to, że jeśli próbujesz uzyskać unikalny identyfikator ze sprzętu, prawdopodobnie popełnisz błąd. - Tim Bray
Jeśli zezwolisz na resetowanie blokady urządzenia po przywróceniu ustawień fabrycznych, model wersji próbnej będzie tak dobry, jak martwy. - Seva Alekseyev


W Google I / O Firma Reto Meier opublikowała solidną odpowiedź na to, jak się do tego podejść, dzięki czemu większość programistów musi śledzić użytkowników w różnych instalacjach. Anthony Nolan pokazuje kierunek w swojej odpowiedzi, ale myślałem, że wypiszę pełne podejście, aby inni mogli łatwo zobaczyć, jak to zrobić (zajęło mi trochę czasu, aby dowiedzieć się szczegółów).

Takie podejście zapewni anonimowy, bezpieczny identyfikator użytkownika, który będzie trwały dla użytkownika na różnych urządzeniach (na podstawie podstawowego konta Google) i na różnych instalacjach. Podstawowym podejściem jest wygenerowanie losowego ID użytkownika i zapisanie go we wspólnych preferencjach aplikacji. Następnie używasz agenta kopii zapasowych Google do przechowywania współdzielonych preferencji połączonych z kontem Google w chmurze.

Przejdźmy przez pełne podejście. Najpierw musimy utworzyć kopię zapasową dla SharedPreferences za pomocą usługi kopii zapasowej Android. Zacznij od zarejestrowania aplikacji przez http://developer.android.com/google/backup/signup.html.

Google da ci zapasowy klucz usługi, który musisz dodać do manifestu. Musisz również poinformować aplikację, aby używała programu 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 należy utworzyć agenta kopii zapasowej i poinformować go, aby użył agenta pomocniczego do współdzielenia odwołań:

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 ukończyć tworzenie kopii zapasowej, musisz utworzyć instancję programu BackupManager w głównej aktywności:

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 ID użytkownika będzie teraz stały w różnych instalacjach, nawet jeśli użytkownik przeniesie urządzenie.

Aby uzyskać więcej informacji na temat tego podejścia, patrz Dyskusja Reto.

Aby uzyskać szczegółowe informacje na temat implementacji agenta kopii zapasowej, zobacz Backup danych. Szczególnie polecam sekcję na dole podczas testowania, ponieważ tworzenie kopii zapasowej nie odbywa się natychmiastowo, więc aby przetestować musisz wymusić wykonanie kopii zapasowej.


36
2017-12-22 08:13



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
Minimalny cel 8 jest wymagany do tego. - halxinate
Czy byłby to preferowany sposób tworzenia ładunku weryfikacyjnego podczas robienia zakupów w aplikacji? Z komentarza do kodu rozliczeniowego w aplikacji: "Tak więc dobry ładunek programisty ma następujące cechy: 1. Jeśli dwóch różnych użytkowników kupuje przedmiot, ładunek jest inny między nimi, tak że zakup jednego użytkownika nie może zostać odtworzony innemu użytkownikowi. 2. Ładunek musi być taki, aby można go było zweryfikować, nawet jeśli aplikacja nie była tym, który zainicjował przepływ zakupu (aby przedmioty kupione przez użytkownika na jednym urządzeniu działały na innych urządzeniach będących własnością użytkownika). " - TouchBoarder
@Tosa Miałem 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 wracać w ten sam sposób? Identyfikator urządzenia nie przetrwałby po wyczyszczeniu lub ponownym zainstalowaniu, ale jeśli mamy stały identyfikator użytkownika, możemy nie potrzebować tak dużo od identyfikatora urządzenia. - jwehrle
zrootowani użytkownicy mogą z łatwością edytować udostępnione preferencje - Redman


Poniższy kod zwraca numer seryjny urządzenia za pomocą ukrytego interfejsu API systemu Android. 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) {

}

34
2018-01-25 02:39



Po prostu czytałem na Xda Developer, że ro.serialno służy do generowania Settings.Secure.ANDROID_ID. Więc są to zasadniczo różne przedstawienia o tej samej wartości. - Martin
@Martin: ale prawdopodobnie numer seryjny nie zmienia się po zresetowaniu urządzenia. Czyż nie? Po prostu nowa wartość dla ANDROID_ID pochodzi z niego. - Ronnie
Właściwie na wszystkich urządzeniach testowałem je tam, gdzie są identyczne. Lub przynajmniej wartości mieszania, gdzie to samo (ze względu na prywatność nie zapisuję wartości true w plikach dziennika). - Martin
Ta wartość jest taka sama jak android.os.Build.SERIAL - eugeneek
android.os.Build.SERIAL będzie przestarzałe w Androidzie O, patrz android-developers.googleblog.com/2017/04/... - EpicPandaForce


Myślę, że to jest na pewno ognisty sposób budowania szkieletu dla unikalnego identyfikatora ... 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 uwzględniać uprawnienia READ_PHONE_STATE. Nadal możesz przeczytać szczegóły, takie jak wersja ROM, nazwa producenta, typ procesora i inne szczegóły sprzętu, które będą dobrze pasować, jeśli chcesz użyć identyfikatora do sprawdzenia klucza szeregowego lub do innych ogólnych celów. Identyfikowany w ten sposób identyfikator nie będzie unikalny: możliwe jest znalezienie dwóch urządzeń o tym samym ID (w oparciu o ten sam sprzęt i obraz ROM), ale zmiany w aplikacjach rzeczywistych są pomijalne. 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 Build to ciągi, a my tutaj robimy to, aby wziąć ich długość i przekształcić za pomocą modulo w jedną cyfrę. Mamy 13 takich cyfr i dodajemy dwa kolejne z przodu (35), aby mieć ten sam identyfikator rozmiaru co IMEI (15 cyfr). Są tu inne możliwości, wystarczy spojrzeć na te struny. Zwraca coś podobnego 355715565309247. Żadne specjalne zezwolenie nie jest wymagane, dzięki czemu podejście to jest bardzo wygodne.


(Dodatkowe informacje: Powyższa technika została skopiowana z artykułu na temat Pocket Magic.)


32
2018-03-24 19:55



Ciekawe rozwiązanie. Wygląda na to, że naprawdę powinieneś po prostu mieszać wszystkie te dane, zamiast próbować wymyślić własną funkcję "hash". Istnieje wiele przypadków, w których można uzyskać kolizje, nawet jeśli istnieją istotne dane, które są różne dla każdej wartości. Moje zalecenie: użyj funkcji mieszania, a następnie przekształć wyniki binarne na dziesiętne i skróć je w razie potrzeby. Aby zrobić to dobrze, powinieneś naprawdę użyć UUID lub pełnego ciągu hasha. - Steve Pomeroy
Powinieneś udzielić kredytu swoim źródłom ... Zostało to usunięte z następującego artykułu: pocketmagic.net/?p=1662 - Steve Haley
Ten identyfikator jest otwarty na kolizje, jak nie wiesz co. Praktycznie gwarantowane jest to samo na identycznych urządzeniach z tego samego przewoźnika. - Seva Alekseyev
Może się to również zmienić, jeśli urządzenie zostanie uaktualnione. - David Given
Bardzo, bardzo złe rozwiązanie. Testowany na dwóch Nexusach 5 ... Zwróć te same liczby. - GeneralKimi