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?
Czy istnieje unikalny identyfikator urządzenia z Androidem?
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
ANDROID_ID
- nie mogę tego powtórzyć w testach - warto być tego świadomym...
- person Dori; 06.03.2014
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):
- Wszystkie testowane urządzenia zwróciły wartość
TelephonyManager.getDeviceId()
- Wszystkie urządzenia GSM (wszystkie testowane z kartą SIM) zwróciły wartość
TelephonyManager.getSimSerialNumber()
- Wszystkie urządzenia CDMA zwróciły wartość null dla
getSimSerialNumber()
(zgodnie z oczekiwaniami) - Wszystkie urządzenia z dodanym kontem Google zwróciły wartość
ANDROID_ID
- Wszystkie urządzenia CDMA zwracały tę samą wartość (lub pochodną tej samej wartości) zarówno dla
ANDROID_ID
, jak iTelephonyManager.getDeviceId()
-- o ile konto Google zostało dodane podczas konfiguracji. - 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;
<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
#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" />
lubAPI 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/
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;
}
}
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 :).
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
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.
02:00:00:00:00:00
- person Behrouz.M; 10.07.2016
Przydatne informacje znajdziesz tutaj.
Obejmuje pięć różnych typów identyfikatorów:
- IMEI (tylko dla urządzeń z Androidem z telefonem; wymaga
android.permission.READ_PHONE_STATE
) - Pseudounikalny identyfikator (dla wszystkich urządzeń z Androidem)
- Identyfikator Androida (może być pusty, można go zmienić po przywróceniu ustawień fabrycznych, można go zmienić na zrootowanym telefonie)
- Ciąg Adres MAC WLAN (wymaga
android.permission.ACCESS_WIFI_STATE
) - Ciąg Adres MAC BT (urządzenia z Bluetooth, wymaga
android.permission.BLUETOOTH
)
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.
UUID.randomUUID()
zależnej od czasu.
- person Nikita Kurtin; 25.02.2021
Oficjalny blog programistów Androida zawiera teraz pełny artykuł właśnie na ten temat, Identyfikowanie Instalacje aplikacji.
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.
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).
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) {
}
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);
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.
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.
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();
}
}
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" />
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.
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.
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_ID — Settings.Secure.ANDROID_ID
Adres Bluetooth - Adres adaptera Bluetooth
Zwróci coś takiego: 551F27C060712A72730B0A0F734064B1
Uwaga: zawsze możesz dodać więcej identyfikatorów do 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 "";
}
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
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.
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;
}
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);
}
}
}
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.
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;
}
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).
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.
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);
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
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
HTH
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.
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.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.
- 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.
DeviceInfoProvider
nie jest częścią pakietu Android SDK
- person user924; 06.02.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"/>
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
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;
}
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;
}
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;
}
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:
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:
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ł:
- 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();
}
}
- 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.
- 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.
- 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.
- 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.
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.
String SERIAL_NUMER = Build.SERIAL;
Zwraca SERIAL NUMBER jako ciąg, który jest unikalny w każdym urządzeniu.
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).
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.
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" />
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.
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.
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.
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
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)
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();
}
ANDROID_ID
, przeczytaj tę odpowiedź i ten błąd. - person Dheeraj Vepakomma   schedule 16.01.2013