uniqueidentifier ändern - Gibt es eine eindeutige Android-Geräte-ID?



device herausfinden (25)

Verfügen Android-Geräte über eine eindeutige ID, und wenn ja, wie kann man sie auf einfache Weise mit Java erreichen?


Answers

Ich denke, das ist eine sichere Art und Weise, wie man ein Skelett für eine eindeutige ID erstellt ... check it out.

Pseudo-eindeutige ID, die auf allen Android-Geräten funktioniert Einige Geräte verfügen nicht über ein Telefon (z. B. Tablets) oder Sie möchten die Berechtigung READ_PHONE_STATE aus irgendeinem Grund nicht hinzufügen. Sie können weiterhin Details wie ROM-Version, Herstellername, CPU-Typ und andere Hardware-Details lesen, die sich gut eignen, wenn Sie die ID für eine Serienschlüsselprüfung oder für andere allgemeine Zwecke verwenden möchten. Die auf diese Weise berechnete ID ist nicht eindeutig: Es ist möglich, zwei Geräte mit derselben ID zu finden (basierend auf derselben Hardware und demselben ROM-Image), aber die Änderungen in realen Anwendungen sind vernachlässigbar. Zu diesem Zweck können Sie die Build-Klasse verwenden:

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

Die meisten Build-Mitglieder sind Strings. Wir machen hier ihre Länge und wandeln sie per Modulo in eine Ziffer um. Wir haben 13 solcher Ziffern und fügen zwei weitere (35) hinzu, um dieselbe ID-Größe wie der IMEI (15 Ziffern) zu haben. Es gibt auch andere Möglichkeiten hier, schaut euch einfach diese Saiten an. Gibt so etwas zurück 355715565309247. Es ist keine besondere Erlaubnis erforderlich, was diesen Ansatz sehr bequem macht.

(Zusätzliche Informationen: Die oben angegebene Technik wurde aus einem Artikel über here kopiert .)


Ausführliche Anweisungen zum Beziehen einer eindeutigen Kennung für jedes Android-Gerät, von dem aus Ihre Anwendung installiert ist, finden Sie im offiziellen Blog für Entwickler von Android, das android-developers.blogspot.com/2011/03/… .

Es scheint, dass der beste Weg für Sie ist, einen bei der Installation selbst zu generieren und anschließend zu lesen, wenn die Anwendung neu gestartet wird.

Ich persönlich finde das akzeptabel, aber nicht ideal. Keine von Android bereitgestellte Kennung funktioniert in allen Fällen, da die meisten von den Funkzuständen des Telefons abhängen (Wi-Fi ein / aus, Mobilfunk ein / aus, Bluetooth ein / aus). Die anderen, wie, Settings.Secure.ANDROID_IDmüssen vom Hersteller implementiert werden und sind nicht unbedingt eindeutig.

Im Folgenden finden Sie ein Beispiel für das Schreiben von Daten in eine Installationsdatei , die zusammen mit anderen Daten gespeichert werden, die von der Anwendung lokal gespeichert werden.

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

Es gibt mehr als 30 Antworten und einige sind gleich und einige sind einzigartig. Diese Antwort basiert auf wenigen dieser Antworten. Einer von ihnen ist die Antwort von @Lenn Dolling.

Es kombiniert 3 IDs und erstellt eine 32-stellige Hex-Zeichenfolge. Es hat sehr gut für mich funktioniert.

3 - IDs sind:
Pseudo-ID - sie erzeugt wird , basierend auf physikalischen Gerätespezifikationen
ANDROID_ID - Settings.Secure.ANDROID_ID
Bluetooth - Adresse - Bluetooth - Adapter - Adresse

Es wird etwas wie folgt zurückgegeben : 551F27C060712A72730B0A0F734064B1

Hinweis: Sie können der longIdZeichenfolge immer weitere IDs hinzufügen . Zum Beispiel, Seriennummer. WLAN-Adapteradresse. IMEI. Auf diese Weise machen Sie es für jedes Gerät einzigartig.

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

