Czy istnieje unikalny identyfikator urządzenia z Androidem?

Czy urządzenia z Androidem mają unikalny identyfikator, a jeśli tak, jaki jest prosty sposób uzyskania do niego dostępu za pomocą Javy?


person Tyler    schedule 07.05.2010    source źródło
comment
Jeśli używasz ANDROID_ID, przeczytaj tę odpowiedź i ten błąd.   -  person Dheeraj Vepakomma    schedule 16.01.2013
comment
Twoje rozwiązanie jest tutaj : stackoverflow.com/a/63481350/7135685   -  person Mujahid Khan    schedule 19.08.2020


Odpowiedzi (50)


Settings.Secure#ANDROID_ID zwraca identyfikator Androida jako unikatowy dla każdego użytkownika 64-bitowy szesnastkowy strunowy.

import android.provider.Settings.Secure;

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

Przeczytaj także najlepsze praktyki dotyczące unikalnych identyfikatorów: https://developer.android.com/training/articles/user-data-ids

person Anthony Forloney    schedule 07.05.2010
comment
Wiadomo, że czasami jest pusty, udokumentowano, że może się zmienić po przywróceniu ustawień fabrycznych. Używaj na własne ryzyko i można go łatwo zmienić na zrootowanym telefonie. - person Seva Alekseyev; 23.06.2010
comment
Myślę, że musimy uważać na używanie ANDROID_ID w hashu w pierwszej odpowiedzi na temat, ponieważ może nie być ustawiony podczas pierwszego uruchomienia aplikacji, może zostać ustawiony później, a nawet może zmienić się teoretycznie, stąd unikalny identyfikator może się zmienić - person ; 05.02.2011
comment
Pamiętaj, że to rozwiązanie ma ogromne ograniczenia: android-developers. blogspot.com/2011/03/ - person emmby; 08.04.2011
comment
ten ANDROID_ID jest tylko dla karty Android, jeśli możesz uruchomić w telefonie, otrzymasz wartość null, jeśli uruchomisz w karcie, a następnie uzyskasz unikalny identyfikator.-Girish - person Girish Patel; 30.09.2011
comment
ANDROID_ID nie identyfikuje już jednoznacznie urządzenia (od 4.2): stackoverflow.com/a/13465373/150016 - person Tom; 15.12.2012
comment
Wygląda na to, że może się to również zmienić, jeśli użytkownik wyczyści dane z pamięci podręcznej Usług Play. androidpolice.com/2013/11/20/ wskazówki dotyczące Zmienia to podstawowy identyfikator, według którego Google zna Twoje urządzenie. Jeśli chodzi o serwery, urządzenie zostało w zasadzie zresetowane do ustawień fabrycznych. zakładam, że ANDROID_ID - nie mogę tego powtórzyć w testach - warto być tego świadomym... - person Dori; 06.03.2014
comment
Salaam. spójrz na @Joe odpowiedź http://stackoverflow.com/a/2853253/1676736 - person Sayed Abolfazl Fatemi; 09.07.2014
comment
Używanie getString do uzyskiwania identyfikatorów urządzeń nie jest zalecane. DLACZEGO? - person Iman Marashi; 06.04.2017
comment
Android O zmieni ten android-developers.googleblog.com/2017/04/ - person EpicPandaForce; 12.04.2017
comment
Używam Android ID w mojej aplikacji, aby jednoznacznie identyfikować użytkowników, ponieważ uważam, że jest to łatwiejsze niż rutynowa rejestracja z identyfikatorem e-mail, i jak dotąd nie znalazłem żadnych problemów z tym rozwiązaniem, żaden z naszych subskrybentów do tej pory nie narzekał, i wiemy, że opcja powrotu nie będzie tak niszczycielska, jeśli to się powtórzy, wszystko zależy od rodzaju aplikacji, chyba że aplikacja wymaga ścisłych zabezpieczeń Myślę, że ANDROID ID może nie być problemem - person Naga; 22.02.2019
comment
Android Lint mówi, że używanie getString do uzyskiwania identyfikatorów urządzeń nie jest zalecane. Informacje dotyczące kontroli:Używanie tych identyfikatorów urządzeń nie jest zalecane z wyjątkiem celów związanych z zapobieganiem oszustwom o dużej wartości i zaawansowanymi przypadkami użycia telefonii. W przypadku zastosowań reklamowych użyj AdvertisingIdClient$Info#getId, a do analizy użyj InstanceId#getId. - person Malwinder Singh; 24.07.2019
comment
@AaronUllal przepraszam trochę za późno, nie, nie sądzę, w ustawieniach O telefonie są takie rzeczy, jak wersja Androida, imei itp., W jednym z telefonów z Androidem, które sprawdziłem, może to nie jest tak istotne dla użytkowników niż dla aplikacji - person Naga; 03.09.2019
comment
Jaka jest wersja 2020 odpowiedzi na to pytanie? Z pewnością wszystko się zmieniło. - person André; 24.07.2020
comment
Ten identyfikator zmienia się wraz ze zmianą pliku keystore. Szukałem czegoś bardziej wyjątkowego. Identyfikator, który pozostaje stały dla jednego urządzenia. - person Syed Arsalan Kazmi; 20.11.2020
comment
@SyedArsalanKazmi wybrałem token fcm - person famfamfam; 05.03.2021

AKTUALIZACJA: od najnowszych wersji Androida wiele problemów z ANDROID_ID zostało rozwiązanych i uważam, że takie podejście nie jest już potrzebne. Zapoznaj się z odpowiedzią Anthony'ego.

Pełne ujawnienie: moja aplikacja pierwotnie korzystała z poniższego podejścia, ale nie korzysta już z tego podejścia, a teraz używamy podejścia opisanego w Blog dla programistów Androida, do którego prowadzi odpowiedź Emmby (mianowicie , generując i zapisując UUID#randomUUID()).


Istnieje wiele odpowiedzi na to pytanie, z których większość będzie działać tylko przez pewien czas, ale 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 testowane 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 zwracały tę samą wartość (lub pochodną tej samej wartości) zarówno dla ANDROID_ID, jak i TelephonyManager.getDeviceId() -- o ile konto Google zostało dodane podczas konfiguracji.
  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.

Jeśli więc potrzebujesz czegoś unikalnego dla samego urządzenia, TM.getDeviceId() powinno wystarczyć. Oczywiście niektórzy użytkownicy są bardziej paranoiczni niż inni, więc warto zahaszować co najmniej 1 z tych identyfikatorów, aby ciąg był nadal praktycznie unikalny dla urządzenia, ale nie identyfikował bezpośrednio rzeczywistego urządzenia użytkownika. Na przykład używając String.hashCode() w połączeniu z identyfikatorem 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 skutkować czymś takim jak: 00000000-54b3-e7c7-0000-000046bffd97

U mnie działa wystarczająco dobrze.

Jak wspomina Richard poniżej, nie zapomnij, że potrzebujesz uprawnień do odczytu właściwości TelephonyManager, więc 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;
person Joe    schedule 17.05.2010
comment
Identyfikator oparty na telefonii nie będzie dostępny na tabletach, prawda? - person Seva Alekseyev; 23.06.2010
comment
Dlatego powiedziałem, że większość nie będzie działać cały czas :) Nie spotkałem się jeszcze z odpowiedzią na to pytanie, która byłaby niezawodna dla wszystkich urządzeń, wszystkich typów urządzeń i wszystkich konfiguracji sprzętowych. Dlatego to pytanie jest tutaj na początku. Jest całkiem jasne, że nie ma na to ostatecznego rozwiązania. Poszczególni producenci urządzeń mogą mieć numery seryjne urządzeń, ale nie są one dla nas udostępniane i nie jest to wymagane. W ten sposób zostajemy z tym, co jest dla nas dostępne. - person Joe; 29.06.2010
comment
Czy zaktualizujesz swoją odpowiedź po dalszych testach? To byłoby całkiem interesujące. - person liori; 31.01.2011
comment
Przykładowy kod 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. - person Richard; 28.02.2011
comment
Pamiętaj, że to rozwiązanie ma ogromne ograniczenia: android-developers. blogspot.com/2011/03/ - person emmby; 08.04.2011
comment
FYI, TelephonyManager.getDeviceId() zwraca prawidłowy unikalny identyfikator na moim Xoom, więc wydaje się, że działa to również na tabletach. - person MusiGenesis; 21.04.2011
comment
Ta odpowiedź jest nieaktualna i nie należy jej używać. Nie śledź urządzeń, śledź instalacje! - person softarn; 17.07.2011
comment
@softarn: Uważam, że masz na myśli blog dla programistów Androida, do którego emmby jest już powiązany, co wyjaśnia, co próbujesz powiedzieć, więc być może zamiast tego powinieneś był po prostu zagłosować na jego komentarz. Tak czy inaczej, jak wspomina emmby w swojej odpowiedzi, nadal są problemy nawet z informacjami na blogu. Pytanie dotyczy unikalnego identyfikatora URZĄDZENIA (nie identyfikatora instalacji), więc nie zgadzam się z Twoim stwierdzeniem. Blog zakłada, że ​​chcesz niekoniecznie śledzić urządzenia, podczas gdy pytanie dotyczy właśnie tego. Zgadzam się z blogiem inaczej. - person Joe; 22.07.2011
comment
Myślę, że w tej metodzie jest jedna poważna wada. Zależy to od informacji o karcie SIM, użytkownicy czasami przełączają się w tryb samolotowy = brak podłączonej karty SIM. W tym scenariuszu musisz mieć mechanizm awaryjny, prawdopodobnie do pobrania identyfikatora Androida. - person Daniel Novak; 04.08.2011
comment
@Daniel Novak: uczciwy punkt. W moim przypadku nie miało to znaczenia, ponieważ identyfikator jest używany w komunikacji API, więc tryb samolotowy = brak aplikacji :) Zaprojektowaliśmy to również w ten sposób, aby np. w przypadku zamiany karty SIM, celowo chcieliśmy uzyskać identyfikator urządzenia być innym. Oczywiście nie dotyczy to wszystkich, więc dziękuję za wskazanie tego. - person Joe; 22.08.2011
comment
Trochę się dziwię, że nikt jeszcze tego nie podniósł, ale przykładowy kod może być naprawdę niefortunny w niektórych okolicznościach - zwróci inny identyfikator w zależności od tego, czy telefon jest na przykład w trybie samolotowym, czy nie, ponieważ simSerialNumber będzie null, jeśli sieć GSM urządzenia jest wyłączona. Jeśli masz aplikację, która opiera się na unikalnym identyfikatorze, ale potrzebuje tylko Internetu, niekoniecznie sieci, najlepiej jest upewnić się, że kod zawsze zwraca ten sam identyfikator, niezależnie od bieżącego stanu sieci telefonu. - person Mathias; 20.12.2011
comment
Używam tego kodu przez 6 miesięcy. Nie generuje unikalnego identyfikatora. Nie polecam wszystkim używać tego kodu. Obecnie używam kodu z tego posta: stackoverflow.com/a/17625641/365229 - person Behrouz.M; 18.06.2015
comment
Zdecydowanie polecam nie używać tego kodu. Ma kilka krytycznych błędów: po pierwsze, nie ma gwarancji, że zarówno telefonia, jak i identyfikator Androida istnieją, a jeśli oba nie istnieją, twoje urządzenia zostaną zmapowane zgodnie z samym ich modelem. Po drugie, co ważniejsze, gdy używasz kodu skrótu identyfikatora Androida, zamieniasz 64-bitową reprezentację liczby na 32-bitową liczbę, a tym samym tracisz wiele z niepowtarzalności. - person lavuy; 30.07.2015
comment
Identyfikator IMEI nie może już działać na Androidzie 10 i nowszych - person abss; 13.07.2021

