Există un ID unic de dispozitiv Android?

Dispozitivele Android au un ID unic și, dacă da, care este o modalitate simplă de a-l accesa folosind Java?


person Tyler    schedule 07.05.2010    source sursă
comment
Dacă utilizați ANDROID_ID, asigurați-vă că citiți acest răspuns și this bug /a>.   -  person Dheeraj Vepakomma    schedule 16.01.2013
comment
Soluția dvs. este aici: stackoverflow.com/a/63481350/7135685   -  person Mujahid Khan    schedule 19.08.2020


Răspunsuri (50)


Settings.Secure#ANDROID_ID returnează ID-ul Android ca unic pentru fiecare utilizator hexadecimal pe 64 de biți şir.

import android.provider.Settings.Secure;

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

Citiți și Cele mai bune practici pentru identificatorii unici: https://developer.android.com/training/articles/user-data-ids

person Anthony Forloney    schedule 07.05.2010
comment
Se știe că uneori este nul, este documentat, deoarece se poate schimba la resetarea din fabrică. Utilizați pe propriul risc și poate fi schimbat cu ușurință pe un telefon rootat. - person Seva Alekseyev; 23.06.2010
comment
Cred că trebuie să fim atenți la utilizarea ANDROID_ID în hash în primul răspuns despre, deoarece este posibil să nu fie setat la prima rulare a aplicației, poate fi setat mai târziu sau chiar se poate schimba în teorie, prin urmare ID-ul unic se poate schimba - person ; 05.02.2011
comment
Rețineți că această soluție are limitări uriașe: dezvoltatori-android. blogspot.com/2011/03/ - person emmby; 08.04.2011
comment
acest ANDROID_ID este numai pentru Android Tab dacă puteți rula în telefon, atunci veți obține null dacă veți rula în Tab, atunci puteți obține ID unic.-Girish - person Girish Patel; 30.09.2011
comment
ANDROID_ID nu mai identifică în mod unic un dispozitiv (începând cu 4.2): stackoverflow.com/a/13465373/150016 - person Tom; 15.12.2012
comment
Se pare că acest lucru se poate schimba și dacă un utilizator șterge datele din cache ale Serviciilor Play. androidpolice.com/2013/11/20/ indică Făcând aceasta, se schimbă ID-ul principal prin care Google știe dispozitivul tau. În ceea ce privește serverele, dispozitivul a fost practic resetat din fabrică., ceea ce presupun că este ANDROID_ID - nu pot replica asta în testare, totuși - merită să fie conștient oricum... - person Dori; 06.03.2014
comment
Salaam. uitați-vă la răspunsul @Joe http://stackoverflow.com/a/2853253/1676736 - person Sayed Abolfazl Fatemi; 09.07.2014
comment
Nu este recomandată utilizarea getString pentru a obține identificatori de dispozitiv. DE CE? - person Iman Marashi; 06.04.2017
comment
Android O va schimba acest android-developers.googleblog.com/2017/04/ - person EpicPandaForce; 12.04.2017
comment
Am folosit ID-ul Android în aplicația mea pentru a identifica în mod unic utilizatorii, deoarece am simțit că acest lucru este mai ușor decât cu înregistrarea de rutină cu ID-ul de e-mail și, până acum, nu am găsit probleme cu această soluție, niciunul dintre abonații noștri nu se plâng până acum, și știm că opțiunea de rezervă nu va fi atât de devastatoare dacă se va întâmpla din nou, totul depinde de felul aplicației, cu excepția cazului în care aplicația are nevoie de securitate strictă. Cred că ID-ul ANDROID nu este o problemă. - person Naga; 22.02.2019
comment
Android Lint spune că nu este recomandată utilizarea getString pentru a obține identificatori de dispozitiv. Informații de inspecție: utilizarea acestor identificatori de dispozitiv nu este recomandată decât pentru prevenirea fraudei de mare valoare și cazuri de utilizare avansate a telefoniei. Pentru cazurile de utilizare în publicitate, utilizați AdvertisingIdClient$Info#getId și pentru analize, utilizați InstanceId#getId. - person Malwinder Singh; 24.07.2019
comment
@AaronUllal Îmi pare rău puțin târziu, nu, nu cred, Despre telefon în setări are lucruri precum versiunea Android, imei etc., într-unul dintre telefoanele Android pe care le-am verificat, poate că acest lucru nu este atât de relevant pentru utilizatori decât pentru aplicații - person Naga; 03.09.2019
comment
Care este versiunea 2020 a răspunsului la această întrebare? Cu siguranță lucrurile s-au schimbat. - person André; 24.07.2020
comment
Acest ID se modifică odată cu schimbarea fișierului keystore. Căutam ceva mai unic. Un ID care rămâne constant pentru un singur dispozitiv. - person Syed Arsalan Kazmi; 20.11.2020
comment
@SyedArsalanKazmi am ales tokenul fcm - person famfamfam; 05.03.2021

ACTUALIZARE: începând cu versiunile recente de Android, multe dintre problemele legate de ANDROID_ID au fost rezolvate și cred că această abordare nu mai este necesară. Vă rugăm să aruncați o privire la răspunsul lui Anthony.

Dezvăluire completă: aplicația mea a folosit abordarea de mai jos inițial, dar nu mai folosește această abordare, iar acum folosim abordarea prezentată în Blog pentru dezvoltatori Android intrare la care răspunsul lui Emmby trimite (și anume , generând și salvând un UUID#randomUUID()).


Există multe răspunsuri la această întrebare, dintre care cele mai multe vor funcționa doar o parte din timp și, din păcate, asta nu este suficient de bun.

Pe baza testelor mele de dispozitive (toate telefoanele, dintre care cel puțin unul nu este activat):

  1. Toate dispozitivele testate au returnat o valoare pentru TelephonyManager.getDeviceId()
  2. Toate dispozitivele GSM (toate testate cu un SIM) au returnat o valoare pentru TelephonyManager.getSimSerialNumber()
  3. Toate dispozitivele CDMA au returnat nul pentru getSimSerialNumber() (după cum era de așteptat)
  4. Toate dispozitivele cu un cont Google adăugat au returnat o valoare pentru ANDROID_ID
  5. Toate dispozitivele CDMA au returnat aceeași valoare (sau derivarea aceleiași valori) atât pentru ANDROID_ID, cât și pentru TelephonyManager.getDeviceId() -- atâta timp cât a fost adăugat un cont Google în timpul configurării.
  6. Nu am avut încă șansa de a testa dispozitive GSM fără SIM, un dispozitiv GSM fără cont Google adăugat sau oricare dintre dispozitivele în modul avion.

Deci, dacă doriți ceva unic pentru dispozitivul în sine, TM.getDeviceId() ar trebui să fie suficient. În mod evident, unii utilizatori sunt mai paranoici decât alții, așa că ar putea fi util să trimiți 1 sau mai mulți dintre acești identificatori, astfel încât șirul să fie practic unic pentru dispozitiv, dar să nu identifice în mod explicit dispozitivul real al utilizatorului. De exemplu, folosind String.hashCode(), combinat cu un 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();

ar putea avea ca rezultat ceva de genul: 00000000-54b3-e7c7-0000-000046bffd97

Funcționează suficient de bine pentru mine.

După cum menționează Richard mai jos, nu uitați că aveți nevoie de permisiunea pentru a citi proprietățile TelephonyManager, așa că adăugați asta în manifest:

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

importa biblioteci

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
person Joe    schedule 17.05.2010
comment
ID-ul bazat pe telefonie nu va fi acolo pe tablete, nu? - person Seva Alekseyev; 23.06.2010
comment
De aceea am spus că majoritatea nu vor funcționa tot timpul :) Nu am văzut încă niciun răspuns la această întrebare care să fie de încredere pentru toate dispozitivele, toate tipurile de dispozitive și toate configurațiile hardware. De aceea această întrebare este aici pentru început. Este destul de clar că nu există o soluție finală pentru asta. Producătorii individuali de dispozitive pot avea numere de serie ale dispozitivului, dar acestea nu sunt expuse pentru utilizare și nu este o cerință. Astfel, rămânem cu ceea ce ne este la dispoziție. - person Joe; 29.06.2010
comment
Îți vei actualiza răspunsul după mai multe teste? Ar fi destul de interesant. - person liori; 31.01.2011
comment
Exemplul de cod funcționează excelent. Nu uitați să adăugați <uses-permission android:name="android.permission.READ_PHONE_STATE" /> la fișierul manifest. Dacă se stochează într-o bază de date, șirul returnat are 36 de caractere. - person Richard; 28.02.2011
comment
Rețineți că această soluție are limitări uriașe: dezvoltatori-android. blogspot.com/2011/03/ - person emmby; 08.04.2011
comment
FYI, TelephonyManager.getDeviceId() returnează un ID unic valid pe Xoom-ul meu, așa că pare să funcționeze și pentru tablete. - person MusiGenesis; 21.04.2011
comment
Acest răspuns este depășit și nu ar trebui folosit. Nu urmăriți dispozitivele, urmăriți instalațiile! - person softarn; 17.07.2011
comment
@softarn: Cred că la ce vă referiți este blogul pentru dezvoltatori Android la care emmby s-a conectat deja, care explică ceea ce încercați să spuneți, așa că poate că ar fi trebuit să-i votați pur și simplu comentariul. Oricum, așa cum menționează emmby în răspunsul său, există încă probleme chiar și cu informațiile blogului. Întrebarea solicită un identificator unic DEVICE (nu un identificator de instalare), așa că nu sunt de acord cu afirmația dvs. Blogul presupune că ceea ce doriți nu este neapărat să urmărească dispozitivul, în timp ce întrebarea cere tocmai asta. In rest sunt de acord cu blogul. - person Joe; 22.07.2011
comment
Cred că există un defect grav în această metodă. Acest lucru depinde de informațiile cartelei SIM, utilizatorii trec uneori la modul Avion = nu este conectat SIM. Trebuie să aveți un mecanism de rezervă în acest scenariu, probabil pentru a lua ID-ul Android. - person Daniel Novak; 04.08.2011
comment
@Daniel Novak: punct corect. Pentru cazul meu, nu a fost relevant, deoarece id-ul este folosit în comunicarea API, deci modul Avion = nicio aplicație :) L-am proiectat și astfel încât, de exemplu, dacă utilizatorul schimbă cartelele SIM, am dorit în mod intenționat ID-ul dispozitivului a fi diferit. Evident, acesta nu va fi cazul tuturor, așa că mulțumesc că ai subliniat-o. - person Joe; 22.08.2011
comment
Sunt puțin surprins că nimeni nu l-a adus în discuție încă, dar exemplul de cod poate fi cu adevărat nefericit în anumite circumstanțe - va returna un ID diferit, în funcție de faptul dacă telefonul este, de exemplu, în modul zbor sau nu, deoarece simSerialNumber va fi nul dacă rețeaua GSM a dispozitivului este oprită. Dacă aveți o aplicație care se bazează pe un ID unic, dar are nevoie doar de internet, nu neapărat de rețea, ar putea fi cel mai bine să vă asigurați că codul returnează întotdeauna același ID, indiferent de starea rețelei telefonului curent. - person Mathias; 20.12.2011
comment
Am folosit acest cod timp de 6 luni. Nu generează un ID unic. Nu vă recomand tuturor să utilizați acest cod. În prezent, folosesc codul din această postare: stackoverflow.com/a/17625641/365229 - person Behrouz.M; 18.06.2015
comment
Vă recomand cu tărie să nu utilizați acest cod. Are mai multe erori critice: în primul rând, atât telefonia, cât și ID-ul Android nu sunt garantate a exista, iar dacă ambele nu există, dispozitivele dvs. vor fi mapate numai în funcție de modelul lor. În al doilea rând, și mai important, atunci când utilizați codul hash al ID-ului Android, transformați o reprezentare șir de 64 de biți a unui număr într-un număr de 32 de biți și, astfel, pierdeți mult din unicitate. - person lavuy; 30.07.2015
comment
ID-ul IMEI nu mai poate funcționa pentru Android 10 și versiuni ulterioare - person abss; 13.07.2021