Die eindeutige Geräte-ID eines Android-Betriebssystems als Zeichenfolge unter Verwendung von TelephonyManagerund ANDROID_IDwird wie folgt ermittelt:

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

Ich empfehle jedoch dringend eine von Google vorgeschlagene Methode, siehe App-Installationen identifizieren .


Mit dem folgenden Code können Sie die eindeutige Geräte-ID eines Android-Betriebssystems als Zeichenfolge abrufen.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 


Ein Serial Feld wurde die zusätzliche BuildKlasse in API - Ebene 9 (Android 2.3 - Lebkuchen). Die Dokumentation besagt, dass es sich um die Seriennummer der Hardware handelt. Daher sollte es eindeutig sein, wenn es auf dem Gerät vorhanden ist.

Ich weiß nicht, ob es tatsächlich von allen Geräten mit API-Level> = 9 unterstützt wird (= nicht null).


So generiere ich die eindeutige ID:

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

Die Android-Geräte-MAC-ID hat auch eine eindeutige ID. Diese Einstellung wird nicht geändert, wenn Sie das Gerät selbst formatieren

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

Vergessen Sie auch nicht, die entsprechenden Berechtigungen in Ihre AndroidManifest.xml aufzunehmen

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

Es gibt ziemlich nützliche Informationen here .

Es werden fünf verschiedene ID-Typen behandelt:

  1. IMEI (nur für Android-Geräte mit Phone-Nutzung; benötigt android.permission.READ_PHONE_STATE )
  2. Pseudo-eindeutige ID (für alle Android-Geräte)
  3. Android-ID (kann Null sein, kann sich beim Zurücksetzen auf die Werkseinstellungen ändern, kann am gerooteten Telefon geändert werden)
  4. WLAN-MAC- android.permission.ACCESS_WIFI_STATE (benötigt android.permission.ACCESS_WIFI_STATE )
  5. BT MAC- android.permission.BLUETOOTH (Geräte mit Bluetooth, android.permission.BLUETOOTH )

UPDATE : In den letzten Versionen von Android wurden viele Probleme mit ANDROID_ID behoben, und ich glaube, dass dieser Ansatz nicht länger erforderlich ist. Bitte werfen Sie einen Blick auf die Antwort von Anthony .