#Ostatnia aktualizacja: 6/2/15


Po przeczytaniu każdego postu Stack Overflow o tworzeniu unikalnego identyfikatora, blogu 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 na ŚLEDZENIE UŻYTKOWNIKÓW
  • W przypadku SPRZĘTU ŚLEDZĄCEGO jest to świetny pomysł

Oprogramowanie

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

#Ogólny podział na Androida

###- Gwarancja unikatowości (w tym urządzenia zrootowane) dla API ›= 9/10 (99,5% urządzeń z Androidem) ###- Brak dodatkowych uprawnień

Pseudonim kod:

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ękujemy @stansult za opublikowanie wszystkich naszych opcji (w tym pytaniu Stack Overflow).

##Lista opcji – powody/dlaczego ich nie używać:

  • E-mail użytkownika – oprogramowanie

  • Użytkownik może zmienić adres 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)

  • 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, wymaga android.permission.READ_PHONE_STATE)

  • Większość użytkowników nienawidzi faktu, że w pozwoleniu jest napisane Rozmowy telefoniczne. Niektórzy użytkownicy wystawiają złe oceny, ponieważ uważają, że po prostu kradniesz ich dane osobowe, podczas gdy tak naprawdę chcesz tylko śledzić instalacje urządzeń. To oczywiste, że zbierasz dane.

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

  • Identyfikator Androida – sprzęt (może być pusty, można go zmienić po przywróceniu ustawień fabrycznych, można go zmienić na zrootowanym urządzeniu)

  • Ponieważ może być „null”, możemy sprawdzić „null” i zmienić jego wartość, ale to oznacza, że ​​nie będzie już unikalny.

  • Jeśli masz użytkownika z urządzeniem z przywróconymi ustawieniami fabrycznymi, wartość mogła zostać zmieniona lub zmieniona na zrootowanym urządzeniu, więc w przypadku śledzenia instalacji użytkowników mogą pojawić się zduplikowane wpisy.

  • Adres MAC WLAN — sprzęt (wymaga android.permission.ACCESS_WIFI_STATE)

  • To może być druga najlepsza opcja, ale nadal zbierasz 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 dostępnych na rynku nie korzysta z Bluetooth, więc jeśli Twoja aplikacja nie korzysta z Bluetooth, a Ty to włączysz, użytkownik może stać się podejrzany.

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

  • Pseudounikalny identyfikator — oprogramowanie (dla wszystkich urządzeń z systemem Android)

  • Bardzo możliwe, może zawierać kolizje - zobacz moją metodę zamieszczoną poniżej!

  • Pozwala to na posiadanie „prawie unikalnego” identyfikatora użytkownika bez pobierania niczego, co jest prywatne. Możesz utworzyć swój własny anonimowy identyfikator na podstawie informacji o urządzeniu.


Wiem, że nie ma żadnego „doskonałego” sposobu na uzyskanie unikalnego identyfikatora bez użycia uprawnień; jednak czasami naprawdę wystarczy tylko śledzić instalację urządzenia. Jeśli chodzi o tworzenie unikalnego identyfikatora, możemy utworzyć „pseudounikalny identyfikator” oparty wyłącznie na informacjach przekazanych nam przez interfejs API Androida bez korzystania z dodatkowych uprawnień. W ten sposób możemy okazać szacunek użytkownikom i spróbować zapewnić użytkownikom dobre wrażenia.

Z pseudo-unikalnym identyfikatorem naprawdę natrafiasz na fakt, że mogą istnieć duplikaty na podstawie faktu, że istnieją podobne urządzenia. Możesz dostosować połączoną metodę, aby była bardziej wyjątkowa; jednak niektórzy programiści muszą śledzić instalacje urządzeń, a to załatwi sprawę lub wydajność w oparciu o podobne urządzenia.

##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”.

PAMIĘTAJ, technicznie tracisz 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; miejmy nadzieję, że nie przywrócili ustawień fabrycznych, a ich „Secure.ANDROID_ID” zostanie zachowany lub nie będzie „null”. (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ższy niż API 9 (niższy niż Gingerbread), zresetował swoje urządzenie lub „Secure.ANDROID_ID” zwróci „null”, wtedy po prostu zwrócony identyfikator będzie oparty wyłącznie na informacjach o urządzeniu z Androidem . To tutaj mogą się zdarzyć kolizje.

Zmiany:

  • Usunięto „Android.SECURE_ID”, ponieważ przywrócenie ustawień fabrycznych może spowodować zmianę wartości
  • Edytowano kod do zmiany w API
  • Zmieniono pseudonim

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 ORAZ Usług Google Play):

Z konsoli programisty Google Play:

Od 1 sierpnia 2014 r. Zasady programu dla programistów w Google Play wymagają przesyłania i aktualizowania zupełnie nowych aplikacji, aby w celach reklamowych zamiast innych trwałych identyfikatorów używać identyfikatora wyświetlania reklam. Ucz się więcej

Wdrożenie:

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:

W zamierzeniu identyfikator wyświetlania reklam całkowicie zastępuje 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 zgłoszenie GooglePlayServicesNotAvailableException 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 uzyskałem informacje. Jeśli czegoś brakuje i musisz być uwzględniony, prosimy o komentarz!

Identyfikator instancji usług odtwarzacza Google

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

person Jared Burrows    schedule 12.07.2013
comment
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 dla 5 ID i ponad 30 dla prawie 30 ID. najczęściej powtarzanymi identyfikatorami są 'ffffffff-fc8f-6093-ffff-ffffd8' (159 rekordów) i 'ffffffff-fe99-b334-ffff-ffffef' (154 razy). również biorąc pod uwagę czas i komentarze, oczywiste jest, że istnieją różne narody. łączna liczba dotychczasowych rekordów wynosi 10 000. daj mi znać, dlaczego tak się stało. czołgi. - person hojjat reyhane; 17.03.2015
comment
Napisałem to ponad 1,5 roku temu. Nie jestem pewien, dlaczego nie jest dla Ciebie wyjątkowy. Możesz wypróbować identyfikator wyświetlania reklam. Jeśli nie, możesz wymyślić własne rozwiązanie. - person Jared Burrows; 17.03.2015
comment
tak jakby..Byłbym naprawdę wdzięczny, jeśli przejdziesz przez pytanie i podzielisz się swoimi przemyśleniami na ten temat - person Durai Amuthan.H; 29.04.2015
comment
@ użytkownik1587329 Dziękuję. Staram się, aby to było aktualne dla wszystkich. To pytanie jest trudne, jeśli chodzi o sprzęt, oprogramowanie i wiele platform. - person Jared Burrows; 06.05.2015