#Ultima actualizare: 6/2/15


După ce am citit fiecare postare Stack Overflow despre crearea unui ID unic, blogul dezvoltatorului Google și documentația Android, simt că „Pseudo ID” este cea mai bună opțiune posibilă.

Problemă principală: Hardware vs Software

Hardware

  • Utilizatorii își pot schimba hardware-ul, tableta Android sau telefonul, astfel încât ID-urile unice bazate pe hardware nu sunt idei bune pentru URMĂRIREA UTILIZATORULUI
  • Pentru TRACKING HARDWARE, aceasta este o idee grozavă

Software

  • Utilizatorii își pot șterge/schimba ROM-ul dacă sunt rootați
  • Puteți urmări utilizatorii pe platforme (iOS, Android, Windows și Web)
  • Cea mai bună dorință de a URMĂRIȚI UN UTILIZATOR INDIVIDUAL cu consimțământul acestuia este pur și simplu să-l autentificați (faceți acest lucru fără probleme folosind OAuth)

#Defalcare generală cu Android

###- Garantați unicitatea (includeți dispozitivele rootate) pentru API ›= 9/10 (99,5% dintre dispozitivele Android) ###- Fără permisiuni suplimentare

Cod pseudo:

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)

Mulțumim lui @stansult pentru postarea toate opțiunile noastre (în această întrebare Stack Overflow).

##Lista de opțiuni - motive pentru care/ de ce să nu le folosiți:

  • E-mail utilizator - Software

  • Utilizatorul ar putea schimba adresa de e-mail - FOARTE puțin probabil

  • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> sau

  • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> (Cum să obțineți dispozitivul Android adresa de e-mail principală)

  • Numărul de telefon al utilizatorului - Software

  • Utilizatorii ar putea schimba numerele de telefon - FOARTE puțin probabil

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

  • IMEI - Hardware (numai telefoane, necesită android.permission.READ_PHONE_STATE)

  • Majoritatea utilizatorilor urăsc faptul că scrie Apeluri telefonice în permisiune. Unii utilizatori acordă evaluări proaste deoarece cred că pur și simplu le furați informațiile personale atunci când tot ceea ce doriți să faceți este să urmăriți instalările dispozitivului. Este evident că colectați date.

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

  • ID Android - Hardware (poate fi nul, se poate modifica la resetarea din fabrică, poate fi modificat pe un dispozitiv rootat)

  • Deoarece poate fi „null”, putem verifica „null” și îi putem modifica valoarea, dar asta înseamnă că nu va mai fi unic.

  • Dacă aveți un utilizator cu un dispozitiv de resetare din fabrică, este posibil ca valoarea să se fi schimbat sau modificată pe dispozitivul înrădăcinat, astfel încât pot exista intrări duplicate dacă urmăriți instalările utilizatorilor.

  • Adresă MAC WLAN - Hardware (necesită android.permission.ACCESS_WIFI_STATE)

  • Aceasta ar putea fi a doua cea mai bună opțiune, dar încă colectați și stocați un identificator unic care vine direct de la un utilizator. Acest lucru este evident că colectați date.

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

  • Adresă MAC Bluetooth - Hardware (dispozitive cu Bluetooth, necesită android.permission.BLUETOOTH)

  • Majoritatea aplicațiilor de pe piață nu folosesc Bluetooth și, prin urmare, dacă aplicația dvs. nu folosește Bluetooth și îl includeți, utilizatorul ar putea deveni suspicios.

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

  • ID pseudo-unic - Software (pentru toate dispozitivele Android)

  • Foarte posibil, poate conține coliziuni - Vezi metoda mea postată mai jos!

  • Acest lucru vă permite să aveți un ID „aproape unic” de la utilizator fără a lua nimic privat. Vă puteți crea propriul ID anonim din informațiile despre dispozitiv.


Știu că nu există nicio modalitate „perfectă” de a obține un ID unic fără a utiliza permisiunile; cu toate acestea, uneori trebuie doar să urmărim instalarea dispozitivului. Când vine vorba de crearea unui ID unic, putem crea un „pseudoid unic” bazat exclusiv pe informațiile pe care ni le oferă API-ul Android fără a folosi permisiuni suplimentare. În acest fel, putem arăta utilizatorului respect și putem încerca să oferim și o experiență bună pentru utilizator.

Cu un id pseudo-unic, într-adevăr te întâlnești doar cu faptul că pot exista duplicate pe baza faptului că există dispozitive similare. Puteți modifica metoda combinată pentru a o face mai unică; cu toate acestea, unii dezvoltatori trebuie să urmărească instalările dispozitivelor și acest lucru va face truc sau performanța pe baza dispozitivelor similare.

##API ›= 9:

Dacă dispozitivul lor Android are API 9 sau o versiune ulterioară, acesta este garantat a fi unic datorită câmpului „Build.SERIAL”.

ȚINE minte, din punct de vedere tehnic, pierdeți doar aproximativ 0,5% dintre utilizatorii care au API ‹ 9. Deci, vă puteți concentra pe restul: acesta este 99,5% dintre utilizatori!

##API ‹ 9:

Dacă dispozitivul Android al utilizatorului este mai mic decât API 9; sperăm că nu au făcut o resetare din fabrică și „Secure.ANDROID_ID” lor va fi păstrat sau nu „null”. (consultați http://developer.android.com/about/dashboards/index.html)

##Dacă toate celelalte nu reușesc:

Dacă toate celelalte eșuează, dacă utilizatorul are o versiune mai mică decât API 9 (mai mică decât Gingerbread), și-a resetat dispozitivul sau „Secure.ANDROID_ID” returnează „null”, atunci pur și simplu ID-ul returnat se va baza exclusiv pe informațiile dispozitivului său Android . Aici se pot produce ciocnirile.

Schimbări:

  • S-a eliminat „Android.SECURE_ID” deoarece resetările din fabrică ar putea determina modificarea valorii
  • Am editat codul pentru a fi modificat pe API
  • Schimbat pseudo-ul

Vă rugăm să aruncați o privire la metoda de mai jos:

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

#Nou (pentru aplicații cu reclame ȘI Servicii Google Play):

Din consola pentru dezvoltatori Google Play:

Începând cu 1 august 2014, Politica de program pentru dezvoltatori Google Play necesită încărcări și actualizări de aplicații complet noi pentru a utiliza ID-ul de publicitate în locul oricăror alți identificatori persistenti în orice scop publicitar. Află mai multe

Implementare:

Permisiune:

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

Cod:

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

Sursă/Documente:

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

##Important:

Se intenționează ca ID-ul de publicitate să înlocuiască complet utilizarea existentă a altor identificatori în scopuri publicitare (cum ar fi utilizarea ANDROID_ID în Setări.Securizat) atunci când Serviciile Google Play sunt disponibile. Cazurile în care Serviciile Google Play sunt indisponibile sunt indicate de o excepție GooglePlayServicesNotAvailableException generată de getAdvertisingIdInfo().

##Atenție, utilizatorii pot reseta:

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

Am încercat să fac referire la fiecare link de la care am preluat informații. Dacă lipsești și trebuie să fii inclus, te rog să comentezi!

ID de instanță Google Player Services

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

person Jared Burrows    schedule 12.07.2013
comment
Am folosit metoda ta în aplicația mea pentru a trimite comentarii. am vești proaste. din păcate, PsuedoID nu este complet unic. serverul meu a înregistrat mai mult de 100 pentru 5 ID și mai mult de 30 pentru aproape 30 ID. cele mai repetate ID-uri sunt „ffffffff-fc8f-6093-ffff-ffffd8” (înregistrare 159) și „ffffffff-fe99-b334-ffff-ffffef” (ori 154). de asemenea, pe baza timpului și a comentariilor, este evident că există popoare diferite. totalul înregistrărilor până în prezent este de 10.000. te rog spune-mi de ce s-a intamplat asta. tancuri. - person hojjat reyhane; 17.03.2015
comment
Am scris asta acum 1,5 ani. Nu sunt sigur de ce nu este unic pentru tine. Puteți încerca ID-ul de publicitate. Dacă nu, poți veni cu propria ta soluție. - person Jared Burrows; 17.03.2015
comment
Sorta..Aș aprecia foarte mult dacă ai trece prin întrebare și ai da părerea despre asta - person Durai Amuthan.H; 29.04.2015
comment
@user1587329 Vă mulțumesc. Încerc să țin asta la zi pentru toată lumea. Această întrebare este dificilă când vine vorba de hardware vs software și cross platform. - person Jared Burrows; 06.05.2015

După cum menționează Dave Webb, Blogul dezvoltatorilor Android are un articol care acoperă asta. Soluția lor preferată este să urmărească instalările aplicațiilor, mai degrabă decât dispozitivele, iar asta va funcționa bine pentru majoritatea cazurilor de utilizare. Postarea de pe blog vă va arăta codul necesar pentru ca acest lucru să funcționeze și vă recomand să-l verificați.

Cu toate acestea, postarea de blog continuă să discute soluții dacă aveți nevoie de un identificator de dispozitiv, mai degrabă decât de un identificator de instalare a aplicației. Am vorbit cu cineva de la Google pentru a obține niște clarificări suplimentare cu privire la câteva elemente în cazul în care trebuie să faceți acest lucru. Iată ce am descoperit despre identificatorii de dispozitiv care NU sunt menționate în postarea de blog menționată mai sus:

  • ANDROID_ID este identificatorul preferat de dispozitiv. ANDROID_ID este perfect de încredere pe versiunile de Android ‹=2.1 sau >=2.3. Doar 2.2 are problemele menționate în postare.
  • Mai multe dispozitive de la mai mulți producători sunt afectate de eroarea ANDROID_ID din 2.2.
  • Din câte am putut stabili, toate dispozitivele afectate au același ANDROID_ID, care este 9774d56d682e549c. Care este, de asemenea, același ID de dispozitiv raportat de emulator, btw.
  • Google crede că OEM-urile au corectat problema pentru multe sau majoritatea dispozitivelor lor, dar am putut verifica că, cel puțin, de la începutul lui aprilie 2011, este încă destul de ușor să găsești dispozitive care au ANDROID_ID-ul stricat.

Pe baza recomandărilor Google, am implementat o clasă care va genera un UUID unic pentru fiecare dispozitiv, folosind ANDROID_ID ca seed acolo unde este cazul, recurgând înapoi la TelephonyManager.getDeviceId() după cum este necesar și, dacă nu reușește, recurgând la un UUID unic generat aleatoriu. care persistă la repornirile aplicației (dar nu la reinstalările aplicației).

Rețineți că, pentru dispozitivele care trebuie să recurgă la ID-ul dispozitivului, ID-ul unic VA persista la resetările din fabrică. Acesta este ceva de care trebuie să fii conștient. Dacă trebuie să vă asigurați că o resetare din fabrică vă va reseta ID-ul unic, poate doriți să luați în considerare revenirea direct la UUID-ul aleatoriu în loc de ID-ul dispozitivului.

Din nou, acest cod este pentru un ID de dispozitiv, nu pentru un ID de instalare a aplicației. Pentru majoritatea situațiilor, un ID de instalare a aplicației este probabil ceea ce cauți. Dar dacă aveți nevoie de un ID de dispozitiv, atunci următorul cod va funcționa probabil pentru dvs.

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
Nu ar trebui să faci hashing diferitele ID-uri astfel încât să aibă toate aceeași dimensiune? În plus, ar trebui să faci hashing ID-ul dispozitivului pentru a nu expune accidental informații private. - person Steve Pomeroy; 12.04.2011
comment
De asemenea, un dispozitiv a cărui configurație face ca ID-ul dispozitivului să fie utilizat va lega ID-ul de dispozitiv, nu neapărat de utilizator. Acest ID va supraviețui resetării din fabrică, care ar putea fi potențial rău. Poate că ID-ul dispozitivului ar putea fi hashing cu ceva care raportează ora ultimei resetari din fabrică? - person Steve Pomeroy; 12.04.2011
comment
Puncte bune, Steve. Am actualizat codul pentru a returna întotdeauna un UUID. Acest lucru asigură că a) ID-urile generate sunt întotdeauna de aceeași dimensiune și b) ID-urile Android și dispozitivele sunt hashing înainte de a fi returnate pentru a evita expunerea accidentală a informațiilor personale. De asemenea, am actualizat descrierea pentru a reține că ID-ul dispozitivului va persista la resetările din fabrică și că acest lucru poate să nu fie de dorit pentru unii utilizatori. - person emmby; 12.04.2011
comment
cred că ești greșit; soluția preferată este să urmăriți instalațiile, nu identificatorii dispozitivului. Codul dvs. este substanțial mai lung și mai complex decât cel din postarea de blog și nu este evident pentru mine că adaugă vreo valoare. - person Tim Bray; 12.04.2011
comment
Ideea bună, am actualizat comentariul pentru a sugera cu tărie utilizatorii să folosească ID-uri de instalare a aplicațiilor, mai degrabă decât ID-uri de dispozitiv. Cu toate acestea, cred că această soluție este încă valoroasă pentru persoanele care au nevoie de un dispozitiv mai degrabă decât de un ID de instalare. - person emmby; 12.04.2011
comment
ANDROID_ID se poate modifica la resetarea din fabrică, așa că nu poate identifica și dispozitivele - person Samuel; 19.05.2011
comment
După cum remarc în același răspuns, aici există nu există nicio garanție că veți obține același UUID generat între procese - copia SharedPrefs este locală! - person Mr_and_Mrs_D; 18.09.2013

Iată codul pe care Reto Meier l-a folosit în prezentarea Google I/O anul acesta pentru a obține un ID unic pentru utilizator:

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