Vollständige Offenlegung: Meine App hat ursprünglich den folgenden Ansatz verwendet, verwendet diesen Ansatz jedoch nicht mehr. Wir verwenden jetzt den im android-developers.blogspot.com/2011/03/… Eintrag beschriebenen Ansatz, auf den sich die Antwort von emmby bezieht (nämlich das Generieren und Speichern einer UUID#randomUUID() ).

Es gibt viele Antworten auf diese Frage, von denen die meisten nur "einige" der Zeit funktionieren werden, und das ist leider nicht gut genug.

Basierend auf meinen Gerätetests (alle Telefone, von denen mindestens eines nicht aktiviert ist):

  1. Alle getesteten Geräte haben einen Wert für TelephonyManager.getDeviceId()
  2. Alle GSM-Geräte (alle mit einer SIM-Karte getestet) haben einen Wert für TelephonyManager.getSimSerialNumber()
  3. Alle CDMA-Geräte gaben für getSimSerialNumber() (wie erwartet) Null zurück.
  4. Alle Geräte mit einem hinzugefügten Google-Konto haben einen Wert für ANDROID_ID
  5. Alle CDMA-Geräte haben für ANDROID_ID und TelephonyManager.getDeviceId() denselben Wert (oder dieselbe Ableitung desselben Werts TelephonyManager.getDeviceId() - solange ein Google-Konto während des Setups hinzugefügt wurde.
  6. Ich hatte noch keine Gelegenheit, GSM-Geräte ohne SIM-Karte, ein GSM-Gerät ohne Google-Konto oder eines der Geräte im Flugzeugmodus zu testen.

Wenn Sie also etwas TM.getDeviceId() für das Gerät selbst TM.getDeviceId() , sollte TM.getDeviceId() ausreichend sein. Offensichtlich sind einige Benutzer paranoider als andere. Daher kann es hilfreich sein, 1 oder mehrere dieser Bezeichner zu hashieren, sodass die Zeichenfolge immer noch praktisch eindeutig für das Gerät ist, das tatsächliche Gerät des Benutzers jedoch nicht explizit identifiziert. Verwenden Sie beispielsweise String.hashCode() in Kombination mit einer 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();

könnte zu etwas führen wie: 00000000-54b3-e7c7-0000-000046bffd97

Es funktioniert gut genug für mich.

Vergessen Sie nicht, wie Richard unten erwähnt, dass Sie die Berechtigung zum Lesen der TelephonyManager Eigenschaften benötigen. Fügen Sie dies Ihrem Manifest hinzu:

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

libs importieren

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


Fügen Sie folgenden Code in der Klassendatei hinzu:

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

Hinzufügen in AndroidManifest.xml:

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

Eines möchte ich hinzufügen - ich habe eine dieser einzigartigen Situationen.

Mit:

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

Es stellt sich heraus, dass, obwohl mein Viewsonic G-Tablet eine nicht-NULL-DeviceID meldet, jedes G-Tablet die gleiche Nummer angibt.

Es macht es interessant, "Pocket Empires" zu spielen, wodurch Sie auf der "eindeutigen" DeviceID sofort Zugriff auf das Konto einer anderen Person haben.

Mein Gerät verfügt nicht über ein Mobilfunkgerät.


Meine zwei Cents - Anmerkung: Dies ist für eine eindeutige Geräte-ID (err) - nicht für die Installation, wie im Blog der Android-Entwickler beschrieben .

Beachten Sie, dass die von @emmby bereitgestellte solution auf eine Anwendungs-ID zurückgreift, da die SharedPreferences nicht prozessübergreifend synchronisiert werden ( here und here ). Also habe ich das ganz vermieden.

Stattdessen habe ich die verschiedenen Strategien zum Abrufen einer (Geräte-) ID in einer Enumeration gekapselt. Die Änderung der Reihenfolge der Enumenkonstanten beeinflusst die Priorität der verschiedenen Arten, die ID zu erhalten. Die erste Nicht-Null-ID wird zurückgegeben oder eine Ausnahme wird ausgelöst (gemäß den guten Java-Praktiken, wenn Null keine Bedeutung hat). So habe ich zum Beispiel zuerst die TELEPHONY - aber eine gute Standardwahl wäre die ANDROID_ID- Beta:

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


Bei Google I / O veröffentlichte Reto Meier eine robuste Antwort auf die Vorgehensweise, die die meisten Entwickleranforderungen erfüllen sollte, um Benutzer systemübergreifend zu verfolgen. Anthony Nolan gibt in seiner Antwort die Richtung vor, aber ich dachte, ich würde die gesamte Herangehensweise aufschreiben, damit andere leicht sehen können, wie es geht (es dauerte eine Weile, bis ich die Details herausfand).

Durch diesen Ansatz erhalten Sie eine anonyme, sichere Benutzer-ID, die für den Benutzer auf verschiedenen Geräten (basierend auf dem primären Google-Konto) und bei allen Installationen dauerhaft ist. Der grundlegende Ansatz besteht darin, eine zufällige Benutzer-ID zu generieren und diese in den gemeinsamen Einstellungen der Apps zu speichern. Sie verwenden dann den Sicherungsagenten von Google, um die mit dem Google-Konto verknüpften freigegebenen Einstellungen in der Cloud zu speichern.

Gehen wir den vollständigen Ansatz durch. Zunächst müssen wir eine Sicherungskopie für unsere SharedPreferences erstellen, indem wir den Android-Sicherungsdienst verwenden. Beginnen Sie mit der Registrierung Ihrer App über http://developer.android.com/google/backup/signup.html .

Google gibt Ihnen einen Sicherungsdienstschlüssel, den Sie zum Manifest hinzufügen müssen. Sie müssen der Anwendung außerdem mitteilen, dass sie BackupAgent wie folgt verwenden soll:

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

Dann müssen Sie den Sicherungsagenten erstellen und ihm mitteilen, dass er den Hilfsagenten für gemeinsam genutzte Präferenzen verwenden soll:

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

Um die Sicherung abzuschließen, müssen Sie eine Instanz von BackupManager in Ihrer Hauptaktivität erstellen:

BackupManager backupManager = new BackupManager(context);

Erstellen Sie schließlich eine Benutzer-ID, falls diese noch nicht vorhanden ist, und speichern Sie sie in den 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;
}

Diese Benutzer-ID ist jetzt auch in allen Installationen erhalten, auch wenn der Benutzer das Gerät bewegt.

Weitere Informationen zu diesem Ansatz finden Sie im talk .

Ausführliche Informationen zur Implementierung des Sicherungsagenten finden Sie unter Datensicherung . Ich empfehle insbesondere den Abschnitt unten zum Testen, da die Sicherung nicht sofort erfolgt und Sie zum Testen die Sicherung erzwingen müssen.


Google-Instanz-ID

Freigegeben am I / O 2015; Für Android sind Spieldienste erforderlich. 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

Es scheint, dass Google beabsichtigt, diese ID zur Identifizierung von Installationen unter Android, Chrome und iOS zu verwenden.

Es identifiziert eine Installation und nicht ein Gerät, aber ANDROID_ID (die akzeptierte Antwort) identifiziert nun auch keine Geräte mehr. Mit der ARC-Laufzeit wird für jede Installation eine neue ANDROID_ID generiert ( Details hier ), genau wie diese neue Instanz-ID. Ich denke auch, dass die Identifizierung von Installationen (nicht Geräten) das ist, wonach die meisten von uns tatsächlich suchen.

Die Vorteile der Instanz-ID

Mir scheint, Google beabsichtigt, dass es für diesen Zweck verwendet wird (Identifizierung Ihrer Installationen), es ist plattformübergreifend und kann für eine Reihe anderer Zwecke verwendet werden (siehe die obigen Links).

Wenn Sie GCM verwenden, müssen Sie schließlich diese Instanz-ID verwenden, da Sie diese benötigen, um das GCM-Token zu erhalten (das die alte GCM-Registrierungs-ID ersetzt).

Die Nachteile / Probleme

In der aktuellen Implementierung (GPS 7.5) wird die Instanz-ID von einem Server abgerufen, wenn Ihre App sie anfordert. Dies bedeutet, dass der obige Anruf ein blockierender Anruf ist. In meinen unwissenschaftlichen Tests dauert es 1 bis 3 Sekunden, wenn das Gerät online ist, und 0,5 bis 1,0 Sekunden, wenn es offline ist (vermutlich dauert es, bis es aufgibt und ein Gerät generiert) zufällige ID). Dies wurde in Nordamerika auf Nexus 5 mit Android 5.1.1 und GPS 7.5 getestet.