Jak wspomina Dave Webb, Blog dla programistów Androida zawiera artykuł który to obejmuje. Preferowanym przez nich rozwiązaniem jest śledzenie instalacji aplikacji, a nie urządzeń, co sprawdzi się w większości przypadków użycia. Post na blogu pokaże Ci niezbędny kod, aby to zadziałało, i polecam to sprawdzić.

Jednak wpis 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, na wypadek gdybyś musiał to zrobić. Oto, co odkryłem o identyfikatorach urządzeń, które NIE są wymienione we wspomnianym poście na blogu:

  • ANDROID_ID to preferowany identyfikator urządzenia. ANDROID_ID jest całkowicie niezawodny w wersjach Androida ‹=2.1 lub >=2.3. Tylko 2.2 ma problemy wymienione we wpisie.
  • Kilka urządzeń kilku producentów jest dotkniętych błędem ANDROID_ID w 2.2.
  • 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 naprawili ten problem dla wielu lub większości swoich urządzeń, ale udało mi się zweryfikować, że przynajmniej na początku kwietnia 2011 r. nadal dość łatwo jest znaleźć urządzenia z uszkodzonym ANDROID_ID.

W oparciu o zalecenia Google zaimplementowałem klasę, która będzie generować unikalny UUID dla każdego urządzenia, używając ANDROID_ID jako seeda tam, gdzie to konieczne, korzystając w razie potrzeby z TelephonyManager.getDeviceId(), a jeśli to się nie powiedzie, uciekając się do losowo wygenerowanego unikalnego UUID który jest utrwalany po ponownym uruchomieniu aplikacji (ale nie ponownych instalacji aplikacji).

Pamiętaj, że w przypadku urządzeń, które muszą korzystać z identyfikatora urządzenia, unikalny identyfikator BĘDZIE obowiązywał podczas przywracania ustawień fabrycznych. To jest 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ć 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, 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;
    }
}
person emmby    schedule 11.04.2011
comment
Czy nie powinieneś haszować różnych identyfikatorów, aby wszystkie miały ten sam rozmiar? Dodatkowo należy zahaszować identyfikator urządzenia, aby przypadkowo nie ujawnić prywatnych informacji. - person Steve Pomeroy; 12.04.2011
comment
Ponadto urządzenie, którego konfiguracja powoduje użycie identyfikatora urządzenia, powiąże identyfikator z urządzeniem, niekoniecznie z użytkownikiem. Ten identyfikator przetrwa resetowanie do ustawień fabrycznych, co może być potencjalnie złe. Może identyfikator urządzenia mógłby zostać zahaszowany czymś, co zgłasza czas ostatniego resetu do ustawień fabrycznych? - person Steve Pomeroy; 12.04.2011
comment
Dobre punkty, Steve. Zaktualizowałem kod, aby zawsze zwracał UUID. Dzięki temu a) wygenerowane identyfikatory będą zawsze tego samego rozmiaru oraz b) identyfikatory Androida i urządzenia zostaną zahaszowane przed ich zwróceniem, aby uniknąć przypadkowego ujawnienia danych osobowych. Zaktualizowałem również opis, aby zauważyć, że identyfikator urządzenia będzie się utrzymywał po przywróceniu ustawień fabrycznych i że może to nie być pożądane dla niektórych użytkowników. - person emmby; 12.04.2011
comment
Uważam, ż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ż ten w poście na blogu i nie jest dla mnie oczywiste, że wnosi jakąkolwiek wartość. - person Tim Bray; 12.04.2011
comment
Dobra uwaga, 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. - person emmby; 12.04.2011
comment
ANDROID_ID może się zmienić po przywróceniu ustawień fabrycznych, więc nie może również identyfikować urządzeń - person Samuel; 19.05.2011
comment
Jak zauważam w tej samej odpowiedzi, tutaj jest nie ma gwarancji, że otrzymasz ten sam wygenerowany UUID we wszystkich procesach - kopia SharedPrefs jest lokalna ! - person Mr_and_Mrs_D; 18.09.2013

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

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 połączysz to ze strategią tworzenia kopii zapasowych, aby wysłać preferencje do chmury (opisane również w talk, powinieneś mieć identyfikator, który jest powiązany z użytkownikiem i pozostaje w pobliżu po wyczyszczeniu lub nawet wymianie urządzenia. Planuję użyć tego w analityce idę dalej (innymi słowy, jeszcze tego nie zrobiłem :).

person Anthony Nolan    schedule 28.10.2011
comment
Świetna opcja, jeśli nie chcesz, aby unikalny identyfikator zachował się po odinstalowaniu i ponownej instalacji (np. wydarzenie promocyjne/gra, w której masz trzy szanse na wygraną, kropka). - person Kyle Clegg; 16.05.2012
comment
Prezentacja Meiera opiera się na użyciu Menedżera kopii zapasowych systemu Android, co 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żytkowanie przez Meiera), ponieważ jeśli użytkownik nie wybrał tej opcji, po prostu nie otrzyma kopii zapasowej. Pierwotne pytanie dotyczy jednak generowania unikalnego identyfikatora dla urządzenia, a identyfikator ten jest generowany dla aplikacji, a nie dla instalacji, nie mówiąc już o urządzeniu, a ponieważ zależy to od wybrania przez użytkownika opcja kopii zapasowej, jej zastosowania wykraczające poza preferencje użytkownika (np. w przypadku wersji próbnej ograniczonej czasowo) są ograniczone. - person Carl; 22.12.2012
comment
To nie zadziała w przypadku odinstalowania lub wyczyszczenia danych. - person John Shelley; 02.09.2014
comment
bardzo złe rozwiązanie - person famfamfam; 23.02.2021
comment
Myślę, że to dobre rozwiązanie, na urządzeniu i na serwerze jest unikalny identyfikator na wypadek odinstalowania. Możesz upewnić się, że zapisałeś go w e-mailu klienta, aby się zatrzymał ;-p - person vin shaba; 25.04.2021

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

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

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

Zgłoszono, że jest dostępny, nawet gdy Wi-Fi nie jest podłączony. Jeśli Joe z powyższej odpowiedzi wypróbuje tego na swoich wielu urządzeniach, byłoby miło.

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

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

person Seva Alekseyev    schedule 23.06.2010
comment

Problem polega na tym, że twój XML używa domyślnej przestrzeni nazw, ale XSD określa docelową przestrzeń nazw. Jeśli określisz <BadManifest xmlns="http://www.engagesoftware.com/Schemas/EngageManifest"> w swoim pliku XML, powinieneś zauważyć, że walidator zgłasza błędy zgodnie z oczekiwaniami. W przeciwnym razie, ponieważ nie rozpoznaje przestrzeni nazw XML, po prostu ją ignoruje.

- person ohhorob; 01.11.2010
comment
co z urządzeniami bez Wi-Fi? - person Axarydax; 22.12.2010
comment
Wiem, że to pytanie jest stare - ale to świetny pomysł. Użyłem BT mac ID w mojej aplikacji, ale tylko dlatego, że wymaga BT do działania. Pokaż mi urządzenie z Androidem, dla którego warto stworzyć, które NIE ma WiFi. - person Jack; 30.08.2011
comment
Myślę, że przekonasz 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. - person chrisdowney; 22.05.2012
comment
@Sanandrea - spójrzmy prawdzie w oczy, na urządzeniu zrootowanym WSZYSTKO można sfałszować. - person ocodo; 04.09.2013
comment
Jak stwierdził blog Google, MAC nie jest dobrą opcją. Możliwe jest pobranie adresu Mac ze sprzętu Wi-Fi lub Bluetooth urządzenia. Nie zalecamy używania tego jako unikalnego identyfikatora. Na początek nie wszystkie urządzenia mają WiFi. Ponadto, jeśli Wi-Fi nie jest włączone, sprzęt może nie zgłaszać adresu Mac. android-developers.blogspot.com.es/2011/ 03/ - person jiahao; 01.06.2014
comment
Dostęp do adresu MAC Wi-Fi został zablokowany na Androidzie M: stackoverflow.com/questions/31329733/ - person breez; 22.12.2015
comment
Przede wszystkim lokalne adresy MAC Wi-Fi i Bluetooth nie są już dostępne. Metoda getMacAddress() obiektu aWifiInfo i metoda BluetoothAdapter.getDefaultAdapter().getAddress() od teraz zwrócą 02:00:00:00:00:00 - person sarika kate; 30.03.2016
comment
niektóre urządzenia mogą nie mieć wi-fi (osobiście doświadczony) - person Alberto M; 31.05.2016
comment
Z Androida 6.x zwraca spójny fałszywy adres mac: 02:00:00:00:00:00 - person Behrouz.M; 10.07.2016
comment
Android 10+ randomizuj adres mac, więc nie polecam tego rozwiązania - person Hari Shankar S; 09.11.2020

Przydatne informacje znajdziesz tutaj.

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

  1. IMEI (tylko dla urządzeń z Androidem z telefonem; wymaga android.permission.READ_PHONE_STATE)
  2. Pseudounikalny identyfikator (dla wszystkich urządzeń z Androidem)
  3. Identyfikator Androida (może być pusty, można go zmienić po przywróceniu ustawień fabrycznych, można go zmienić na zrootowanym telefonie)
  4. Ciąg Adres MAC WLAN (wymaga android.permission.ACCESS_WIFI_STATE)
  5. Ciąg Adres MAC BT (urządzenia z Bluetooth, wymaga android.permission.BLUETOOTH)
