Vraag Bestaat er een unieke ID van een Android-apparaat?


Hebben Android-apparaten een unieke ID en zo ja, wat is een eenvoudige manier om toegang te krijgen tot Java?


2309
2018-05-07 00:47


oorsprong


antwoorden:


Settings.Secure#ANDROID_ID geeft de Android ID als een uniek voor elke gebruiker 64-bits hex-string.

import android.provider.Settings.Secure;

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

1697
2018-05-07 00:49



BIJWERKEN: Vanaf recente versies van Android, veel van de problemen met ANDROID_ID zijn opgelost en ik ben van mening dat deze aanpak niet langer nodig is. Kijk eens naar Anthony's antwoord.

Volledige openbaarmaking: mijn app heeft oorspronkelijk de onderstaande benadering gebruikt, maar deze benadering wordt niet langer gebruikt en we gebruiken nu de benadering die wordt beschreven in de Android-blog voor ontwikkelaars doe dat emmby's antwoord links naar (namelijk, genereren en opslaan van een UUID#randomUUID()).


Er zijn veel antwoorden op deze vraag, waarvan de meeste alleen "sommigen" van die tijd zullen werken, en helaas is dat niet goed genoeg.

Op basis van mijn tests van apparaten (alle telefoons waarvan er tenminste één niet is geactiveerd):

  1. Alle geteste apparaten hebben een waarde geretourneerd voor TelephonyManager.getDeviceId()
  2. Alle GSM-apparaten (allemaal getest met een simkaart) hebben een waarde geretourneerd voor TelephonyManager.getSimSerialNumber()
  3. Alle CDMA-apparaten zijn null geretourneerd getSimSerialNumber() (zoals verwacht)
  4. Alle apparaten waarvoor een Google-account is toegevoegd, hebben een waarde geretourneerd voor ANDROID_ID
  5. Alle CDMA-apparaten hebben voor beide dezelfde waarde (of afleiding van dezelfde waarde) geretourneerd ANDROID_ID en TelephonyManager.getDeviceId() - zo lang als een Google-account is toegevoegd tijdens de installatie.
  6. Ik had nog geen kans om GSM-apparaten zonder SIM-kaart, een GSM-apparaat zonder toegevoegde Google-account of een van de apparaten in de vliegtuigmodus te testen.

Dus als u iets unieks wilt met het apparaat zelf, TM.getDeviceId()  moeten voldoende zijn. Natuurlijk zijn sommige gebruikers paranoïde dan andere, dus het kan handig zijn hash 1 of meer van deze identifiers te gebruiken, zodat de string nog steeds vrijwel uniek is voor het apparaat, maar niet expliciet het daadwerkelijke apparaat van de gebruiker identificeert. Gebruik bijvoorbeeld String.hashCode(), gecombineerd met een 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();

kan resulteren in iets als: 00000000-54b3-e7c7-0000-000046bffd97

Het werkt goed genoeg voor mij.

Zoals Richard hieronder vermeldt, vergeet niet dat je toestemming nodig hebt om het te lezen TelephonyManager eigenschappen, voeg dit toe aan uw manifest:

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

libs importeren

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

1056
2018-05-17 22:12



Laatste update: 2 februari 2015


Na het lezen van elke Stack Overflow-post over het maken van een unieke ID, de Google-ontwikkelaarsblog en Android-documentatie, heb ik het gevoel dat de 'Pseudo-ID' de best mogelijke optie is.

Hoofditems: Hardware versus software

Hardware

  • Gebruikers kunnen hun hardware, Android-tablet of telefoon wijzigen, dus unieke ID's op basis van hardware zijn geen goede ideeën voor GEBRUIKERS TRACEREN
  • Voor HARDWARE VOLGEN, dit is een geweldig idee

Software

  • Gebruikers kunnen hun ROM wissen / wijzigen als ze zijn geroot
  • U kunt gebruikers volgen over verschillende platforms (iOS, Android, Windows en Web)
  • De beste wil VOLG EEN INDIVIDUELE GEBRUIKER met hun toestemming is om ze eenvoudig in te loggen (maak dit naadloos met OAuth)

Algehele analyse met Android

- Uniciteit garanderen (inclusief geroote apparaten) voor API> = 9/10 (99,5% van Android-apparaten)

- Geen extra rechten

Psuedo-code:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return unique ID of build information (may overlap data - API < 9)

Bedankt aan @stansult voor het posten al onze opties (in deze vraag over Stack Overflow).