Dacă combinați acest lucru cu o strategie de rezervă pentru a trimite preferințe în cloud (descris și în discuți, ar trebui să ai un ID care se leagă de un utilizator și care rămâne după ce dispozitivul a fost șters sau chiar înlocuit. Intenționez să folosesc acest lucru în analiză mergând înainte (cu alte cuvinte, încă nu am făcut acel pic :).

person Anthony Nolan    schedule 28.10.2011
comment
Opțiune excelentă dacă nu aveți nevoie de ID-ul unic pentru a persista după o dezinstalare și reinstalare (de exemplu, eveniment/joc promoțional în care aveți trei șanse de a câștiga, punct). - person Kyle Clegg; 16.05.2012
comment
Prezentarea Meier se bazează pe utilizarea Android Backup Manager, care, la rândul său, depinde de alegerea utilizatorului să activeze această funcție. Este în regulă pentru preferințele utilizatorului aplicației (utilizarea lui Meier), deoarece dacă utilizatorul nu a selectat acea opțiune, pur și simplu nu le va face copii de rezervă. Cu toate acestea, întrebarea inițială este despre generarea unui ID unic pentru dispozitiv, iar acest ID este generat pe aplicație și nici măcar pe instalare, darămite pe dispozitiv, și deoarece se bazează pe selectarea utilizatorului opțiunea de rezervă, utilizările sale dincolo de preferințele utilizatorului (de exemplu, pentru o încercare limitată în timp) sunt limitate. - person Carl; 22.12.2012
comment
Acest lucru nu va funcționa la dezinstalarea sau ștergerea datelor. - person John Shelley; 02.09.2014
comment
solutie foarte proasta - person famfamfam; 23.02.2021
comment
Cred că este o soluție bună, există un ID unic pe dispozitiv și pe server în cazul în care dezinstalați. Puteți să vă asigurați că îl salvați cu e-mailul clientului, astfel încât să rămână ;-p - person vin shaba; 25.04.2021

De asemenea, ați putea lua în considerare adresa MAC a adaptorului Wi-Fi. Preluat astfel:

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

Necesită permisiunea android.permission.ACCESS_WIFI_STATE în manifest.

Raportat a fi disponibil chiar și atunci când Wi-Fi nu este conectat. Dacă Joe din răspunsul de mai sus îl încearcă pe acesta pe numeroasele sale dispozitive, ar fi bine.

Pe unele dispozitive, acesta nu este disponibil când Wi-Fi este dezactivat.

NOTĂ: de la Android 6.x, returnează o adresă Mac falsă consecventă: 02:00:00:00:00:00

person Seva Alekseyev    schedule 23.06.2010
comment

Problema este că XML-ul tău folosește spațiul de nume implicit, dar XSD specifică un spațiu de nume țintă. Dacă specificați <BadManifest xmlns="http://www.engagesoftware.com/Schemas/EngageManifest"> în XML, ar trebui să descoperiți că validatorul raportează erori așa cum era de așteptat. În caz contrar, deoarece nu recunoaște spațiul de nume al XML-ului, pur și simplu îl ignoră.

- person ohhorob; 01.11.2010
comment
ce zici de dispozitivele fără wifi? - person Axarydax; 22.12.2010
comment
Știu că această întrebare este veche, dar aceasta este o idee grozavă. Am folosit ID-ul BT mac în aplicația mea, dar numai pentru că necesită BT pentru a funcționa. Arată-mi un dispozitiv Android care merită dezvoltat pentru care NU are WiFi. - person Jack; 30.08.2011
comment
Cred că veți descoperi că nu este disponibil când WiFi este oprit, pe aproape toate dispozitivele Android. Oprirea WiFi elimină dispozitivul la nivel de kernel. - person chrisdowney; 22.05.2012
comment
@Sanandrea - să recunoaștem, pe un dispozitiv rootat TOTUL poate fi falsificat. - person ocodo; 04.09.2013
comment
După cum se spune pe blogul Google, MAC nu este o opțiune bună. Este posibil să preluați o adresă Mac de la hardware-ul WiFi sau Bluetooth al unui dispozitiv. Nu vă recomandăm să utilizați acesta ca un identificator unic. Pentru început, nu toate dispozitivele au WiFi. De asemenea, dacă WiFi nu este pornit, este posibil ca hardware-ul să nu raporteze adresa Mac. android-developers.blogspot.com.es/2011/ 03/ - person jiahao; 01.06.2014
comment
Accesarea adresei MAC WiFi a fost blocată pe Android M: stackoverflow.com/questions/31329733/ - person breez; 22.12.2015
comment
Cel mai important, adresele MAC locale WiFi și Bluetooth nu mai sunt disponibile. Metoda getMacAddress() a unui obiect WifiInfo și metoda BluetoothAdapter.getDefaultAdapter().getAddress() vor reveni ambele02:00:00:00:00:00 de acum înainte - person sarika kate; 30.03.2016
comment
unele dispozitive nu pot avea wi-fi (cu experiență personală) - person Alberto M; 31.05.2016
comment
Din Android 6.x, returnează o adresă Mac falsă consecventă: 02:00:00:00:00:00 - person Behrouz.M; 10.07.2016
comment
android 10+ randomizează adresa mac, așa că nu recomand această soluție - person Hari Shankar S; 09.11.2020

Există informații destul de utile aici.

Acesta acoperă cinci tipuri de ID diferite:

  1. IMEI (numai pentru dispozitivele Android cu utilizarea telefonului; necesită android.permission.READ_PHONE_STATE)
  2. ID pseudo-unic (pentru toate dispozitivele Android)
  3. ID Android (poate fi nul, se poate modifica la resetarea din fabrică, poate fi modificat pe telefonul rootat)
  4. șir Adresă MAC WLAN (necesită android.permission.ACCESS_WIFI_STATE)
  5. Șir de adresă MAC BT (dispozitive cu Bluetooth, necesită android.permission.BLUETOOTH)
person stansult    schedule 08.02.2012
comment
Punct important omis (aici și în articol): nu puteți obține WLAN sau BT MAC decât dacă sunt pornite! Altfel, cred că WLAN MAC ar fi identificatorul perfect. Nu aveți nicio garanție că utilizatorul își va activa vreodată Wi-Fi și nu cred că este „potrivit” să îl porniți singur. - person Tom; 08.10.2012
comment
@Tom te înșeli. Puteți citi în continuare WLAN sau BT MAC chiar și atunci când sunt oprite. Cu toate acestea, nu există nicio garanție că dispozitivul are module WLAN sau BT disponibile. - person Marqs; 04.08.2014
comment
Cel mai important, adresele MAC locale WiFi și Bluetooth nu mai sunt disponibile. Metoda getMacAddress() a unui obiect WifiInfo și metoda BluetoothAdapter.getDefaultAdapter().getAddress() vor reveni ambele02:00:00:00:00:00 de acum înainte - person sarika kate; 30.03.2016
comment
@sarikakate Este adevărat doar în 6.0 Marshmallow și mai sus... Încă funcționează așa cum era de așteptat în sub 6.0 Marshmallow. - person Smeet; 13.04.2016

Este o întrebare simplă, fără un răspuns simplu.

Mai mult, toate răspunsurile existente aici sunt învechite sau nesigure.

Deci, dacă sunteți în căutarea unei soluții în 2020.

Iată câteva lucruri de luat în considerare:

Toți identificatorii bazați pe hardware (SSAID, IMEI, MAC etc.) nu sunt de încredere pentru dispozitivele non-google (Totul, cu excepția Pixels și Nexus), care reprezintă mai mult de 50% dintre dispozitivele active din întreaga lume. Prin urmare, cele mai bune practici oficiale privind identificatorii Android precizează clar:

Evitați să utilizați identificatori hardware, cum ar fi SSAID (ID Android), IMEI, adresa MAC etc...

Asta face ca majoritatea răspunsurilor de mai sus să fie invalide. De asemenea, datorită diferitelor actualizări de securitate Android, unele dintre ele necesită permisiuni de rulare mai noi și mai stricte, care pot fi pur și simplu refuzate de utilizator.

Ca exemplu CVE-2018-9489 care afectează toate tehnicile bazate pe WIFI menționate mai sus.

Acest lucru face ca acești identificatori nu numai să fie nesiguri, ci și inaccesibili în multe cazuri.

Deci, cu cuvinte mai simple: nu folosi aceste tehnici.

Multe alte răspunsuri de aici sugerează să utilizați AdvertisingIdClient, care este, de asemenea, incompatibil, deoarece designul său ar trebui utilizat numai pentru profilarea reclamelor. Este, de asemenea, menționat în referința oficială

Utilizați un ID de publicitate numai pentru profilarea utilizatorilor sau pentru cazurile de utilizare a anunțurilor

Nu este doar de încredere pentru identificarea dispozitivului, dar trebuie să urmați și politica privind confidențialitatea utilizatorului în ceea ce privește urmărirea anunțurilor, care prevede clar că utilizatorul o poate reseta sau bloca în orice moment.

Așa că nici nu îl folosiți.

Deoarece nu puteți avea identificatorul de dispozitiv unic și de încredere static dorit la nivel global. Referința oficială pentru Android sugerează:

Utilizați un FirebaseInstanceId sau un GUID stocat privat ori de câte ori este posibil pentru toate celelalte cazuri de utilizare, cu excepția prevenirii fraudei la plată și a telefoniei.

Este unic pentru instalarea aplicației pe dispozitiv, așa că atunci când utilizatorul dezinstalează aplicația - este șters, deci nu este 100% fiabil, dar este cel mai bun lucru.

Pentru a utiliza FirebaseInstanceId adăugați cea mai recentă dependență de mesagerie Firebase în gradul dvs.

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

Și folosiți codul de mai jos într-un thread de fundal:

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

Dacă trebuie să stocați identificarea dispozitivului pe serverul dvs. la distanță, atunci nu o stocați așa cum este (text simplu), ci o haș cu sare.

Astăzi nu este doar o practică bună, ci trebuie să o faci prin lege, conform GDPR - identificatori și reglementări similare.

person Nikita Kurtin    schedule 28.11.2019
comment
Deocamdată, acesta este cel mai bun răspuns, iar prima propoziție este cel mai bun rezumat: este o întrebare simplă, fără un răspuns simplu - doar iubește-l. - person b2mob; 22.01.2020
comment
@M.UsmanKhan, răspunsul este scris imediat după aceea: Astăzi nu este doar o bună practică, de fapt trebuie să o faci prin lege, conform GDPR - identificatori și reglementări similare. - person Nikita Kurtin; 08.03.2020
comment
Ați putea specifica ce secțiune a linkului GDPR pe care l-ați postat menționează de fapt cerința pentru codurile hashing? - person David Schneider; 21.07.2020
comment
@DavidSchneider, conținutul web este dinamic în natura sa, iar GDPR este doar unul dintre exemple, vă rugăm să rețineți că am scris GDPR și reglementări similare, deoarece există multe reglementări locale și globale care vă afectează produs/sistem/domeniu. În orice caz, secțiunile GDPR pe care le căutați sunt: ​​Identificare, Identificatori online și Principii de protecție a datelor - person Nikita Kurtin; 21.07.2020
comment
proandroiddev.com/ - person william gouvea; 03.01.2021
comment
ID-ul unic firebase se va schimba dacă aplicația este reinstalată - person famfamfam; 23.02.2021
comment
@famfamfam, exact - de aceea am scris că: Este unic pentru instalarea aplicației pe dispozitiv, așa că atunci când utilizatorul dezinstalează aplicația - este ștearsă, deci nu este 100% fiabilă, dar este următorul lucru cel mai bun . - person Nikita Kurtin; 25.02.2021
comment
mulțumesc, mă întreb de ce Android nu poate face ANDROID_ID pe dispozitiv uuid, astfel încât codul de dezvoltator al Android este mai greu - person famfamfam; 25.02.2021
comment
@famfamfam Cea mai bună presupunere a mea ar fi că asta se datorează naturii deschise a Android-ului și platformei pseudoaleatoare UUID.randomUUID() a Java, care depindea de natură bazată pe timp. - person Nikita Kurtin; 25.02.2021
comment
Așteptați, nu sunt multe circumstanțe care ar determina schimbarea de la o valoare la alta? - person Michael Paccione; 03.07.2021

Blogul oficial pentru dezvoltatori Android are acum un articol complet despre acest subiect, Identificarea Instalări de aplicații.

person BoD    schedule 06.04.2011
comment
Și punctul cheie al acestui argument este că, dacă încercați să obțineți un ID unic din hardware, probabil că faceți o greșeală. - person Tim Bray; 12.04.2011
comment
Și dacă permiteți resetarea blocării dispozitivului printr-o resetare din fabrică, modelul dvs. de probă este la fel de bun. - person Seva Alekseyev; 04.05.2011
comment
Iar postarea de blog are deja linkuri către acest site: developer.android.com/training/ articole/user-data-ids - person Bruno Bieri; 16.09.2020

La Google I/O, Reto Meier a lansat un răspuns solid despre cum să abordăm acest lucru, care ar trebui să răspundă nevoilor majorității dezvoltatorilor de a urmări utilizatorii din toate instalațiile. Anthony Nolan arată direcția în răspunsul său, dar m-am gândit să scriu abordarea completă, astfel încât alții să poată vedea cu ușurință cum să o facă (mi-a luat ceva timp să-mi dau seama de detalii).

Această abordare vă va oferi un ID de utilizator anonim, securizat, care va fi persistent pentru utilizator pe diferite dispozitive (pe baza contului Google principal) și pe parcursul instalărilor. Abordarea de bază este generarea unui ID de utilizator aleatoriu și stocarea acestuia în preferințele comune ale aplicațiilor. Apoi utilizați agentul de rezervă Google pentru a stoca preferințele partajate legate de contul Google în cloud.

Să trecem prin abordarea completă. În primul rând, trebuie să creăm o copie de rezervă pentru SharedPreferences folosind serviciul Android Backup. Începeți prin a vă înregistra aplicația prin http://developer.android.com/google/backup/signup.html.

Google vă va oferi o cheie de serviciu de rezervă pe care trebuie să o adăugați la manifest. De asemenea, trebuie să spuneți aplicației să folosească BackupAgent după cum urmează:

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

Apoi, trebuie să creați agentul de rezervă și să îi spuneți să folosească agentul de ajutor pentru preferințe partajate:

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

Pentru a finaliza backup-ul, trebuie să creați o instanță a BackupManager în Activitatea principală:

BackupManager backupManager = new BackupManager(context);

În cele din urmă, creați un ID de utilizator, dacă nu există deja și stocați-l în 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;
}