person stansult    schedule 08.02.2012
comment
Ważny punkt pominięty (tu i w artykule): nie można uzyskać WLAN lub BT MAC, jeśli nie są włączone! W przeciwnym razie uważam, że WLAN MAC byłby idealnym identyfikatorem. Nie masz gwarancji, że użytkownik kiedykolwiek włączy swoją sieć Wi-Fi i nie sądzę, by „właściwe” było włączanie jej samemu. - person Tom; 08.10.2012
comment
@Tom jesteś w błędzie. Nadal możesz czytać WLAN lub BT MAC, nawet gdy są wyłączone. Nie ma jednak gwarancji, że urządzenie ma dostępne moduły WLAN lub BT. - person Marqs; 04.08.2014
comment
Przede wszystkim lokalne adresy MAC Wi-Fi i Bluetooth nie są już dostępne. Metoda getMacAddress() obiektu aWifiInfo i metoda BluetoothAdapter.getDefaultAdapter().getAddress() od teraz zwrócą 02:00:00:00:00:00 - person sarika kate; 30.03.2016
comment
@sarikakate To prawda tylko w wersji 6.0 Marshmallow i nowszych... Nadal działa zgodnie z oczekiwaniami w wersji poniżej 6.0 Marshmallow. - person Smeet; 13.04.2016

To proste pytanie, bez prostej odpowiedzi.

Co więcej, wszystkie istniejące odpowiedzi 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 dla urządzeń innych niż Google (wszystko oprócz Pixels i Nexuses), 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 (identyfikator Androida), IMEI, adres MAC itp...

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

Jako przykład CVE-2018-9489, który ma wpływ na wszystkie wymienione powyżej techniki oparte na sieci WIFI.

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

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

Wiele innych odpowiedzi sugeruje użycie AdvertisingIdClient, który jest również niezgodny, ponieważ jego konstrukcja powinna być używana tylko do profilowania reklam. Jest to również opisane w oficjalnym dokumencie

Używaj identyfikatora wyświetlania reklam tylko do profilowania użytkowników lub przypadków użycia reklam

Nie tylko nie sprawdza się w identyfikacji urządzenia, ale musisz też przestrzegać Prywatność użytkownika w odniesieniu do polityki śledzenia reklam, która wyraźnie stwierdza, że ​​użytkownik może ją zresetować lub zablokować w dowolnym momencie.

Więc nie używaj go też.

Ponieważ nie możesz mieć pożądanego statycznego globalnie unikalnego i niezawodnego identyfikatora urządzenia. Oficjalne odniesienie Androida sugeruje:

Używaj FirebaseInstanceId lub prywatnie przechowywanego identyfikatora GUID we wszystkich innych przypadkach użycia, z wyjątkiem zapobiegania oszustwom płatniczym i telefonii.

Jest unikalny dla instalacji aplikacji na urządzeniu, więc po odinstalowaniu aplikacji przez użytkownika jest ona wymazana, więc nie jest w 100% niezawodna, ale jest następną najlepszą rzeczą.

Aby użyć FirebaseInstanceId, dodaj najnowszą zależność wiadomości Firebase do swojego Gradle

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

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

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

Jeśli chcesz przechowywać identyfikator urządzenia na zdalnym serwerze, nie przechowuj go bez zmian (zwykły tekst), ale hasz z solą.

Dziś jest to nie tylko najlepsza praktyka, musisz to robić zgodnie z prawem, zgodnie z RODO - identyfikatory i podobne przepisy.

person Nikita Kurtin    schedule 28.11.2019
comment
Na razie to najlepsza odpowiedź, a pierwsze zdanie jest najlepszym podsumowaniem: To proste pytanie, bez prostej odpowiedzi – po prostu kochaj. - person b2mob; 22.01.2020
comment
@M.UsmanKhan, odpowiedź jest napisana zaraz po tym: Dziś to nie tylko najlepsza praktyka, właściwie musisz to robić zgodnie z prawem zgodnie z RODO - identyfikatory i podobne przepisy. - person Nikita Kurtin; 08.03.2020
comment
Czy możesz określić, która sekcja linku RODO, który opublikowałeś, faktycznie wspomina o wymogu hashowania identyfikatorów? - person David Schneider; 21.07.2020
comment
@DavidSchneider treść internetowa ma charakter dynamiczny, a RODO jest tylko jednym z przykładów, pamiętaj, że napisałem RODO i podobne przepisy , ponieważ istnieje wiele lokalnych i globalnych przepisów, które mają wpływ na Twoje produkt / system / pole. W każdym razie sekcje RODO, których szukasz to: Identyfikacja, Identyfikatory online i Zasady ochrony danych - person Nikita Kurtin; 21.07.2020
comment
proandroiddev.com/ - person william gouvea; 03.01.2021
comment
Unikalny identyfikator Firebase zmieni się, jeśli aplikacja zostanie ponownie zainstalowana - person famfamfam; 23.02.2021
comment
@famfamfam dokładnie - dlatego napisałem, że: Jest unikalny dla instalacji aplikacji na urządzeniu, więc gdy użytkownik odinstaluje aplikację - jest wymazany, więc nie jest w 100% niezawodny, ale to kolejna najlepsza rzecz . - person Nikita Kurtin; 25.02.2021
comment
dzięki, zastanawiam się, dlaczego Android nie może utworzyć ANDROID_ID na urządzeniu uuid, co utrudni kod programisty Androida - person famfamfam; 25.02.2021
comment
@famfamfam Domyślam się, że wynika to z otwartej natury Androida i pseudolosowej platformy Javy UUID.randomUUID() zależnej od czasu. - person Nikita Kurtin; 25.02.2021
comment
Czekaj, czy nie ma wielu okoliczności, które spowodowałyby zmianę z jednej wartości na drugą? - person Michael Paccione; 03.07.2021

Oficjalny blog programistów Androida zawiera teraz pełny artykuł właśnie na ten temat, Identyfikowanie Instalacje aplikacji.

person BoD    schedule 06.04.2011
comment
A kluczowym punktem tego argumentu jest to, że jeśli próbujesz uzyskać unikalny identyfikator ze sprzętu, prawdopodobnie popełniasz błąd. - person Tim Bray; 12.04.2011
comment
A jeśli zezwalasz na zresetowanie blokady urządzenia przez przywrócenie ustawień fabrycznych, Twój model wersji próbnej jest prawie martwy. - person Seva Alekseyev; 04.05.2011
comment
A post na blogu zawiera już linki do tej witryny: developer.android.com/training/ artykuły/identyfikatory-danych-użytkowników - person Bruno Bieri; 16.09.2020

Na Google I/O Reto Meier opublikował solidną odpowiedź na to, jak podejść do tego, co powinno spełnić większość potrzeb programistów do śledzenia użytkowników w różnych instalacjach. Anthony Nolan pokazuje kierunek w swojej odpowiedzi, ale pomyślałem, że napiszę całe 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 (w oparciu o główne konto Google) i podczas instalacji. 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 SharedPreferences za pomocą usługi Android Backup Service. Zacznij od zarejestrowania aplikacji przez http://developer.android.com/google/backup/signup.html.

Google przekaże Ci zapasowy klucz usługi, który musisz dodać do manifestu. Musisz również powiedzieć aplikacji, aby używała 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 ukończyć tworzenie kopii zapasowej, musisz utworzyć instancję BackupManager w swojej głównej czynnoś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 identyfikator użytkownika będzie teraz trwały we wszystkich instalacjach, nawet jeśli użytkownik przeniesie urządzenie.

Więcej informacji na temat tego podejścia można znaleźć na stronie Rozmowa Reto.

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

person TechnoTony    schedule 22.12.2012
comment
Czy nie prowadzi to do wielu urządzeń o tym samym identyfikatorze, gdy użytkownik ma wiele urządzeń? Na przykład tablet i telefon. - person Tosa; 13.03.2013

Myślę, że to na pewno ognisty sposób na zbudowanie 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 włączać uprawnienia READ_PHONE_STATE. Nadal możesz odczytać szczegóły, takie jak wersja ROM, nazwa producenta, typ procesora i inne szczegóły dotyczące sprzętu, które będą dobrze dopasowane, jeśli chcesz użyć identyfikatora do sprawdzenia 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 (na podstawie tego samego sprzętu i obrazu ROM), ale zmiany w rzeczywistych aplikacjach są znikome. 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ść elementów Build to łańcuchy, co robimy tutaj, to bierzemy ich długość i przekształcamy ją za pomocą modulo w cyfrę. Mamy 13 takich cyfr i dodajemy kolejne dwie z przodu (35), aby mieć taki sam identyfikator rozmiaru jak IMEI (15 cyfr). Są tu inne możliwości, dobrze, spójrz tylko na te struny. Zwraca coś takiego jak 355715565309247. Nie jest wymagane żadne specjalne zezwolenie, dzięki czemu takie podejście jest bardzo wygodne.


(Dodatkowe informacje: technika podana powyżej została skopiowana z artykułu na Magia kieszonkowa).