Lijst met opties - redenen waarom / waarom niet gebruiken:

  • Gebruikers e-mail - Software

    • Gebruiker kan e-mail wijzigen - ZEER onwaarschijnlijk
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> of
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" />  <uses-permission android:name="android.permission.READ_CONTACTS" /> (Het primaire e-mailadres van het Android-apparaat ophalen)
  • Gebruikerstelefoonnummer - Software

    • Gebruikers kunnen telefoonnummers wijzigen - ZEER onwaarschijnlijk
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (alleen telefoons, behoeften android.permission.READ_PHONE_STATE)

    • De meeste gebruikers haten het feit dat in de toestemming 'telefoontjes' staat. Sommige gebruikers geven slechte beoordelingen, omdat ze denken dat je gewoon hun persoonlijke gegevens steelt, terwijl het enige dat je echt wilt doen, is om apparaatinstallaties te volgen. Het is duidelijk dat u gegevens verzamelt.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID - Hardware (kan nul zijn, kan veranderen na fabrieksreset, kan worden gewijzigd op een geroot apparaat)

    • Omdat het 'null' kan zijn, kunnen we 'null' controleren en de waarde ervan wijzigen, maar dit betekent dat het niet langer uniek zal zijn.
    • Als u een gebruiker hebt met een apparaat voor het herstellen van de fabrieksinstellingen, is de waarde mogelijk gewijzigd of gewijzigd op het geroote apparaat, dus er kunnen dubbele vermeldingen zijn als u gebruikersinstallaties bijhoudt.
  • WLAN MAC-adres - Hardware (behoeften android.permission.ACCESS_WIFI_STATE)

    • Dit kan de op een na beste optie zijn, maar u verzamelt en slaat nog steeds een unieke ID op die rechtstreeks van een gebruiker komt. Dit is duidelijk dat u gegevens verzamelt.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Bluetooth MAC-adres - hardware (apparaten met Bluetooth, behoeften android.permission.BLUETOOTH)

    • De meeste toepassingen op de markt maken geen gebruik van Bluetooth. Als uw toepassing dus geen Bluetooth gebruikt en u neemt dit op, dan kan de gebruiker achterdochtig worden.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-unieke ID - Software (voor alle Android-apparaten)

    • Heel goed mogelijk, kan botsingen bevatten - Zie mijn methode hieronder gepost!
    • Hiermee kunt u een 'bijna unieke' ID van de gebruiker hebben zonder iets te nemen dat privé is. U kunt uw eigen anonieme ID maken op basis van apparaatinformatie.

Ik weet dat er geen 'perfecte' manier is om een ​​unieke ID te krijgen zonder toestemming te gebruiken; Soms hoeven we echter alleen de installatie van het apparaat te volgen. Als het gaat om het maken van een unieke ID, kunnen we een 'pseudo-unieke id' maken die uitsluitend is gebaseerd op informatie die de Android API ons biedt zonder extra machtigingen te gebruiken. Op deze manier kunnen we de gebruiker respect tonen en proberen ook een goede gebruikerservaring te bieden.

Met een pseudo-unieke id kom je er echt alleen maar achter dat er duplicaten kunnen zijn gebaseerd op het feit dat er vergelijkbare apparaten zijn. U kunt de gecombineerde methode aanpassen om het unieker te maken; Sommige ontwikkelaars moeten echter apparaatinstallaties volgen en dit zal de truc of prestaties op basis van vergelijkbare apparaten doen.

API> = 9:

Als hun Android-apparaat API 9 of hoger heeft, is dit gegarandeerd uniek vanwege het veld 'BuildSERIAL'.

ONTHOUDEN, je mist technisch gezien slechts ongeveer 0,5% van de gebruikers wie heeft API <9. U kunt zich dus concentreren op de rest: dit is 99,5% van de gebruikers!

API <9:

Als het Android-apparaat van de gebruiker lager is dan API 9; hopelijk hebben ze geen fabrieksreset uitgevoerd en blijft hun 'Secure.ANDROID_ID' behouden of niet 'null'. (zien http://developer.android.com/about/dashboards/index.html)

Als al het andere faalt:

Als al het andere niet lukt, als de gebruiker lager is dan API 9 (lager dan Gingerbread), het apparaat heeft gereset of 'Secure.ANDROID_ID' retourneert 'null', dan zal de geretourneerde ID alleen gebaseerd zijn op de informatie van hun Android-apparaat. Dit is waar de botsingen kunnen gebeuren.

Veranderingen:

  • 'Android.SECURE_ID' is verwijderd vanwege fabrieksinstellingen waardoor de waarde kan veranderen
  • Bewerk de code om te veranderen op API
  • De pseudo veranderd

Bekijk de onderstaande methode alstublieft:

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

Nieuw (voor apps met advertenties EN Google Play-services):

Via de Google Play Developer's console:

Vanaf 1 augustus 2014, het programmabeleid voor Google Play-ontwikkelaars   vereist alle nieuwe uploads van apps en updates om de advertentie-ID te gebruiken   in plaats van andere persistente identifiers voor advertentiedoeleinden.   Kom meer te weten

Implementatie:

Toestemming:

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

Code:

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

Bron / Docs:

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

Belangrijk:

Het is de bedoeling dat de advertentie-ID de bestaande volledig vervangt   gebruik van andere ID's voor advertentiedoeleinden (zoals het gebruik van ANDROID_ID   in Settings.Secure) wanneer Google Play-services beschikbaar is. Gevallen   waar Google Play Services niet beschikbaar is, wordt aangegeven met een   GooglePlayServicesNotAvailableException wordt voorbij gegooid   getAdvertisingIdInfo ().

Waarschuwing, gebruikers kunnen opnieuw instellen:

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

Ik heb geprobeerd naar elke link te verwijzen waarvan ik informatie heb overgenomen. Als je bent gemist en moet worden opgenomen, reageer alsjeblieft!

InstanceID van Google Player Services

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


364
2017-07-12 23:58



Zoals Dave Webb vermeldt, de Android-blog voor ontwikkelaars heeft een artikel dat dekt dit. Hun voorkeursoplossing is om app-installaties bij te houden in plaats van apparaten, en dat zal in de meeste gevallen goed werken. In het blogbericht ziet u de benodigde code om dat te laten werken, en ik raad u aan dit te bekijken.

In de blogpost worden echter oplossingen besproken als u een apparaat-ID nodig hebt in plaats van een app-installatie-ID. Ik heb met iemand van Google gesproken om aanvullende informatie te krijgen over een paar items voor het geval dat u dit moet doen. Hier is wat ik ontdekte over apparaat-ID's die NIET wordt genoemd in de bovengenoemde blogpost:

  • ANDROID_ID is de apparaat-ID die de voorkeur heeft. ANDROID_ID is perfect betrouwbaar in versies van Android <= 2.1 of> = 2.3. Alleen 2.2 heeft de problemen genoemd in de post.
  • Verschillende apparaten van verschillende fabrikanten worden getroffen door de ANDROID_ID-bug in 2.2.
  • Voor zover ik heb kunnen vaststellen, hebben alle getroffen apparaten hetzelfde ANDROID_ID, dat is 9774d56d682e549c. Dat is ook hetzelfde apparaat-ID gerapporteerd door de emulator, trouwens.
  • Google is van mening dat OEM's het probleem voor veel of het grootste deel van hun apparaten hebben opgelost, maar ik heb kunnen verifiëren dat vanaf het begin van april 2011 het nog steeds vrij eenvoudig is om apparaten te vinden met de gebroken ANDROID_ID.

Op basis van de aanbevelingen van Google heb ik een klasse geïmplementeerd die een unieke UUID genereert voor elk apparaat, waarbij ANDROID_ID als het zaad wordt gebruikt waar dat van toepassing is, zo nodig terugvalt op TelephonyManager.getDeviceId () en als dat niet lukt, gebruik te maken van een willekeurig gegenereerde unieke UUID dat blijft bestaan ​​over app-herstarts (maar niet over app-herinstallaties).

Merk op dat voor apparaten die moeten terugvallen op de apparaat-ID, de unieke ID ZULLEN blijf bij fabrieksresets. Dit is iets om op te letten. Als u ervoor wilt zorgen dat een fabrieksreset uw unieke ID opnieuw instelt, kunt u overwegen om direct terug te vallen naar de willekeurige UUID in plaats van de apparaat-ID.

Nogmaals, deze code is voor een apparaat-ID, niet voor een app-installatie-ID. Voor de meeste situaties is een app-installatie-ID waarschijnlijk wat u zoekt. Maar als u een apparaat-ID nodig heeft, dan zal de volgende code waarschijnlijk voor u werken.

import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;

import java.io.UnsupportedEncodingException;
import java.util.UUID;

public class DeviceUuidFactory {

    protected static final String PREFS_FILE = "device_id.xml";
    protected static final String PREFS_DEVICE_ID = "device_id";
    protected volatile static UUID uuid;

    public DeviceUuidFactory(Context context) {
        if (uuid == null) {
            synchronized (DeviceUuidFactory.class) {
                if (uuid == null) {
                    final SharedPreferences prefs = context
                            .getSharedPreferences(PREFS_FILE, 0);
                    final String id = prefs.getString(PREFS_DEVICE_ID, null);
                    if (id != null) {
                        // Use the ids previously computed and stored in the
                        // prefs file
                        uuid = UUID.fromString(id);
                    } else {
                        final String androidId = Secure.getString(
                            context.getContentResolver(), Secure.ANDROID_ID);
                        // Use the Android ID unless it's broken, in which case
                        // fallback on deviceId,
                        // unless it's not available, then fallback on a random
                        // number which we store to a prefs file
                        try {
                            if (!"9774d56d682e549c".equals(androidId)) {
                                uuid = UUID.nameUUIDFromBytes(androidId
                                        .getBytes("utf8"));
                            } else {
                                final String deviceId = (
                                    (TelephonyManager) context
                                    .getSystemService(Context.TELEPHONY_SERVICE))
                                    .getDeviceId();
                                uuid = deviceId != null ? UUID
                                    .nameUUIDFromBytes(deviceId
                                            .getBytes("utf8")) : UUID
                                    .randomUUID();
                            }
                        } catch (UnsupportedEncodingException e) {
                            throw new RuntimeException(e);
                        }
                        // Write the value out to the prefs file
                        prefs.edit()
                                .putString(PREFS_DEVICE_ID, uuid.toString())
                                .commit();
                    }
                }
            }
        }
    }

    /**
     * Returns a unique UUID for the current android device. As with all UUIDs,
     * this unique ID is "very highly likely" to be unique across all Android
     * devices. Much more so than ANDROID_ID is.
     * 
     * The UUID is generated by using ANDROID_ID as the base key if appropriate,
     * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
     * be incorrect, and finally falling back on a random UUID that's persisted
     * to SharedPreferences if getDeviceID() does not return a usable value.
     * 
     * In some rare circumstances, this ID may change. In particular, if the
     * device is factory reset a new device ID may be generated. In addition, if
     * a user upgrades their phone from certain buggy implementations of Android
     * 2.2 to a newer, non-buggy version of Android, the device ID may change.
     * Or, if a user uninstalls your app on a device that has neither a proper
     * Android ID nor a Device ID, this ID may change on reinstallation.
     * 
     * Note that if the code falls back on using TelephonyManager.getDeviceId(),
     * the resulting ID will NOT change after a factory reset. Something to be
     * aware of.
     * 
     * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
     * directly.
     * 
     * @see http://code.google.com/p/android/issues/detail?id=10603
     * 
     * @return a UUID that may be used to uniquely identify your device for most
     *         purposes.
     */
    public UUID getDeviceUuid() {
        return uuid;
    }
}

314
2018-04-11 19:06



Hier is de code die Reto Meier in de gebruikte Google I / O presentatie dit jaar om een ​​unieke id voor de gebruiker te krijgen:

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

Als u dit koppelt met een back-upstrategie om voorkeuren naar de cloud te verzenden (ook beschreven in Reto's praten, je zou een id moeten hebben die aan een gebruiker koppelt en blijft hangen nadat het apparaat is gewist of zelfs is vervangen. Ik ben van plan dit in de toekomst te gaan gebruiken (met andere woorden, ik heb dat nog niet gedaan :).


165
2017-10-28 13:19



Ook zou u het MAC-adres van de Wi-Fi-adapter kunnen overwegen. Op deze manier verkregen:

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

Vereist toestemming android.permission.ACCESS_WIFI_STATE in het manifest.

Gerapporteerd om beschikbaar te zijn, zelfs wanneer wifi niet is verbonden. Als Joe van het bovenstaande antwoord deze op zijn vele apparaten een kans geeft, zou dat leuk zijn.

Op sommige apparaten is deze niet beschikbaar wanneer wifi is uitgeschakeld.

NOTITIE: Vanaf Android 6.x retourneert het consistent nep-mac-adres: 02:00:00:00:00:00


97
2018-06-23 14:27



Er is nogal nuttige informatie hier.

Het behandelt vijf verschillende ID-types:

  1. IMEI (alleen voor Android-apparaten met gebruik van de telefoon; android.permission.READ_PHONE_STATE)
  2. Pseudo-unieke ID (voor alle Android-apparaten)
  3. Android ID (kan nul zijn, kan veranderen na fabrieksreset, kan gewijzigd worden op geroote telefoon)
  4. WLAN MAC-adres string (behoeften android.permission.ACCESS_WIFI_STATE)
  5. BT MAC-adres string (apparaten met Bluetooth, behoeften android.permission.BLUETOOTH)

78
2018-02-08 02:16