Acest User_ID va fi acum persistent în toate instalările, chiar dacă utilizatorul mută dispozitivul.

Pentru mai multe informații despre această abordare, consultați Discursul lui Reto.

Și pentru detalii complete despre cum să implementați agentul de rezervă, consultați Copia de rezervă a datelor. Recomand în special secțiunea din partea de jos despre testare, deoarece backup-ul nu are loc instantaneu, așa că pentru a testa trebuie să forțați backup-ul.

person TechnoTony    schedule 22.12.2012
comment
Acest lucru nu duce la mai multe dispozitive cu același ID atunci când un utilizator are mai multe dispozitive? O tabletă și un telefon, de exemplu. - person Tosa; 13.03.2013

Cred că acesta este un mod sigur de a construi un schelet pentru un ID unic... verifică-l.

ID pseudo-unic, care funcționează pe toate dispozitivele Android Unele dispozitive nu au telefon (de exemplu, tablete) sau, dintr-un motiv oarecare, nu doriți să includeți permisiunea READ_PHONE_STATE. Puteți citi în continuare detalii precum versiunea ROM, numele producătorului, tipul procesorului și alte detalii hardware, care vor fi potrivite dacă doriți să utilizați ID-ul pentru verificarea cheii de serie sau în alte scopuri generale. ID-ul calculat în acest fel nu va fi unic: este posibil să găsiți două dispozitive cu același ID (pe baza aceluiași hardware și imagine ROM), dar schimbările în aplicațiile din lumea reală sunt neglijabile. În acest scop puteți folosi clasa 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

Majoritatea membrilor Build sunt șiruri, ceea ce facem aici este să le luăm lungimea și să o transformăm prin modulo într-o cifră. Avem 13 astfel de cifre și mai adăugăm două în față (35) pentru a avea aceeași dimensiune ID ca și IMEI (15 cifre). Există și alte posibilități aici sunt bune, aruncați o privire la aceste șiruri. Returnează ceva de genul 355715565309247. Nu este necesară nicio permisiune specială, ceea ce face această abordare foarte convenabilă.


(Informații suplimentare: tehnica prezentată mai sus a fost copiată dintr-un articol de pe Pocket Magic.)

person Lenn Dolling    schedule 24.03.2011
comment
Interesanta solutie. Se pare că aceasta este o situație în care într-adevăr ar trebui să faci hashing toate acele date concatenate în loc să încerci să creezi propria ta funcție hash. Există multe situații în care ați obține coliziuni chiar dacă există date substanțiale care sunt diferite pentru fiecare valoare. Recomandarea mea: utilizați o funcție hash și apoi transformați rezultatele binare în zecimale și trunchiați-le după cum este necesar. Pentru a face acest lucru corect, deși ar trebui să utilizați cu adevărat un UUID sau un șir hash complet. - person Steve Pomeroy; 12.04.2011
comment
Am descoperit că Build.CPU_ABI și Build.MANUFACTURER nu sunt prezente în toate versiunile.. Primeam erori severe de build când rulam împotriva ‹2.2 :) - person Lenn Dolling; 15.05.2011
comment
Ar trebui să acordați credit surselor dvs.... Acest lucru a fost eliminat direct din următorul articol: pocketmagic. net/?p=1662 - person Steve Haley; 16.05.2011
comment
Acest ID este deschis pentru coliziuni ca și cum nu știți ce. Este practic garantat că va fi același pe dispozitive identice de la același operator. - person Seva Alekseyev; 27.05.2011
comment
Acest lucru se poate schimba și dacă dispozitivul este actualizat. - person David Given; 25.01.2012
comment
Nu cred că este o idee bună să folosiți această soluție. După cum am înțeles, toate câmpurile Build vor fi aceleași pentru toate telefoanele produse împreună. - person Victor Ronin; 26.07.2012
comment
După comentariul lui David Given, aceasta pare a fi o îngrijorare serioasă. Ar trebui făcut un inventar atent al atributelor Build pentru a determina care dintre ele este puțin probabil să se schimbe ca urmare a unei actualizări over-the-air. De exemplu, Build.DISPLAY de mai sus, conform Javadoc, este Un șir de ID de compilare menit pentru a fi afișat utilizatorului, așa că nu s-ar putea modifica atunci când are loc o actualizare? Încă cred că această abordare ar putea adăuga atribute distinctive utile în combinație cu alte informații de pe dispozitiv, dar numai dacă astfel de atribute modificabile prin OTA pot fi selectate cu atenție. - person Carl; 23.12.2012
comment
De asemenea, Build.HOST este definit ca un șir care identifică în mod unic gazda pe care a fost construită construcția, în format care poate fi citit de om. Se pare cu totul posibil ca diferite mașini BUILD să poată fi folosite pentru a crea versiunea pentru o actualizare OTA. - person Carl; 23.12.2012
comment
Soluție foarte, foarte proastă. Testat pe două Nexus 5... Returnează aceleași numere. - person Sinan Dizdarević; 04.03.2015

Următorul cod returnează numărul de serie al dispozitivului folosind un API Android ascuns. Dar, acest cod nu funcționează pe Samsung Galaxy Tab, deoarece „ro.serialno” nu este setat pe acest dispozitiv.

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

Folosind codul de mai jos, puteți obține ID-ul unic de dispozitiv al unui dispozitiv cu sistem de operare Android ca șir.

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

Un câmp Serial a fost adăugat la clasa Build la nivelul API 9 (Android 2.3 - Turtă dulce). Documentația spune că reprezintă numărul de serie hardware. Astfel, ar trebui să fie unic, dacă există pe dispozitiv.

Totuși, nu știu dacă este acceptat (=nu nul) de toate dispozitivele cu nivel API >= 9.

person rony l    schedule 06.03.2011
comment
Din păcate, nu se știe. - person m0skit0; 15.04.2013

Un lucru aș adăuga - am una dintre acele situații unice.

Folosind:

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

Se pare că, deși tableta mea Viewsonic G raportează un DeviceID care nu este Null, fiecare tabletă G raportează același număr.

O face interesantă să joci „Pocket Empires”, care îți oferă acces instantaneu la contul cuiva, pe baza ID-ului dispozitivului „unic”.

Dispozitivul meu nu are un radio celular.

person Tony Maro    schedule 21.03.2011
comment
@Treewallie funcționează? Puteți obține același ID de dispozitiv din aplicații diferite? - person Arnold Brown; 04.02.2020

Pentru instrucțiuni detaliate despre cum să obțineți un identificator unic pentru fiecare dispozitiv Android de pe care este instalată aplicația dvs., consultați postarea oficială pe blogul dezvoltatorilor Android Identificarea instalărilor de aplicații.

Se pare că cel mai bun mod este să generați unul singur la instalare și să îl citiți ulterior când aplicația este relansată.

Eu personal consider acest lucru acceptabil, dar nu ideal. Niciun identificator furnizat de Android nu funcționează în toate cazurile, deoarece majoritatea depind de stările radio ale telefonului (Wi-Fi activat/dezactivat, pornit/dezactivat mobil, Bluetooth activat/dezactivat). Celelalte, cum ar fi Settings.Secure.ANDROID_ID, trebuie implementate de producător și nu sunt garantate a fi unice.

Următorul este un exemplu de scriere a datelor într-un fișier de instalare care ar fi stocat împreună cu orice alte date pe care aplicația le salvează local.

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
Dacă doriți să urmăriți instalările aplicației, acest lucru este perfect. Cu toate acestea, urmărirea dispozitivelor este mult mai dificilă și nu pare să existe o soluție complet etanșă. - person Luca Spiller; 03.10.2011
comment
Dar dispozitivele rootate? Ei pot schimba cu ușurință acest ID de instalare, nu? - person tasomaniac; 10.05.2012
comment
Absolut. Root poate schimba ID-ul de instalare. Puteți verifica dacă există root folosind acest bloc de cod: stackoverflow.com/questions/1101380/ - person Kevin Parker; 18.05.2012
comment
dacă resetăm din fabrică, se va șterge fișierul? - person Jamshid; 08.01.2015
comment
Dacă resetați din fabrică și ștergeți sau formatați partiția /data, UUID-ul este diferit. - person Kevin Parker; 12.01.2015