person Lenn Dolling    schedule 24.03.2011
comment
Ciekawe rozwiązanie. Wygląda na to, że jest to sytuacja, w której naprawdę powinieneś po prostu haszować wszystkie połączone dane, zamiast próbować wymyślić własną funkcję haszującą. Istnieje wiele przypadków, w których doszłoby do kolizji, nawet jeśli istnieją znaczne dane, które są różne dla każdej wartości. Moja rekomendacja: użyj funkcji haszującej, a następnie przekształć wyniki binarne na dziesiętne i skróć je w razie potrzeby. Aby zrobić to dobrze, naprawdę powinieneś użyć UUID lub pełnego ciągu skrótu. - person Steve Pomeroy; 12.04.2011
comment
Odkryłem, że Build.CPU_ABI i Build.MANUFACTURER nie są obecne we wszystkich wersjach.. Podczas pracy z ‹2.2 pojawiały się ostre błędy kompilacji :) - person Lenn Dolling; 15.05.2011
comment
Powinieneś podać uznanie dla swoich źródeł... Zostało to wyjęte prosto z następującego artykułu: pocketmagic. netto/?p=1662 - person Steve Haley; 16.05.2011
comment
Ten identyfikator jest otwarty na kolizje, jak nie wiesz co. Praktycznie gwarantuje się, że będzie taki sam na identycznych urządzeniach tego samego operatora. - person Seva Alekseyev; 27.05.2011
comment
Może się to również zmienić, jeśli urządzenie zostanie zaktualizowane. - person David Given; 25.01.2012
comment
Nie sądzę, żeby to był dobry pomysł. Jak rozumiem, wszystkie pola Build będą takie same dla wszystkich telefonów wyprodukowanych razem. - person Victor Ronin; 26.07.2012
comment
Według komentarza Davida Givena wydaje się to być poważnym problemem. Należy dokładnie sporządzić inwentaryzację atrybutów kompilacji, aby określić, które z nich prawdopodobnie nie ulegną zmianie w wyniku bezprzewodowej aktualizacji. Na przykład, Build.DISPLAY powyżej, zgodnie z dokumentacją Javadoc, jest ciągiem identyfikatora kompilacji przeznaczonym do wyświetlania użytkownikowi, więc czy nie zmieniłoby się to po wystąpieniu aktualizacji? Nadal uważam, że takie podejście mogłoby dodać przydatne atrybuty odróżniające w połączeniu z innymi informacjami z urządzenia, ale tylko wtedy, gdy takie zmienne OTA atrybuty można ostrożnie usunąć. - person Carl; 23.12.2012
comment
Podobnie Build.HOST jest zdefiniowany jako ciąg znaków, który jednoznacznie identyfikuje hosta, na którym kompilacja została ZBUDOWANA, w formacie czytelnym dla człowieka. Wydaje się całkowicie możliwe, że do stworzenia kompilacji aktualizacji OTA można użyć różnych maszyn BUILD. - person Carl; 23.12.2012
comment
Bardzo, bardzo złe rozwiązanie. Testowane na dwóch Nexusach 5... Zwróć te same numery. - person Sinan Dizdarević; 04.03.2015

Poniższy kod zwraca numer seryjny urządzenia przy użyciu 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) {

}
person Roman SL    schedule 25.01.2011

Korzystając z poniższego kodu, możesz uzyskać unikalny identyfikator urządzenia z systemem Android w postaci ciągu.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
person Mohit Kanada    schedule 17.05.2011

Pole Serial zostało dodane do klasy Build na poziomie interfejsu API 9 (Android 2.3 - Piernik). Dokumentacja mówi, że reprezentuje numer seryjny sprzętu. Dlatego powinien być unikalny, jeśli istnieje na urządzeniu.

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

person rony l    schedule 06.03.2011
comment
Niestety nie wiadomo. - person m0skit0; 15.04.2013

Jedno dodam - 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 jest pusty, każdy tablet G zgłasza ten sam numer.

Sprawia, że ​​granie w „Pocket Empires” jest interesujące, co daje natychmiastowy dostęp do czyjegoś konta na podstawie „unikalnego” DeviceID.

Moje urządzenie nie ma radia komórkowego.

person Tony Maro    schedule 21.03.2011
comment
@Treewallie czy to działa? Czy możesz uzyskać ten sam identyfikator urządzenia z różnych aplikacji? - person Arnold Brown; 04.02.2020

Szczegółowe instrukcje, jak uzyskać unikalny identyfikator dla każdego urządzenia z Androidem, na którym jest zainstalowana Twoja aplikacja, znajdziesz na oficjalnym blogu programistów aplikacji na Androida, który znajduje się Identyfikowanie instalacji aplikacji.

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

Osobiście uważam to za dopuszczalne, ale nie idealne. Żaden identyfikator dostarczony przez Androida nie działa we wszystkich przypadkach, ponieważ większość z nich jest zależna od stanów radiowych telefonu (wł./wył. Wi-Fi, wł./wył. sieci komórkowej, wł./wył. Bluetooth). Pozostałe, takie jak Settings.Secure.ANDROID_ID, muszą być zaimplementowane przez producenta i nie ma gwarancji, że będą unikatowe.

Poniżej znajduje się przykład zapisywania danych do pliku instalacyjnego, który byłby przechowywany wraz z innymi danymi, które aplikacja zapisuje lokalnie.

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();
    }
}
person Kevin Parker    schedule 02.08.2011
comment
Jeśli chcesz śledzić instalacje aplikacji, jest to idealne rozwiązanie. Urządzenia śledzące są jednak o wiele trudniejsze i nie wydaje się, aby było to całkowicie hermetyczne rozwiązanie. - person Luca Spiller; 03.10.2011
comment
A co z urządzeniami zrootowanymi? Mogą łatwo zmienić ten identyfikator instalacji, prawda? - person tasomaniac; 10.05.2012
comment
Absolutnie. Root może zmienić identyfikator instalacji. Możesz sprawdzić root, używając tego bloku kodu: stackoverflow.com/questions/1101380/ - person Kevin Parker; 18.05.2012
comment
jeśli przywrócimy ustawienia fabryczne, czy plik zostanie usunięty? - person Jamshid; 08.01.2015
comment
Jeśli przywrócisz ustawienia fabryczne i usuniesz lub sformatujesz partycję /data, identyfikator UUID jest inny. - person Kevin Parker; 12.01.2015

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 AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
person Android    schedule 27.02.2013

Istnieje wiele różnych podejść do obejścia tych ANDROID_ID problemów (może być null czasami lub urządzenia określonego modelu zawsze zwracają ten sam identyfikator) z zaletami i wadami:

  • Implementacja niestandardowego algorytmu generowania identyfikatorów (w oparciu o właściwości urządzenia, które mają być statyczne i nie ulegną zmianie -> kto wie)
  • Nadużywanie innych identyfikatorów, takich jak IMEI, numer seryjny, adres Wi-Fi/Bluetooth-MAC nie istnieje na wszystkich urządzeniach lub konieczne są dodatkowe uprawnienia)

Osobiście wolę używać istniejącej implementacji OpenUDID (patrz https://github.com/ylechelle/OpenUDID) dla Android (patrz https://github.com/vieux/OpenUDID). Jest łatwy do zintegrowania i wykorzystuje ANDROID_ID z rozwiązaniami awaryjnymi dla wyżej wymienionych problemów.

person Andreas Klöber    schedule 18.11.2012

Unikalny identyfikator urządzenia z systemem operacyjnym Android jako String, używający TelephonyManager i 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 polecam metodę sugerowaną przez Google, zobacz Identyfikowanie Instalacje aplikacji.

person Jorgesys    schedule 13.01.2014

Jest tu ponad 30 odpowiedzi, a niektóre są takie same, a niektóre są unikalne. 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. U mnie zadziałało to bardzo dobrze.

3 identyfikatory to:
Pseudo-ID — jest generowany na podstawie fizycznych specyfikacji urządzenia
ANDROID_IDSettings.Secure.ANDROID_ID
Adres Bluetooth - Adres adaptera Bluetooth

Zwróci coś takiego: 551F27C060712A72730B0A0F734064B1

Uwaga: zawsze możesz dodać więcej identyfikatorów do ciągu longId. Na przykład numer seryjny. adres adaptera Wi-Fi. IMEI. W ten sposób sprawisz, że będzie bardziej wyjątkowy na urządzenie.

@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 "";
}
person ᴛʜᴇᴘᴀᴛᴇʟ    schedule 08.03.2017
comment
Dodanie UUID do longId i zapisanie go w pliku sprawi, że będzie to najbardziej unikalny identyfikator : String uuid = UUID.randomUUID().toString(); - person Mousa Alfhaily; 11.04.2017
comment
Jeśli wszystko inne zawiedzie, jeśli użytkownik ma niższy niż API 9 (niższy niż Gingerbread), zresetował swój telefon lub „Secure.ANDROID_ID”. jeśli zwróci „null”, to po prostu zwrócony identyfikator będzie oparty wyłącznie na informacjach o urządzeniu z Androidem. To tutaj mogą się zdarzyć kolizje. Staraj się nie używać DISPLAY, HOST lub ID - te elementy mogą się zmienić. W przypadku kolizji dane będą się nakładać. Źródło: gist.github.com/pedja1/fe69e8a80ed505500caa - person Mousa Alfhaily; 11.04.2017
comment
@Ninja Ponieważ adres mac BLE jest unikalny, tak, wygenerowany identyfikator zawsze będzie unikalny. Jeśli jednak naprawdę chcesz mieć pewność, sugeruję dodanie UUID do 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. - person ᴛʜᴇᴘᴀᴛᴇʟ; 03.04.2019