Wenn Sie die ID für die vorgesehenen Zwecke verwenden, z. App-Authentifizierung, App-Identifizierung, GCM - Ich denke, diese 1-3 Sekunden könnten ein Ärgernis sein (abhängig von Ihrer App natürlich).


Wie wäre es mit der IMEI . Das ist einzigartig für Android oder andere mobile Geräte.


Zuletzt aktualisiert: 02.06.15

Nachdem ich jeden -Beitrag zum Erstellen einer eindeutigen ID, des Google-Entwicklerblogs und der Android-Dokumentation gelesen habe, habe ich das Gefühl, dass die "Pseudo-ID" die beste Option ist.

Hauptproblem: Hardware vs. Software

Hardware

  • Benutzer können ihre Hardware, ihr Android-Tablet oder ihr Telefon ändern. Daher sind eindeutige, auf Hardware basierende IDs keine gute Idee für TRACKING-BENUTZER
  • Für TRACKING HARDWARE ist dies eine großartige Idee

Software

  • Benutzer können ihr ROM löschen oder ändern, wenn sie verwurzelt sind
  • Sie können Benutzer plattformübergreifend verfolgen (iOS, Android, Windows und Web).
  • Am besten möchten Sie mit Ihrer Zustimmung EINEN EINZELNUTZER VERFOLGEN , indem Sie sich einfach anmelden (machen Sie dies nahtlos mit OAuth).