Adăugați codul de mai jos în fișierul clasei:

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

Adăugați în AndroidManifest.xml:

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

Există o mulțime de abordări diferite pentru a rezolva aceste ANDROID_ID probleme (poate fi null uneori sau dispozitivele unui anumit model returnează întotdeauna același ID) cu argumente pro și contra:

  • Implementarea unui algoritm personalizat de generare a ID-ului (bazat pe proprietățile dispozitivului care ar trebui să fie statice și nu se vor schimba -> cine știe)
  • Abuzul de alte ID-uri, cum ar fi IMEI, numărul de serie, adresa Wi-Fi/Bluetooth-MAC (se vor nu există pe toate dispozitivele sau devin necesare permisiuni suplimentare)

Eu prefer să folosesc o implementare OpenUDID existentă (vezi https://github.com/ylechelle/OpenUDID) pentru Android (consultați https://github.com/vieux/OpenUDID). Este ușor de integrat și folosește ANDROID_ID cu alternative pentru problemele menționate mai sus.

person Andreas Klöber    schedule 18.11.2012

ID-ul unic de dispozitiv al unui dispozitiv cu sistem de operare Android ca String, folosind TelephonyManager și ANDROID_ID, este obținut prin:

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

Dar recomand cu tărie o metodă sugerată de Google, consultați Identificare Instalări de aplicații.

person Jorgesys    schedule 13.01.2014

Există peste 30 de răspunsuri aici și unele sunt aceleași, iar altele sunt unice. Acest răspuns se bazează pe câteva dintre aceste răspunsuri. Unul dintre ele este răspunsul lui @Lenn Dolling.

Combină 3 ID-uri și creează un șir hexadecimal de 32 de cifre. A funcționat foarte bine pentru mine.

3 ID-uri sunt:
Pseudo-ID - Este generat pe baza specificațiilor dispozitivului fizic
ANDROID_ID - Settings.Secure.ANDROID_ID
Adresa Bluetooth - Adresa adaptorului Bluetooth

Va returna ceva de genul acesta: 551F27C060712A72730B0A0F734064B1

Notă: puteți adăuga oricând mai multe ID-uri la șirul longId. De exemplu, Serial #. adresa adaptorului wifi. IMEI. În acest fel, îl faceți mai unic pentru fiecare dispozitiv.

@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
Adăugarea UUID la longId și stocarea acestuia într-un fișier, îl va face cel mai unic identificator : String uuid = UUID.randomUUID().toString(); - person Mousa Alfhaily; 11.04.2017
comment
Dacă toate celelalte nu reușesc, dacă utilizatorul are o versiune mai mică decât API 9 (mai mică decât Gingerbread), și-a resetat telefonul sau „Secure.ANDROID_ID”. dacă returnează „null”, atunci pur și simplu ID-ul returnat se va baza exclusiv pe informațiile dispozitivului Android. Aici se pot produce ciocnirile. Încercați să nu utilizați DISPLAY, HOST sau ID - aceste elemente se pot schimba. Dacă există coliziuni, vor exista date care se suprapun. Sursa: gist.github.com/pedja1/fe69e8a80ed505500caa - person Mousa Alfhaily; 11.04.2017
comment
@Ninja Deoarece adresa mac BLE este unică, da, ID-ul generat va fi întotdeauna unic. Cu toate acestea, dacă doriți cu adevărat să fiți sigur, aș sugera să adăugați un UUID la longId. Schimbați acea linie astfel: String longId = pseudoId + androidId + btId + UUID.randomUUID().toString(); Acest lucru garantează că ID-ul generat va fi unic. - person ᴛʜᴇᴘᴀᴛᴇʟ; 03.04.2019

Ce zici de IMEI. Este unic pentru Android sau alte dispozitive mobile.

person Elzo Valugi    schedule 14.07.2011
comment
Nu pentru tabletele mele, care nu au IMEI, deoarece nu se conectează la operatorul meu de telefonie mobilă. - person Brill Pappin; 05.01.2012
comment
Ca să nu mai vorbim de dispozitivele CDMA care au un ESN în loc de un IMEI. - person David Given; 25.01.2012
comment
Doar asta va face dacă este un telefon :) O tabletă nu poate. - person Brill Pappin; 26.01.2012
comment
@ElzoValugi Sunt deja zilele astea și încă nu toate tabletele au carduri SIM. - person MLQ; 25.09.2012

Iată cum generez ID-ul unic:

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
dacă folosim ReadPhoneState în versiunea 6.0 cerem permisiunea de rulare - person Harsha; 17.11.2016

Cei doi cenți ai mei - NB, acesta este pentru un ID unic de dispozitiv (err) - nu pentru cel de instalare, așa cum se discută în Blogul dezvoltatorilor Android.

De reținut că soluția furnizată de @emmby revine într-un ID per aplicație, deoarece SharedPreferences nu sunt sincronizate între procese (consultați aici și aici). Așa că am evitat acest lucru cu totul.

În schimb, am încapsulat diferitele strategii pentru obținerea unui ID (dispozitiv) într-o enumerare - schimbarea ordinii constantelor enumerare afectează prioritatea diferitelor modalități de obținere a ID-ului. Primul ID non-null este returnat sau se aruncă o excepție (conform bunelor practici Java de a nu da un sens null). Așa că, de exemplu, am primul TELEPHONY - dar o alegere implicită bună ar fi 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

O altă modalitate este să utilizați /sys/class/android_usb/android0/iSerial într-o aplicație fără nicio permisiune.

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

Pentru a face acest lucru în Java, ar trebui doar să folosiți un FileInputStream pentru a deschide fișierul iSerial și a citi caracterele. Doar asigurați-vă că îl includeți într-un handler de excepții, deoarece nu toate dispozitivele au acest fișier.

Se știe că cel puțin următoarele dispozitive au acest fișier lizibil în întreaga lume:

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

De asemenea, puteți vedea articolul meu de blog Scurgeri de hardware Android număr de serie către aplicații neprivilegiate, unde discut despre ce alte fișiere sunt disponibile pentru informații.

person insitusec    schedule 31.01.2013
comment
Tocmai am citit postarea ta pe blog. Cred că acest lucru nu este unic: Build.SERIAL este disponibil și fără permisiuni și este (teoretic) un număr de serie hardware unic. - person Tom; 01.05.2013
comment
Ai dreptate. Este doar o altă modalitate prin care dispozitivul dvs. poate fi urmărit și, după cum ați spus, ambele moduri nu necesită permisiuni pentru aplicații. - person insitusec; 14.03.2014

TelephonyManger.getDeviceId() Returnează ID-ul unic al dispozitivului, de exemplu, IMEI pentru GSM și MEID sau ESN pentru telefoanele CDMA.

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

Dar recomand să folosești:

Settings.Secure.ANDROID_ID care returnează ID-ul Android ca un șir hexadecimal unic de 64 de biți.

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

Uneori, TelephonyManger.getDeviceId() va returna null, așa că pentru a asigura un ID unic, veți folosi această metodă:

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
Am descoperit recent că dispozitivul unui client de tip SM-G928F / Galaxy S6 edge+ oferă doar 15 cifre hexadecimale în loc de 16 pentru ID-ul Android. - person Holger Jakobs; 13.03.2016

ID de instanță Google

Lansat la I/O 2015; pe Android necesită servicii de redare 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

Se pare că Google intenționează ca acest ID să fie utilizat pentru a identifica instalările pe Android, Chrome și iOS.

Identifică o instalare mai degrabă decât un dispozitiv, dar, din nou, ANDROID_ID (care este răspunsul acceptat) acum nu mai identifică nici dispozitivele. Cu timpul de execuție ARC este generat un nou ANDROID_ID pentru fiecare instalare (detalii aici), la fel ca acest nou ID de instanță. De asemenea, cred că identificarea instalațiilor (nu a dispozitivelor) este ceea ce caută de fapt majoritatea dintre noi.

Avantajele ID-ului instanței

Mi se pare că Google intenționează ca acesta să fie utilizat în acest scop (identificarea instalărilor dvs.), este multiplatformă și poate fi folosit în mai multe alte scopuri (consultați linkurile de mai sus).

Dacă utilizați GCM, în cele din urmă va trebui să utilizați acest ID de instanță, deoarece aveți nevoie de el pentru a obține indicativul GCM (care înlocuiește vechiul ID de înregistrare GCM).

Dezavantajele/problemele

În implementarea curentă (GPS 7.5), ID-ul instanței este preluat de pe un server atunci când aplicația dvs. îl solicită. Aceasta înseamnă că apelul de mai sus este un apel de blocare - în testarea mea neștiințifică durează 1-3 secunde dacă dispozitivul este online și 0,5 - 1,0 secunde dacă este offline (probabil că acesta este cât timp așteaptă înainte de a renunța și de a genera un ID aleatoriu). Acesta a fost testat în America de Nord pe Nexus 5 cu Android 5.1.1 și GPS 7.5.

Dacă utilizați ID-ul în scopurile pe care le intenționează - de ex. autentificarea aplicației, identificarea aplicației, GCM - Cred că aceste 1-3 secunde ar putea fi o pacoste (în funcție de aplicația dvs., desigur).