Co powiesz na IMEI. To jest unikalne dla Androida lub innych urządzeń mobilnych.

person Elzo Valugi    schedule 14.07.2011
comment
Nie dla moich tabletów, które nie mają numeru IMEI, ponieważ nie łączą się z moim operatorem komórkowym. - person Brill Pappin; 05.01.2012
comment
Nie wspominając o urządzeniach CDMA, które mają ESN zamiast IMEI. - person David Given; 25.01.2012
comment
Zrobi to tylko wtedy, gdy jest telefonem :) Tablet może nie. - person Brill Pappin; 26.01.2012
comment
@ElzoValugi To już czasy i wciąż nie wszystkie tablety mają karty SIM. - person MLQ; 25.09.2012

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;
}
person Eng.Fouad    schedule 27.05.2013
comment
jeśli używamy ReadPhoneState w wersji 6.0 z prośbą o pozwolenie na wykonanie - person Harsha; 17.11.2016

Moje dwa centy – NB to jest dla unikalnego identyfikatora urządzenia (err) – a nie dla instalacji, jak omówiono w Blog programistów Androida.

Należy zauważyć, że rozwiązanie dostarczone przez @emmby powraca do identyfikatora aplikacji, ponieważ SharedPreferences nie są synchronizowane między procesami (zobacz tutaj i tutaj). Więc całkowicie tego unikałem.

Zamiast tego opisałem różne strategie uzyskiwania identyfikatora (urządzenia) w wyliczeniu — zmiana kolejności stałych wyliczenia wpływa na priorytet różnych sposobów uzyskiwania identyfikatora. Zwracany jest pierwszy identyfikator inny niż null lub zgłaszany jest wyjątek (zgodnie z dobrymi praktykami Javy dotyczącymi nienadawania znaczenia null). Na przykład najpierw mam TELEFONIĘ – ale dobrym domyślnym wyborem będzie 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);
        }
    }
}
person Mr_and_Mrs_D    schedule 18.09.2013

Innym sposobem jest użycie /sys/class/android_usb/android0/iSerial w 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 pamiętaj, aby umieścić go w programie obsługi wyjątków, ponieważ nie wszystkie urządzenia mają ten plik.

Przynajmniej następujące urządzenia są znane z tego, że ten plik jest czytelny na całym świecie:

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

Możesz również zobaczyć mój wpis na blogu Wyciek sprzętu z Androidem numer seryjny do nieuprzywilejowanych aplikacji, gdzie omawiam, jakie inne pliki są dostępne w celach informacyjnych.

person insitusec    schedule 31.01.2013
comment
Właśnie przeczytałem Twój wpis na blogu. Uważam, że nie jest to wyjątkowe: Build.SERIAL jest również dostępny bez żadnych uprawnień i jest (teoretycznie) unikalnym numerem seryjnym sprzętu. - person Tom; 01.05.2013
comment
Masz rację. To jeszcze jeden sposób na śledzenie urządzenia i, jak powiedziałeś, oba te sposoby nie wymagają uprawnień aplikacji. - person insitusec; 14.03.2014

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 zwraca identyfikator Androida jako unikalny 64-bitowy ciąg szesnastkowy.

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

Czasami TelephonyManger.getDeviceId() zwróci null, więc aby zapewnić unikalny identyfikator, użyj 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;
}
person Jorgesys    schedule 06.02.2015
comment
Niedawno odkryłem, że urządzenie klienckie typu SM-G928F / Galaxy S6 edge+ dostarcza tylko 15 zamiast 16 cyfr szesnastkowych dla identyfikatora Androida. - person Holger Jakobs; 13.03.2016

Identyfikator instancji Google

Wydany na I/O 2015; w systemie Android 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żywać tego identyfikatora do identyfikowania instalacji w Androidzie, Chrome i iOS.

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

Zalety identyfikatora instancji

Wydaje mi się, że Google zamierza wykorzystać go do tego celu (identyfikacji twoich instalacji), jest wieloplatformowy i może być używany do wielu innych celów (patrz linki powyżej).

Jeśli używasz GCM, ostatecznie będziesz musiał użyć tego identyfikatora instancji, ponieważ jest on potrzebny do uzyskania tokena GCM (który zastępuje stary identyfikator rejestracji GCM).

Wady/problemy

W obecnej implementacji (GPS 7.5) identyfikator instancji jest pobierany z serwera, gdy aplikacja tego żąda. Oznacza to, że powyższe połączenie jest połączeniem blokującym - w moich nienaukowych testach trwa 1-3 sekundy, jeśli urządzenie jest online i 0,5-1,0 sekundy, jeśli jest offline (przypuszczalnie tyle czasu czeka przed poddaniem się 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żyjesz identyfikatora do celów, do których są przeznaczone – np. uwierzytelnianie aplikacji, identyfikacja aplikacji, GCM – myślę, że te 1-3 sekundy mogą być uciążliwe (oczywiście w zależności od aplikacji).

person Tom    schedule 19.06.2015
comment
kolejną istotną wadą instanceID jest to, że zostanie wygenerowany nowy instanceID, jeśli użytkownik wyczyści dane aplikacji. - person idanakav; 08.07.2015
comment
Interesujące, ale nie sądzę, aby to naprawdę zmieniało potencjalne przypadki użycia: identyfikator instancji, taki jak android_id, nie nadaje się do identyfikacji urządzenia. Dzięki temu Twój serwer będzie widział, jak użytkownik usuwający dane, podobnie jak użytkownik odinstalowujący i ponownie instalujący Twoją aplikację – co nie jest nierozsądne. - person Tom; 08.07.2015

Do rozpoznawania sprzętu konkretnego urządzenia z systemem Android można sprawdzić adresy MAC.

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

w AndroidManifest.xml

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

teraz w twoim kodzie:

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

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

W każdym urządzeniu z Androidem jest to przynajmniej interfejs "wlan0", który jest chipem WI-FI. Ten kod działa nawet wtedy, gdy WI-FI nie jest włączone.

PS Jest to kilka innych interfejsów, które otrzymasz z listy zawierającej MACS, ale może się to zmienić między telefonami.

person Ilan.b    schedule 01.09.2015

Używam następującego kodu, aby uzyskać IMEI lub używać Secure.ANDROID_ID jako alternatywy, gdy urządzenie nie obsługuje 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);
person Asaf Pinhassi    schedule 15.04.2013

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 instancji, identyfikatory GUID, identyfikator SSAID, identyfikator reklamy, interfejs API sieci bezpieczeństwa do weryfikacji urządzeń.

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

person Waheed Nazir    schedule 03.05.2019

Google ma teraz Identyfikator reklamowy.
Może to również być używane, ale pamiętaj, że:

Identyfikator wyświetlania reklam to unikalny, możliwy do zresetowania identyfikator użytkownika

oraz

umożliwia użytkownikom zresetowanie identyfikatora lub rezygnację z reklam opartych na zainteresowaniach w aplikacjach Google Play.

Więc chociaż ten identyfikator może się zmienić, wydaje się, że wkrótce możemy nie mieć wyboru, zależy to od celu tego identyfikatora.

Więcej informacji @ develper.android

Skopiuj i wklej kod tutaj

HTH

person Hertzel Guinness    schedule 02.11.2013
comment
Można go zresetować: identyfikator wyświetlania reklam jest unikalnym, ale możliwym do zresetowania przez użytkownika identyfikatorem ciągu, który umożliwia sieciom reklamowym i innym aplikacjom anonimową identyfikację użytkownika. - person Jared Burrows; 06.11.2013
comment
(@JaredBurrows tak, jest wspomniane w poście...) - person Hertzel Guinness; 06.11.2013

1. Użyj menedżera telefonii, który zapewnia unikalny identyfikator (tj. IMEI). Zobacz przykład,

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

Wymaga to android.permission.READ_PHONE_STATE od użytkownika, co może być trudne do uzasadnienia po typie złożonego wniosku.

  1. Urządzenia bez usług telefonicznych, takie jak tablety, muszą zgłaszać unikalny identyfikator urządzenia, który jest dostępny pod adresem android.os.Build.SERIAL od wersji Androida 2.3 Gingerbread. Niektóre telefony z usługami telefonicznymi mogą również definiować numer seryjny. Ponieważ nie wszystkie urządzenia z Androidem mają numer seryjny, to rozwiązanie nie jest niezawodne.

  2. Podczas pierwszego rozruchu urządzenia generowana i zapisywana jest losowa wartość. Ta wartość jest dostępna poprzez Settings.Secure.ANDROID_ID. Jest to liczba 64-bitowa, która powinna pozostać stała przez cały okres eksploatacji urządzenia. ANDROID_ID wydaje się dobrym wyborem dla unikalnego identyfikatora urządzenia, ponieważ jest dostępny dla smartfonów i tabletów. Aby pobrać wartość, możesz użyć następującego kodu,

    Ciąg androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