Gesamtausfall bei Android

- Eindeutigkeit garantieren (einschließlich gerootete Geräte) für API> = 9/10 (99,5% der Android-Geräte)

- Keine zusätzlichen Berechtigungen

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

Vielen Dank an @stansult für das Posten aller Optionen (in dieser -Frage).

Liste der Optionen - Gründe warum / warum nicht verwendet werden:

  • Benutzer-E-Mail - Software

    • Der Benutzer könnte die E-Mail-Adresse ändern - sehr unwahrscheinlich
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> oder
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> ( So erhalten Sie die primäre E-Mail-Adresse des Android-Geräts )
  • Telefonnummer des Benutzers - Software

    • Benutzer können Telefonnummern ändern - sehr unwahrscheinlich
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (nur Telefone, die android.permission.READ_PHONE_STATE )

    • Die meisten Benutzer hassen die Tatsache, dass in der Berechtigung "Telefonanrufe" angezeigt wird. Einige Benutzer geben schlechte Bewertungen ab, weil sie der Meinung sind, dass Sie einfach ihre persönlichen Informationen stehlen, wenn Sie wirklich nur Geräteinstallationen verfolgen möchten. Es ist offensichtlich, dass Sie Daten sammeln.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android-ID - Hardware (kann Null sein, kann sich beim Zurücksetzen auf die Werkseinstellungen ändern, kann auf einem gerooteten Gerät geändert werden)

    • Da es 'null' sein kann, können wir nach 'null' suchen und dessen Wert ändern. Dies bedeutet jedoch, dass es nicht mehr eindeutig ist.
    • Wenn Sie einen Benutzer mit einem Gerät zum Zurücksetzen auf die Werkseinstellungen haben, hat sich der Wert möglicherweise auf dem gerooteten Gerät geändert oder geändert, sodass bei der Nachverfolgung von Benutzerinstallationen Duplikateinträge vorhanden sind.
  • WLAN-MAC-Adresse - Hardware (benötigt android.permission.ACCESS_WIFI_STATE )

    • Dies könnte die zweitbeste Option sein, aber Sie erfassen und speichern immer noch eine eindeutige Kennung, die direkt von einem Benutzer stammt. Dies ist offensichtlich, dass Sie Daten sammeln.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Bluetooth MAC-Adresse - Hardware (Geräte mit Bluetooth, benötigt android.permission.BLUETOOTH )

    • Die meisten auf dem Markt befindlichen Anwendungen verwenden kein Bluetooth. Wenn Ihre Anwendung also kein Bluetooth verwendet und Sie dies berücksichtigen, kann der Benutzer verdächtig werden.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - Software (für alle Android-Geräte)

    • Sehr gut möglich, kann Kollisionen enthalten - Siehe meine Methode!
    • Auf diese Weise können Sie eine "fast eindeutige" ID vom Benutzer erhalten, ohne etwas zu nehmen, das nicht privat ist. Sie können Ihre eigene anonyme ID aus den Geräteinformationen erstellen.

Ich weiß, dass es keine "perfekte" Möglichkeit gibt, eine eindeutige ID ohne Berechtigungen zu erhalten. Manchmal müssen wir jedoch nur die Geräteinstallation wirklich nachverfolgen. Wenn Sie eine eindeutige ID erstellen möchten, können Sie eine "pseudo-eindeutige ID" erstellen, die ausschließlich auf Informationen basiert, die uns die Android-API ohne zusätzliche Berechtigungen zur Verfügung stellt. Auf diese Weise können wir den Respekt der Benutzer zeigen und versuchen, auch eine gute Benutzererfahrung anzubieten.

Mit einer pseudo-eindeutigen ID stößt man eigentlich nur darauf, dass es möglicherweise Duplikate gibt, wenn ähnliche Geräte vorhanden sind. Sie können die kombinierte Methode anpassen, um sie einzigartig zu machen. Einige Entwickler müssen jedoch die Geräteinstallation nachverfolgen. Dies wird den Trick oder die Leistung auf der Grundlage ähnlicher Geräte bewirken.