person Tom    schedule 19.06.2015
comment
Un alt dezavantaj semnificativ al instanceID este că un nou instanceID va fi generat pentru dvs. dacă utilizatorul șterge datele aplicației. - person idanakav; 08.07.2015
comment
Interesant, dar nu cred că schimbă cu adevărat cazurile de utilizare potențiale: ID-ul instanței, precum android_id, nu este potrivit pentru identificarea unui dispozitiv. Așadar, serverul dvs. va vedea datele despre ștergerea utilizatorului ca și cum ar fi dezinstalarea și reinstalarea aplicației de către utilizator - ceea ce nu este nerezonabil. - person Tom; 08.07.2015

Pentru recunoașterea hardware a unui anumit dispozitiv Android, puteți verifica adresele MAC.

poti face asa:

în AndroidManifest.xml

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

acum in codul tau:

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

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

În fiecare dispozitiv Android există cel puțin o interfață „wlan0” care este cipul WI-FI. Acest cod funcționează chiar și atunci când WI-FI nu este pornit.

P.S. Sunt o grămadă de alte interfețe pe care le veți obține din lista care conține MACS, dar acest lucru se poate schimba între telefoane.

person Ilan.b    schedule 01.09.2015

Folosesc următorul cod pentru a obține IMEI sau pentru a folosi Secure.ANDROID_ID ca alternativă, când dispozitivul nu are capabilități de telefon:

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

Pentru a înțelege ID-urile unice disponibile pe dispozitivele Android. Utilizați acest ghid oficial.

Cele mai bune practici pentru identificatorii unici:

IMEI, adrese Mac, ID de instanță, GUID-uri, SSAID, ID de publicitate, API Safety Net pentru a verifica dispozitivele.

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

person Waheed Nazir    schedule 03.05.2019

Google are acum un ID de publicitate.
Acesta poate, de asemenea, fi folosit, dar rețineți că:

ID-ul de publicitate este un ID specific utilizatorului, unic, resetabil

și

permite utilizatorilor să își resetați identificatorul sau să renunțe la anunțurile bazate pe interese din aplicațiile Google Play.

Deci, deși acest ID se poate schimba, se pare că în curând s-ar putea să nu avem de ales, depinde de scopul acestui id.

Mai multe informații @ develper.android

Copiați și inserați codul aici

HTH

person Hertzel Guinness    schedule 02.11.2013
comment
Poate fi resetat: ID-ul de publicitate este un identificator de șir unic, dar resetat de utilizator, care permite rețelelor publicitare și altor aplicații să identifice în mod anonim un utilizator. - person Jared Burrows; 06.11.2013
comment
(@JaredBurrows da, este menționat în postare...) - person Hertzel Guinness; 06.11.2013

1.Utilizați managerul de telefonie, care oferă un ID unic (adică IMEI). Vezi exemplul,

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

Acest lucru necesită android.permission.READ_PHONE_STATE utilizatorului dvs., ceea ce poate fi greu de justificat în funcție de tipul de aplicație pe care ați făcut-o.

  1. Dispozitivele fără servicii de telefonie, cum ar fi tabletele, trebuie să raporteze un ID unic de dispozitiv care este disponibil prin android.os.Build.SERIAL începând cu Android 2.3 Gingerbread. Unele telefoane care au servicii de telefonie pot defini, de asemenea, un număr de serie. Deoarece nu toate dispozitivele Android au un număr de serie, această soluție nu este de încredere.

  2. La prima pornire a dispozitivului, este generată și stocată o valoare aleatorie. Această valoare este disponibilă prin Settings.Secure.ANDROID_ID. Este un număr pe 64 de biți care ar trebui să rămână constant pe durata de viață a unui dispozitiv. ANDROID_ID pare o alegere bună pentru un identificator unic de dispozitiv, deoarece este disponibil pentru smartphone-uri și tablete. Pentru a prelua valoarea, puteți utiliza următorul cod,

    String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

Cu toate acestea, valoarea se poate modifica dacă se efectuează o resetare din fabrică pe dispozitiv. Există, de asemenea, o eroare cunoscută cu un telefon popular de la un producător, în care fiecare instanță are același ANDROID_ID. În mod clar, soluția nu este 100% fiabilă.

  1. Utilizați UUID. Deoarece cerința pentru majoritatea aplicațiilor este identificarea unei anumite instalări și nu a unui dispozitiv fizic, o soluție bună pentru a obține ID-ul unic pentru un utilizator dacă folosește clasa UUID. Următoarea soluție a fost prezentată de Reto Meier de la Google într-o prezentare Google I/O,
SharedPreferences sharedPrefs = context.getSharedPreferences(
         PREF_UNIQUE_ID, Context.MODE_PRIVATE);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);

Actualizare: opțiunea #1 și #2 nu mai sunt disponibile după Android 10, deoarece confidențialitatea este actualizată de către Google. ca opțiunea 2 și 3 necesită permisiunea critică.

person Kiran Maniya    schedule 05.10.2018
comment
Care telefon este cel în care fiecare instanță are același ANDROID_ID? - person viper; 26.08.2019
comment
consultați documentele oficiale developer.android.com/reference/ android/furnizor/ - person Kiran Maniya; 26.08.2019
comment
DeviceInfoProvider nu face parte din Android SDK - person user924; 06.02.2020
comment
Mulțumesc, @user924 pentru că ai subliniat asta. Dacă aveți mai multe detalii, puteți edita răspunsul pentru a-l îmbunătăți. - person Kiran Maniya; 06.02.2020
comment
@KiranManiya Editează răspunsul inventat. Cum cred oamenii să știe cum să-l editeze dacă l-ai inventat? Tu ești cel care ar trebui să-l editezi. Nu răspunde la o întrebare aici cu iluzia ta - person jerinho.com; 25.04.2020
comment
@jerinho Mulțumesc mult. Cred că ai trecut prin ambele răspunsuri ale mele. - person Kiran Maniya; 26.04.2020

ID-ul mac al dispozitivului Android este, de asemenea, un id unic. Nu se va schimba chiar dacă dispozitivul în sine este formatat.

Utilizați următorul cod pentru a obține ID-ul mac:

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

De asemenea, nu uitați să adăugați permisiunile corespunzătoare în AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
person Baskaran Veerabathiran    schedule 03.10.2016
comment
Din păcate, acest lucru nu va funcționa dacă nu există o conexiune WiFi actuală. Din documentele (sublinierea adăugată ): Returnați informații dinamice despre conexiunea Wi-Fi actuală, dacă este activă. - person Ted Hopp; 05.10.2016
comment
De asemenea, acordând acces root pe dispozitiv, se poate falsifica adresa Mac - person ; 03.07.2017
comment
Dispozitivele care rulează Android 10 (nivel API 29) și o versiune ulterioară raportează adrese MAC aleatorii pentru toate aplicațiile care nu sunt aplicații proprietare de dispozitiv. Deci, nu va fi unic atunci când aveți versiunea Android 10 sau o versiune ulterioară - person Saddan; 23.05.2020

Doar un avertisment pentru toți cei care citesc care caută mai multe informații actualizate. Cu Android O, există unele modificări ale modului în care sistemul gestionează aceste ID-uri.

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

tl;dr Serial va necesita permisiunea TELEFON, iar ID-ul Android se va schimba pentru diferite aplicații, în funcție de numele și semnătura pachetului.

Și, de asemenea, Google a creat un document frumos care oferă sugestii despre când să utilizați ID-urile hardware și software.

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

person bugraoral    schedule 11.04.2017

În mod normal, folosesc ID-ul unic al dispozitivului pentru aplicațiile mele. Dar uneori folosesc IMEI. Ambele sunt numere unice.

pentru a obține IMEI (identificatorul internațional de echipament mobil)

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

pentru a obține ID unic al dispozitivului

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

Am întâlnit această întrebare în urmă cu câțiva ani și am învățat să implementez o soluție generalizată bazată pe diferite răspunsuri.

Am folosit soluția generalizată de câțiva ani, într-un produs din lumea reală. Imi serveste destul de bine pana acum. Iată fragmentul de cod, bazat pe diferite răspunsuri furnizate.

Rețineți, getEmail va returna null de cele mai multe ori, deoarece nu am cerut permisiunea în mod explicit.

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
Dar funcționează acest lucru atunci când utilizatorul își resetează telefonul? în acest caz, id-ul Android se va schimba, id-ul de publicitate este resetat și, de asemenea, e-mail-ul. - person G3n1t0; 09.03.2021

Nu este recomandat ca deviceId poate fi folosit ca urmărire în mâinile terților, dar aceasta este o altă modalitate.

@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 efectuează câteva modificări pe: Settings.Secure.ANDROID_ID; Pe Android 8.0 (API nivel 26) și versiunile superioare ale platformei, un număr de 64 de biți (exprimat ca șir hexazecimal), unic pentru fiecare combinație de cheie de semnare a aplicației, utilizator și dispozitiv. Aceasta înseamnă că Settings.Secure.ANDROID_ID returnează acum ID-uri care sunt unice pentru combinația aplicație/dispozitiv, ceea ce face lucrurile mai sigure pentru utilizator. - person Jeff Padgett; 22.06.2018

Iată un răspuns simplu pentru a obține AAID, testat funcțional corect în iunie 2019

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

citește răspunsul complet în detaliu aici:

person Raj    schedule 11.06.2019

Obțineți DUUID-ul dispozitivului, numărul de model cu numele mărcii și numărul său de versiune cu ajutorul funcției de mai jos.

Funcționează în Android 10 perfect și nu este nevoie să permiteți permisiunea de citire a stării telefonului.

Fragmente de cod:

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

Funcția Apelați deasupra și pentru a verifica rezultatul codului de mai sus. vă rugăm să vedeți pisica de jurnal în Android Studio. Arata ca mai jos:

introduceți descrierea imaginii aici