Jednak wartość może ulec zmianie, jeśli urządzenie zostanie zresetowane do ustawień fabrycznych. Istnieje również znany błąd dotyczący popularnego telefonu od producenta, w którym każda instancja ma to samo ANDROID_ID. Oczywiście rozwiązanie nie jest w 100% niezawodne.

  1. Użyj identyfikatora UUID. Ponieważ wymogiem dla większości aplikacji jest identyfikacja konkretnej instalacji, a nie urządzenia fizycznego, dobrym rozwiązaniem jest uzyskanie unikalnego identyfikatora dla użytkownika, jeśli używa się klasy UUID. Poniższe rozwiązanie przedstawił Reto Meier z Google w prezentacji Google I/O,
SharedPreferences sharedPrefs = context.getSharedPreferences(
         PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

Aktualizacja : opcje #1 i #2 nie są już dostępne po Androidzie 10 jako aktualizacje prywatności Google. ponieważ opcje 2 i 3 wymagają pozwolenia krytycznego.

person Kiran Maniya    schedule 05.10.2018
comment
Który telefon to ten, w którym każda instancja ma ten sam ANDROID_ID? - person viper; 26.08.2019
comment
zapoznaj się z oficjalnymi dokumentami developer.android.com/reference/ android/dostawca/ - person Kiran Maniya; 26.08.2019
comment
DeviceInfoProvider nie jest częścią pakietu Android SDK - person user924; 06.02.2020
comment
Dzięki, @user924 za wskazanie tego. Jeśli masz dalsze szczegóły, możesz edytować odpowiedź, aby ją poprawić. - person Kiran Maniya; 06.02.2020
comment
@KiranManiya Edytuj swoją zmyśloną odpowiedź. Skąd ludzie mają wiedzieć, jak to edytować, jeśli to wymyśliłeś? To Ty powinieneś go edytować. Nie odpowiadaj tutaj na pytanie swoją iluzją - person jerinho.com; 25.04.2020
comment
@jerinho Wielkie dzięki. Myślę, że przeszedłeś przez obie moje odpowiedzi. - person Kiran Maniya; 26.04.2020

Identyfikator mac urządzenia z Androidem jest również unikalnym identyfikatorem. Nie zmieni się, nawet jeśli samo urządzenie jest sformatowane.

Użyj następującego kodu, aby uzyskać identyfikator mac:

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

Nie zapomnij też dodać odpowiednich uprawnień do pliku AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
person Baskaran Veerabathiran    schedule 03.10.2016
comment
Niestety to nie zadziała, jeśli nie ma aktualnego połączenia Wi-Fi. Z dokumentacji (podkreślenie dodane ): Zwróć dynamiczne informacje o bieżącym połączeniu Wi-Fi, jeśli jakieś jest aktywne. - person Ted Hopp; 05.10.2016
comment
Ponadto, przyznając dostęp do roota na urządzeniu, można sfałszować adres mac - person ; 03.07.2017
comment
Urządzenia z systemem Android 10 (poziom interfejsu API 29) lub nowszym zgłaszają losowe adresy MAC do wszystkich aplikacji, które nie są aplikacjami właściciela urządzenia. Nie będzie to więc unikatowe, jeśli korzystasz z systemu Android w wersji 10 lub nowszej - person Saddan; 23.05.2020

Tylko uwaga dla wszystkich, którzy czytają i szukają bardziej aktualnych informacji. W przypadku Androida O wprowadzono pewne zmiany w sposobie zarządzania tymi identyfikatorami przez system.

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

tl;dr Serial będzie wymagał zezwolenia na TELEFON, a identyfikator Androida zmieni się dla różnych aplikacji, w zależności od ich nazwy pakietu i podpisu.

A także Google przygotował fajny dokument, który zawiera sugestie, kiedy używać identyfikatorów sprzętu i oprogramowania.

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

person bugraoral    schedule 11.04.2017

Zwykle używam unikalnego identyfikatora urządzenia dla moich aplikacji. Ale czasami używam IMEI. Oba są unikalnymi numerami.

aby uzyskać IMEI (międzynarodowy identyfikator sprzętu mobilnego)

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

aby uzyskać unikalny identyfikator urządzenia

public String getDeviceUniqueID(Activity activity){
    String device_unique_id = Secure.getString(activity.getContentResolver(),
            Secure.ANDROID_ID);
    return device_unique_id;
}
person Zin Win Htet    schedule 19.06.2017

Spotkałem się z tym pytaniem kilka lat temu i nauczyłem się wdrażać uogólnione rozwiązanie oparte na różnych odpowiedziach.

Korzystam z uogólnionego rozwiązania od kilku lat, w rzeczywistym produkcie. Jak dotąd służy mi całkiem dobrze. Oto fragment kodu oparty na różnych udzielonych odpowiedziach.

Zauważ, że getEmail zwróci null przez większość czasu, ponieważ nie prosiliśmy wprost o pozwolenie.

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

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

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

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

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

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

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

    return null;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    public final String id;
    public final Type type;
}

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

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

    return null;
} 
person Cheok Yan Cheng    schedule 07.11.2017
comment
Ale czy to działa, gdy użytkownik resetuje swój telefon? w takim przypadku identyfikator Androida ulegnie zmianie, identyfikator reklamowy będzie można zresetować, a także e-mail. - person G3n1t0; 09.03.2021

Niezalecane, ponieważ identyfikator urządzenia może być używany do śledzenia w rękach osób trzecich, ale jest to inny sposób.

@SuppressLint("HardwareIds")
private String getDeviceID() {
    deviceId = Settings.Secure.getString(getApplicationContext().getContentResolver(),
                    Settings.Secure.ANDROID_ID);
    return deviceId;
}
person Ege Kuzubasioglu    schedule 28.12.2017
comment
Android wprowadza pewne zmiany w: Settings.Secure.ANDROID_ID; W systemie Android 8,0 (poziom interfejsu API 26) i nowszych wersjach platformy liczba 64-bitowa (wyrażona jako ciąg szesnastkowy), unikalna dla każdej kombinacji klucza podpisywania aplikacji, użytkownika i urządzenia. Oznacza to, że Settings.Secure.ANDROID_ID zwraca teraz identyfikatory, które są unikalne dla kombinacji aplikacji/urządzenia, co zwiększa bezpieczeństwo użytkownika. - person Jeff Padgett; 22.06.2018

Oto prosta odpowiedź, aby uzyskać AAID, przetestowany poprawnie w czerwcu 2019 r.

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

            return android_id;
        }

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

    };
    task.execute();

przeczytaj szczegółowo pełną odpowiedź tutaj:

person Raj    schedule 11.06.2019

Uzyskaj Device UUID, numer modelu z nazwą marki i jej numer wersji za pomocą poniższej funkcji.

Pracuj w systemie Android 10 doskonale i nie musisz zezwalać na odczyt stanu telefonu.

Fragmenty kodu:

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

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

Zadzwoń do funkcji powyżej i sprawdź dane wyjściowe powyższego kodu. zobacz swojego kota dziennika w Android Studio. Wygląda to jak poniżej:

tu wpisz opis obrazu

person CodeInsideCoffee    schedule 07.06.2020
comment
co to jest %10 i 35+... w twoim kodzie? chodzi mi o to, dlaczego używasz tego podejścia do budowania unikalnego identyfikatora? dlaczego po prostu nie połączyć tych ciągów i wygenerować unikalnego UUID? czy wyniki tej metody są całkowicie unikalne dla wszystkich urządzeń na świecie? - person porya74; 15.06.2020

Aby dołączyć Androida 9, mam tylko jeden pomysł, który może nadal działać, który (prawdopodobnie) nie narusza żadnych warunków, wymaga uprawnień i działa w różnych instalacjach i aplikacjach.

Odcisk palca dotyczący serwera powinien umożliwiać jednoznaczną identyfikację urządzenia. Połączenie informacji o sprzęcie + zainstalowanych aplikacji i czasów instalacji powinno wystarczyć. Czas pierwszej instalacji nie ulega zmianie, chyba że aplikacja zostanie odinstalowana i ponownie zainstalowana. Ale należałoby to zrobić dla wszystkich aplikacji na urządzeniu, aby nie móc zidentyfikować urządzenia (tj. Po przywróceniu ustawień fabrycznych).

Tak bym się do tego zabrał:

  1. Wyodrębnij informacje o sprzęcie, nazwy pakietów aplikacji i czas pierwszej instalacji.

W ten sposób wyodrębniasz wszystkie aplikacje z Androida (nie są potrzebne żadne uprawnienia):

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