API> = 9:

Wenn das Android-Gerät API 9 oder höher ist, ist dies aufgrund des Felds "Build.SERIAL" garantiert eindeutig.

Denken Sie daran, dass Sie technisch gesehen nur etwa 0,5% der Benutzer mit API <9 verpassen. Sie können sich also auf den Rest konzentrieren: Das sind 99,5% der Benutzer!

API <9:

Wenn das Android-Gerät des Benutzers niedriger als API 9 ist; hoffentlich haben sie kein Werksreset durchgeführt und ihre 'Secure.ANDROID_ID' bleibt erhalten oder nicht 'null'. (siehe http://developer.android.com/about/dashboards/index.html )

Wenn alle Stricke reißen:

Wenn alles andere fehlschlägt, wenn der Benutzer weniger als API 9 (niedriger als Gingerbread) hat, sein Gerät zurückgesetzt hat oder "Secure.ANDROID_ID" den Wert "null" zurückgibt, dann wird die zurückgegebene ID nur auf den Android-Geräteinformationen basieren. Hier können Kollisionen auftreten.

Änderungen:

  • Entfernen von 'Android.SECURE_ID' aufgrund von Werksresets kann dazu führen, dass sich der Wert ändert
  • Der Code wurde für die API-Änderung geändert
  • Das Pseudo wurde geändert

Bitte schauen Sie sich die Methode unten an:

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

Neu (für Apps mit Anzeigen UND Google Play-Services):

Über die Konsole des Google Play-Entwicklers:

Seit dem 1. August 2014 müssen gemäß den Richtlinien für das Google Play-Entwicklerprogramm alle neuen App-Uploads und -Updates die Werbe-ID anstelle von anderen permanenten Kennungen für Werbezwecke verwenden. Mehr erfahren

Umsetzung :

Genehmigung:

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

Quelle / Dokumente:

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

Wichtig:

Es ist beabsichtigt, dass die Werbe-ID die vorhandene Verwendung anderer Bezeichner für Werbezwecke vollständig ersetzt (z. B. Verwendung von ANDROID_ID in Settings.Secure), wenn Google Play-Dienste verfügbar sind. Fälle, in denen Google Play-Dienste nicht verfügbar sind, werden durch eine GooglePlayServicesNotAvailableException angezeigt, die von getAdvertisingIdInfo () ausgelöst wird.

Warnung, Benutzer können zurücksetzen:

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

Ich habe versucht, auf jeden Link zu verweisen, von dem ich Informationen erhielt. Wenn Sie fehlen und aufgenommen werden müssen, kommentieren Sie bitte!

Instanz-ID der Google Player-Dienste

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


Für die Hardwareerkennung eines bestimmten Android-Geräts können Sie die MAC-Adressen überprüfen.

Sie können es so machen:

in AndroidManifest.xml

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

jetzt in deinem code:

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

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

In jedem Android-Gerät gibt es mindestens eine "wlan0" -Schnittstelle, die der WI-FI-Chip ist. Dieser Code funktioniert auch, wenn WI-FI nicht aktiviert ist.

PS Es gibt eine Reihe anderer Schnittstellen, die Sie aus der Liste mit MACS erhalten. Dies kann sich jedoch zwischen den Telefonen ändern.


Wie Dave Webb erwähnt, gibt es im Android Developer Blog einen Artikel , der dies behandelt. Ihre bevorzugte Lösung ist das Verfolgen von App-Installationen anstelle von Geräten. Dies funktioniert in den meisten Anwendungsfällen gut. Der Blogbeitrag zeigt Ihnen den erforderlichen Code, damit dies funktioniert, und ich empfehle Ihnen, es auszuprobieren.

Im Blogbeitrag werden jedoch Lösungen beschrieben, wenn Sie eine Geräte-ID anstelle einer App-Installations-ID benötigen. Ich habe mit jemandem bei Google gesprochen, um einige zusätzliche Informationen zu erhalten, falls Sie dies benötigen. Folgendes habe ich über Gerätekennungen herausgefunden, das im oben genannten Blog-Post NICHT erwähnt wird:

  • ANDROID_ID ist die bevorzugte Gerätekennung. ANDROID_ID ist auf Android-Versionen <= 2.1 oder> = 2.3 absolut zuverlässig. Nur 2.2 hat die in der Post erwähnten Probleme.
  • Mehrere Geräte mehrerer Hersteller sind von dem ANDROID_ID-Fehler in 2.2 betroffen.
  • Soweit ich feststellen konnte, haben alle betroffenen Geräte die gleiche ANDROID_ID , die 9774d56d682e549c . Dies ist auch die gleiche Geräte-ID, die vom Emulator gemeldet wird, übrigens.
  • Google glaubt, dass OEMs das Problem für viele oder die meisten ihrer Geräte behoben haben. Ich konnte jedoch feststellen, dass es zumindest Anfang April 2011 immer noch recht einfach ist, Geräte zu finden, die die defekte ANDROID_ID haben.

Basierend auf den Empfehlungen von Google habe ich eine Klasse implementiert, die eine eindeutige UUID für jedes Gerät generiert, gegebenenfalls mit ANDROID_ID als Ausgangswert, bei Bedarf auf TelephonyManager.getDeviceId () zurückgreift, und falls dies fehlschlägt, auf eine zufällig generierte eindeutige UUID zurückgreift das bleibt bei App-Neustarts erhalten (aber keine App-Neuinstallationen).

Beachten Sie, dass bei Geräten, die auf die Geräte-ID zurückgreifen müssen, die eindeutige ID auch bei Werksrücksetzungen erhalten bleibt. Dies ist etwas, worauf Sie achten sollten. Wenn Sie sicherstellen müssen, dass ein Werksreset Ihre eindeutige ID zurücksetzt, sollten Sie möglicherweise auf die zufällige UUID anstelle der Geräte-ID zurückgreifen.

Dieser Code bezieht sich wiederum auf eine Geräte-ID und nicht auf eine App-Installations-ID. In den meisten Situationen suchen Sie wahrscheinlich nach einer App-Installations-ID. Wenn Sie jedoch eine Geräte-ID benötigen, funktioniert der folgende Code wahrscheinlich für Sie.

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

Genauer gesagt Settings.Secure.ANDROID_ID. Dies ist eine 64-Bit-Menge, die beim ersten Start des Geräts generiert und gespeichert wird. Es wird zurückgesetzt, wenn das Gerät gelöscht wird.

ANDROID_IDscheint eine gute Wahl für eine eindeutige Gerätekennung zu sein. Es gibt Nachteile: Erstens ist es bei Android-Versionen vor 2.2 nicht zu 100% zuverlässig. (“Froyo”).Außerdem ist in einem beliebten Handset eines großen Herstellers, bei dem jede Instanz die gleiche ANDROID_ID hat, mindestens ein weit verbreiteter Fehler aufgetreten.


Es gibt viele verschiedene Ansätze, um diese ANDROID_IDProbleme zu umgehen ( nullmanchmal geben Geräte eines bestimmten Modells immer die gleiche ID zurück) mit Vor- und Nachteilen:

  • Implementierung eines benutzerdefinierten ID-Generierungsalgorithmus (basierend auf Geräteeigenschaften, die statisch sein sollen und sich nicht ändern -> wer weiß)
  • Missbrauch anderer IDs wie IMEI , Seriennummer, Wi-Fi / Bluetooth-MAC-Adresse (diese sind nicht auf allen Geräten vorhanden oder es werden zusätzliche Berechtigungen benötigt)

Ich selbst bevorzuge die Verwendung einer vorhandenen OpenUDID-Implementierung (siehe https://github.com/ylechelle/OpenUDID ) für Android (siehe https://github.com/vieux/OpenUDID ). Es ist einfach zu integrieren und verwendet die ANDROID_IDoben genannten Probleme mit den Fallbacks.


Context in Android is an interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.





android uniqueidentifier