person CodeInsideCoffee    schedule 07.06.2020
comment
care este %10 și 35+... din codul tău? Adică de ce folosești această abordare pentru a construi un ID unic? de ce să nu combinați pur și simplu acele șiruri împreună și să generați un UUID unic? este rezultatul acestei metode complet unic pentru toate dispozitivele din lume? - person porya74; 15.06.2020

Pentru a include Android 9, am o singură idee care ar putea funcționa și care (probabil) nu încalcă niciun termen, necesită permisiuni și funcționează în toate instalările și aplicațiile.

Amprentarea digitală care implică un server ar trebui să poată identifica un dispozitiv în mod unic. Combinația de informații hardware + aplicații instalate și timpii de instalare ar trebui să facă truc. Timpul de instalare nu se modifică decât dacă o aplicație este dezinstalată și instalată din nou. Dar acest lucru ar trebui făcut pentru toate aplicațiile de pe dispozitiv pentru a nu putea identifica dispozitivul (adică după o resetare din fabrică).

Iată cum aș proceda:

  1. Extrageți informații despre hardware, numele pachetelor de aplicații și primele instalări.

Iată cum extrageți toate aplicațiile de pe Android (nu sunt necesare permisiuni):

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. Este posibil să doriți să faceți un hash pentru fiecare nume de pachet și combinația de marcaj de timp al instalării, înainte de a-l trimite la server, deoarece poate fi sau nu ceea ce utilizatorul a instalat pe dispozitiv.
  2. Unele aplicații (de fapt multe) sunt aplicații de sistem. Este posibil ca acestea să aibă același marcaj temporal de instalare, care se potrivește cu cea mai recentă actualizare a sistemului după o resetare din fabrică. Deoarece au același timp de instalare, acestea nu pot fi instalate de utilizator și pot fi filtrate.
  3. Trimiteți informațiile către server și lăsați-l să caute cea mai apropiată potrivire dintre informațiile stocate anterior. Trebuie să stabiliți un prag atunci când comparați cu informațiile stocate anterior pe dispozitiv, deoarece aplicațiile sunt instalate și dezinstalate. Dar presupunerea mea este că acest prag poate fi foarte scăzut, deoarece orice nume de pachet și combinația de marcaj temporal de instalare pentru prima dată va fi destul de unică pentru un dispozitiv, iar aplicațiile nu sunt instalate și dezinstalate atât de frecvent. Având mai multe aplicații, crește probabilitatea de a fi unic.
  4. Returnați ID-ul unic generat pentru meci sau generați un ID unic, stocați cu informații despre dispozitiv și returnați acest nou ID.

NB: Aceasta este o metodă netestată și nedovedită! Sunt încrezător că va funcționa, dar sunt, de asemenea, destul de sigur că, dacă acest lucru va ajunge, o vor închide într-un fel sau altul.

person Jens Vesti    schedule 31.01.2019

Daca adaugati:

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

Android Lint vă va oferi următorul avertisment:

Utilizarea getString pentru a obține identificatori de dispozitiv nu este recomandată. Informații de inspecție: utilizarea acestor identificatori de dispozitiv nu este recomandată decât pentru prevenirea fraudei de mare valoare și cazuri de utilizare avansate pentru telefonie. Pentru cazurile de utilizare în publicitate, utilizați AdvertisingIdClient$Info#getId și pentru analize, utilizați InstanceId#getId.

Deci, ar trebui să evitați să utilizați acest lucru.

După cum este menționat în documentația pentru dezvoltatori Android :

1: Evitați utilizarea identificatorilor hardware.

În majoritatea cazurilor de utilizare, puteți evita utilizarea identificatorilor hardware, cum ar fi SSAID (ID Android) și IMEI, fără a limita funcționalitatea necesară.

2: Folosiți un ID de publicitate numai pentru profilarea utilizatorilor sau pentru cazurile de utilizare pentru anunțuri.

Când utilizați un ID de publicitate, respectați întotdeauna selecțiile utilizatorilor cu privire la urmărirea anunțurilor. De asemenea, asigurați-vă că identificatorul nu poate fi conectat la informații de identificare personală (PII) și evitați resetarea ID-ului publicitar.

3: Folosiți un ID de instanță sau un GUID stocat privat ori de câte ori este posibil pentru toate celelalte cazuri de utilizare, cu excepția prevenirii fraudei la plată și a telefoniei.

Pentru marea majoritate a cazurilor de utilizare non-reclame, un ID de instanță sau un GUID ar trebui să fie suficient.

4: Utilizați API-uri adecvate pentru cazul dvs. de utilizare pentru a minimiza riscul de confidențialitate.

Utilizați API-ul DRM pentru protecția conținutului de mare valoare și API-urile SafetyNet pentru protecția împotriva abuzurilor. API-urile SafetyNet sunt cea mai simplă modalitate de a determina dacă un dispozitiv este autentic, fără a implica riscuri de confidențialitate.

person Malwinder Singh    schedule 24.07.2019

String SERIAL_NUMER = Build.SERIAL;

Returnează NUMĂRUL DE SERIE ca șir unic pentru fiecare dispozitiv.

person Jeffy    schedule 07.09.2017

Numărul de serie este un ID unic de dispozitiv disponibil prin 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;
}

Asigurați-vă că aveți permisiunea READ_PHONE_STATE înainte de a apela getSerial().

NOTĂ:- este nu este disponibil pentru dispozitive fără telefonie (cum ar fi tabletele numai cu Wi-Fi).

person shivampip    schedule 14.12.2017
comment
Rețineți că documentele spun că acest lucru va returna numărul de serie hardware dacă este disponibil, sugerând că Build.SERIAL (sau Build.getSerial()) nu este întotdeauna disponibil. Mai multe informații sunt disponibile în postarea de blog Modificări ale Identificatori de dispozitiv în Android O. De asemenea, merită citit: Cele mai bune practici pentru identificatorii unici. - person Ted Hopp; 14.12.2017

Pentru a fi complet, iată cum puteți obține Id în Xamarin.Android și C#:

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

Sau dacă nu vă aflați într-un Activity:

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

Unde context este transmis în context.

person Martin Zikmund    schedule 21.01.2019

android.telephony.TelephonyManager.getDeviceId()

Aceasta va returna orice șir care identifică în mod unic dispozitivul (IMEI pe GSM, MEID pentru CDMA).

Veți avea nevoie de următoarea permisiune în AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
person Anubhav    schedule 25.09.2019
comment
Este depreciat - person Googlian; 23.10.2019

Da, fiecare dispozitiv Android are numere de serie unice pe care le puteți obține din acest cod. Build.SERIAL. Rețineți că a fost adăugat doar la nivelul API 9 și este posibil să nu fie prezent pe toate dispozitivele. Pentru a obține un ID unic pe platformele anterioare, va trebui să citiți ceva precum adresa MAC sau IMEI.

person Stephan John    schedule 11.09.2019

Verificați SystemInfo.deviceUniqueIdentifier

Documentație: http://docs.unity3d.com/Documentation/ScriptReference/SystemInfo-deviceUniqueIdentifier.html

Un identificator unic de dispozitiv. Este garantat să fie unic pentru fiecare dispozitiv (numai citire).

iOS: pe dispozitivele pre-iOS7 va returna hash-ul adresei MAC. Pe dispozitivele iOS7 va fi UIDevice identifierForVendor sau, dacă nu reușește din orice motiv, ASIdentifierManager advertisingIdentifier.

person Ciul    schedule 06.01.2014

Obțineți ID-ul dispozitivului o singură dată, apoi stocați-l într-o bază de date sau într-un fișier. În acest caz, dacă este prima pornire a aplicației, generează un ID și îl stochează. Data viitoare, va lua doar ID-ul stocat în fișier.

person TootsieRockNRoll    schedule 21.10.2013
comment
Ideea este să aveți un ID care să supraviețuiască dezinstalării și reinstalării aplicației. Salvarea unui ID într-o bază de date nu ajută, deoarece baza de date este eliminată atunci când aplicația este dezinstalată. - person Ted Hopp; 21.10.2013

Pentru a obține un ID de utilizator, puteți utiliza Biblioteca de licențiere Google Play.

Pentru a descărca această bibliotecă, deschideți SDK Manager => SDK Tools. Calea către fișierele de bibliotecă descărcate este:

path_to_android_sdk_on_your_pc/extras/google/market_licensing/library

Includeți biblioteca în proiectul dvs. (puteți să copiați pur și simplu fișierele acesteia).

În continuare, aveți nevoie de implementarea interfeței Policy (puteți utiliza pur și simplu unul dintre cele două fișiere din bibliotecă: ServerManagedPolicy sau StrictPolicy).

Id-ul de utilizator vă va fi furnizat în cadrul funcției processServerResponse():

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

Apoi, trebuie să construiți LicenseChecker cu o politică și să apelați funcția checkAccess(). Utilizați MainActivity.java ca exemplu despre cum să faceți acest lucru. MainActivity.java se află în interiorul acestui folder:

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

Nu uitați să adăugați permisiunea CHECK_LICENSE la AndroidManifest.xml.

Mai multe despre Biblioteca de licențiere: https://developer.android.com/google/play/licensing

person Vitaly Zinchenko    schedule 03.08.2019

Android restricționează ID-ul legat de hardware după Android O, prin urmare, Android_Id este soluția pentru id-ul unic, dar are o problemă când reflectă dispozitivul, va genera un nou android_id pentru a depăși această problemă, putem folosi DRUMID-ul.

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

Veți obține adresa wifi mac utilizând următorul cod, indiferent dacă ați folosit o adresă randomizată când ați încercat să vă conectați la wifi sau nu și indiferent dacă wifi-ul a fost pornit sau oprit.

Am folosit o metodă din linkul de mai jos și am adăugat o mică modificare pentru a obține adresa exactă în loc de cea randomizată:

Obținerea adresei MAC în Android 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