for (ApplicationInfo packageInfo : packages) {
    try {
        Log.d(TAG, "Installed package :" + packageInfo.packageName);
        Log.d(TAG, "Installed :" + pm.getPackageInfo(packageInfo.packageName, 0).firstInstallTime);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
}
  1. Możesz chcieć sporządzić skrót każdej kombinacji nazwy pakietu i sygnatury czasowej instalacji przed wysłaniem jej na serwer, ponieważ może to być żadna z Twojej firmy, co użytkownik zainstalował na urządzeniu.
  2. Niektóre aplikacje (w rzeczywistości dużo) to aplikacje systemowe. Prawdopodobnie mają one ten sam znacznik czasu instalacji, zgodny z najnowszą aktualizacją systemu po przywróceniu ustawień fabrycznych. Ponieważ mają tę samą sygnaturę czasową instalacji, nie mogą zostać zainstalowane przez użytkownika i mogą zostać odfiltrowane.
  3. Wyślij informacje na serwer i pozwól mu szukać najbliższego dopasowania wśród wcześniej zapisanych informacji. Musisz określić próg podczas porównywania z wcześniej zapisanymi informacjami o urządzeniu, gdy aplikacje są instalowane i odinstalowywane. Ale domyślam się, że ten próg może być bardzo niski, ponieważ każda kombinacja nazwy pakietu i samego znacznika czasu pierwszej instalacji będzie dość unikalna dla urządzenia, a aplikacje nie są tak często instalowane i odinstalowywane. Posiadanie wielu aplikacji zwiększa prawdopodobieństwo bycia wyjątkowym.
  4. Zwróć wygenerowany unikalny identyfikator dla dopasowania lub wygeneruj unikalny identyfikator, zapisz z informacjami o urządzeniu i zwróć ten nowy identyfikator.

Uwaga: jest to niesprawdzona i niesprawdzona metoda! Jestem przekonany, że to zadziała, ale jestem też całkiem pewien, że jeśli to się przyjmie, zamkną go w taki czy inny sposób.

person Jens Vesti    schedule 31.01.2019

Jeśli dodasz:

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

Android Lint wyświetli następujące ostrzeżenie:

Używanie getString do uzyskiwania identyfikatorów urządzeń nie jest zalecane. Informacje dotyczące kontroli: używanie tych identyfikatorów urządzeń nie jest zalecane w innych przypadkach niż w celu zapobiegania oszustwom o dużej wartości i zaawansowanych przypadków użycia telefonii. W przypadku zastosowań reklamowych użyj AdvertisingIdClient$Info#getId, a do analizy użyj InstanceId#getId.

Więc powinieneś tego unikać.

Jak wspomniano w dokumentacji dla programistów Androida :

1: Unikaj używania identyfikatorów sprzętowych.

W większości przypadków można uniknąć używania identyfikatorów sprzętowych, takich jak SSAID (identyfikator Androida) i IMEI, bez ograniczania wymaganej funkcjonalności.

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

Korzystając z identyfikatora reklamowego, zawsze szanuj wybory użytkowników dotyczące śledzenia reklam. Upewnij się też, że identyfikatora nie można połączyć z informacjami umożliwiającymi identyfikację osoby (PII) i unikaj mostkowania resetowania identyfikatora wyświetlania reklam.

3: Używaj identyfikatora instancji lub prywatnie przechowywanego identyfikatora GUID, gdy tylko jest to możliwe, we wszystkich innych przypadkach użycia, z wyjątkiem zapobiegania oszustwom płatniczym i telefonii.

W przypadku zdecydowanej większości przypadków użycia niezwiązanych z reklamami wystarczy identyfikator instancji lub identyfikator GUID.

4: Użyj interfejsów API, które są odpowiednie dla Twojego przypadku użycia, aby zminimalizować ryzyko związane z prywatnością.

Używaj interfejsu API DRM do ochrony treści o wysokiej wartości, a interfejsów API SafetyNet do ochrony przed nadużyciami. Interfejsy API SafetyNet to najprostszy sposób na ustalenie, czy urządzenie jest oryginalne, bez narażania się na ryzyko prywatności.

person Malwinder Singh    schedule 24.07.2019

String SERIAL_NUMER = Build.SERIAL;

Zwraca SERIAL NUMBER jako ciąg, który jest unikalny w każdym urządzeniu.

person Jeffy    schedule 07.09.2017

Numer seryjny to unikalny identyfikator urządzenia dostępny za pośrednictwem android.os.Build.SERIAL.

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

Upewnij się, że masz uprawnienie READ_PHONE_STATE przed wywołaniem metody getSerial().

UWAGA:- Jest niedostępne na urządzeniach bez telefonii (tak jak tablety tylko z Wi-Fi).

person shivampip    schedule 14.12.2017
comment
Zwróć uwagę, że dokumentacja mówi, że spowoduje to zwrócenie numeru seryjnego sprzętu jeśli jest dostępny, co sugeruje, że Build.SERIAL (lub Build.getSerial()) nie zawsze jest dostępny. Więcej informacji można znaleźć w poście na blogu Zmiany w Identyfikatory urządzeń w Androidzie O. Warto też przeczytać: Sprawdzone metody dotyczące unikalnych identyfikatorów. - person Ted Hopp; 14.12.2017

Aby uzyskać kompletność, oto jak uzyskać Id w Xamarin.Android i C#:

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

Lub jeśli nie znajdujesz się w Activity:

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

Gdzie context to przekazana w kontekście.

person Martin Zikmund    schedule 21.01.2019

android.telephony.TelephonyManager.getDeviceId()

Spowoduje to zwrócenie dowolnego ciągu jednoznacznie identyfikującego urządzenie (IMEI w sieci GSM, MEID w przypadku CDMA).

Będziesz potrzebować następujących uprawnień w pliku AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
person Anubhav    schedule 25.09.2019
comment
Jest przestarzały - person Googlian; 23.10.2019

Tak, każde urządzenie z Androidem ma unikalne numery seryjne, które można uzyskać z tego kodu. Build.SERIAL. Pamiętaj, że został dodany tylko w API poziomu 9 i może nie być obecny na wszystkich urządzeniach. Aby uzyskać unikalny identyfikator na wcześniejszych platformach, musisz odczytać coś takiego jak adres MAC lub IMEI.

person Stephan John    schedule 11.09.2019

Sprawdź SystemInfo.deviceUniqueIdentifier

Dokumentacja: http://docs.unity3d.com/Documentation/ScriptReference/SystemInfo-deviceUniqueIdentifier.html

Unikalny identyfikator urządzenia. Gwarantuje się, że jest unikalny dla każdego urządzenia (tylko do odczytu).

iOS: na urządzeniach starszych niż iOS7 zwróci hash adresu MAC. Na urządzeniach z systemem iOS7 będzie to identyfikator UIDeviceForVendor lub, jeśli z jakiegoś powodu to się nie powiedzie, identyfikator reklamy ASIdentifierManager.

person Ciul    schedule 06.01.2014

Uzyskaj identyfikator urządzenia tylko raz, a następnie zapisz go w bazie danych lub pliku. W takim przypadku, jeśli jest to pierwsze uruchomienie aplikacji, generuje identyfikator i przechowuje go. Następnym razem pobierze tylko identyfikator zapisany w pliku.

person TootsieRockNRoll    schedule 21.10.2013
comment
Chodzi o to, aby mieć identyfikator, który przetrwa odinstalowywanie i ponowne instalowanie aplikacji. Zapisanie identyfikatora w bazie danych nie pomaga, ponieważ baza danych jest usuwana po odinstalowaniu aplikacji. - person Ted Hopp; 21.10.2013

Aby uzyskać identyfikator użytkownika, możesz skorzystać z Biblioteki licencjonowania Google Play.

Aby pobrać tę bibliotekę, otwórz Menedżer SDK => Narzędzia SDK. Ścieżka do pobranych plików biblioteki to:

path_to_android_sdk_on_your_pc/extras/google/market_licensing/library

Dołącz bibliotekę do swojego projektu (możesz po prostu skopiować jej pliki).

Następnie potrzebujesz implementacji interfejsu Policy (możesz po prostu użyć jednego z dwóch plików z biblioteki: ServerManagedPolicy lub StrictPolicy).

Identyfikator użytkownika zostanie podany w funkcji processServerResponse():

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

Następnie musisz skonstruować LicenseChecker z polityką i wywołać funkcję checkAccess(). Użyj MainActivity.java jako przykładu, jak to zrobić. MainActivity.java znajduje się w tym folderze:

path_to_android_sdk_on_your_pc/extras/google/market_licensing/sample/src/com/example/android/market/licensing

Nie zapomnij dodać uprawnienia CHECK_LICENSE do pliku AndroidManifest.xml.

Więcej o bibliotece licencji: https://developer.android.com/google/play/licensing

person Vitaly Zinchenko    schedule 03.08.2019

Android ogranicza identyfikator związany ze sprzętem po Androidzie O, dlatego Android_Id jest rozwiązaniem dla unikalnego identyfikatora, ale ma problem, gdy reflektor urządzenie wygeneruje nowy android_id, aby rozwiązać ten problem, możemy użyć DRUMID.

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

val drumID = android.util.Base64.encodeToString(drumIDByteArray,android.util.Base64.DEFAULT)
person jai khambhayta    schedule 19.05.2020

Otrzymasz adres mac Wi-Fi za pomocą poniższego kodu, niezależnie od tego, czy użyłeś losowego adresu, gdy próbowałeś połączyć się z Wi-Fi, czy nie, i niezależnie od tego, czy Wi-Fi było włączone, czy wyłączone.

Użyłem metody z linku poniżej i dodałem niewielką modyfikację, aby uzyskać dokładny adres zamiast losowego:

Pobieranie adresu MAC w Androidzie 6.0

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

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

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

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

}

person Abdallah AlTaher    schedule 23.09.2020