Есть ли уникальный идентификатор устройства Android?

устройства Android имеют уникальный идентификатор, и если да, то каков простой способ получить к нему доступ с помощью Java?

30 ответов


Settings.Secure#ANDROID_ID возвращает идентификатор Android как уникальный для каждого пользователя 64-разрядной шестнадцатеричной строки.

import android.provider.Settings.Secure;

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

обновление: по состоянию на последние версии Android, многие из проблем с ANDROID_ID были решены, и я считаю, что этот подход больше не нужен. Пожалуйста, взгляните на Антония.

полное раскрытие: мое приложение использовало приведенный ниже подход первоначально, но больше не использует этот подход, и теперь мы используем подход, описанный в Блог Разработчика Android запись emmby это ссылки на (именно, создание и сохранение UUID#randomUUID()).


есть много ответов на этот вопрос, большинство из которых будет работать только "некоторое" время, и, к сожалению, этого не достаточно.

на основе моих тестов устройств (все телефоны, по крайней мере один из которых не активирован):

  1. все проверенные устройства вернули значение для TelephonyManager.getDeviceId()
  2. все приборы GSM (все испытанные с SIM) возвратили значение для TelephonyManager.getSimSerialNumber()
  3. все устройства CDMA вернули значение null для getSimSerialNumber() (как и ожидалось)
  4. все устройства с добавленной учетной записью Google вернули значение для ANDROID_ID
  5. все устройства CDMA вернули одно и то же значение (или вывод одного и того же значения) для обоих ANDROID_ID и TelephonyManager.getDeviceId() -- пока учетная запись Google была добавлена во время установки.
  6. у меня еще не было возможности протестировать GSM-устройства без SIM-карты, GSM-устройство без учетной записи Google, или любое из устройств в режиме полета.

Итак, если вы хотите что-то уникальное для самого устройства, TM.getDeviceId() должны быть достаточным. Очевидно, что некоторые пользователи более параноидальны, чем другие, поэтому может быть полезно хэшировать 1 или более из этих идентификаторов, так что строка по-прежнему практически уникальна для устройства, но явно не идентифицирует фактическое устройство пользователя. Например, используя String.hashCode(), в сочетании с 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();

может результат в чем-то вроде: 00000000-54b3-e7c7-0000-000046bffd97

она работает достаточно хорошо для меня.

как Ричард упоминает ниже, не забывайте, что вам нужно разрешение на чтение TelephonyManager свойства, поэтому добавьте это в свой манифест:

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

импорт libs

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

Последнее Обновление: 6/2/15


после прочтения каждого сообщения о переполнении стека о создании уникального идентификатора, блога разработчика Google и документации Android, я чувствую, что "псевдо-идентификатор" является лучшим вариантом.

основная проблема: аппаратное и программное обеспечение

оборудование

  • пользователи могут изменить свое оборудование, Android-планшет или телефон, поэтому уникальные идентификаторы на основе оборудования не являются хорошими идеями для отслеживание Пользователи
  • на ОТСЛЕЖИВАНИЕ ОБОРУДОВАНИЯ, это отличная идея

программа

  • пользователи могут стереть / изменить свой ПЗУ, если они укоренены
  • вы можете отслеживать пользователей на разных платформах (iOS, Android, Windows и Web)
  • лучшие хотите ОТСЛЕЖИВАНИЕ ОТДЕЛЬНОГО ПОЛЬЗОВАТЕЛЯ С согласие просто иметь их логин (сделать это бесшовное использование Протокол OAuth)

общая разбивка с Android

- гарантия уникальности (включая корневые устройства) для API >= 9/10 (99,5% устройств Android)

- никаких дополнительных разрешений

код Psuedo:

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)

спасибо @stansult за публикацию все наши варианты (в этом вопросе переполнения стека).

список опций - причины/ почему не использовать они:

  • Электронная Почта Пользователя-Программное Обеспечение

  • Номер Телефона Пользователя-Программное Обеспечение

    • потребители смогли изменить телефонные номера-сильно вряд ли
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI-оборудование (только для телефонов, должен android.permission.READ_PHONE_STATE)

    • большинство пользователей ненавидят тот факт, что он говорит "телефонные звонки" в разрешении. Некоторые пользователи дают плохие оценки, потому что они считают, что вы просто крадете их личную информацию, когда все, что вы действительно хотите сделать, это отслеживать установки устройств. Очевидно, что вы собираете данные.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • Android ID-оборудование (может быть null, может изменяться при сбросе заводских настроек, может быть изменен на корневом устройстве)

    • поскольку он может быть "null", мы можем проверить "null" и изменить его значение, но это означает, что он больше не будет уникальным.
    • если у вас есть пользователь с устройством сброса настроек, значение может быть изменено или изменено на корневом устройстве, поэтому могут быть дубликаты записи, если вы отслеживаете установки пользователя.
  • WLAN MAC-адрес-оборудование (needs android.permission.ACCESS_WIFI_STATE)

    • это может быть второй лучший вариант, но вы все еще собираете и храните уникальный идентификатор, который поступает непосредственно от пользователя. Очевидно, что вы собираете данные.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Bluetooth MAC-адрес - Оборудование (устройства с Bluetooth, потребности android.permission.BLUETOOTH)

    • большинство приложений на рынке не используют Bluetooth, и поэтому, если ваше приложение не использует Bluetooth, и вы включаете это, пользователь может стать подозрительным.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • псевдо-уникальный ID-Software (для всех устройств Android)

    • очень возможно, может содержать столкновения-см. Мой метод размещен ниже!
    • это позволяет вам иметь "почти уникальный" идентификатор от пользователя, не принимая ничего личного. Вы можете создать свой собственный анонимный идентификатор из информации об устройстве.

я знаю, что нет никакого "идеального" способа получить уникальный идентификатор без использования разрешений; однако иногда нам действительно нужно отслеживать установку устройства. Когда дело доходит до создания уникального идентификатора, мы можем создать псевдо уникальный идентификационный основе исключительно от информации, которую Android API дает нам без использования дополнительных разрешений. Таким образом, мы можем показать уважение пользователя и попытаться предложить хороший пользовательский опыт.

С псевдо-уникальным идентификатором вы действительно сталкиваетесь только с тем, что могут быть дубликаты, основанные на том, что есть похожие устройства. Вы можете настроить комбинированный метод, чтобы сделать его более уникальным; однако некоторым разработчикам необходимо отслеживать установки устройств, и это сделает трюк или производительность, основанную на подобное устройство.

API >= 9:

если их Android-устройство API 9 или более, это гарантированно будет уникальным из-за "сборки".Серийное поле.

помните, технически вы пропускаете только около 0,5% пользователей у кого есть API . Таким образом, вы можете сосредоточиться на остальном: это 99,5% пользователей!

API

если Android-устройство пользователя ниже API 9; надеюсь, у них есть не сделано заводской перезагрузки и их "безопасность".ANDROID_ID 'будет сохранен или нет 'null'. (см. http://developer.android.com/about/dashboards/index.html)

если все остальное терпит неудачу:

если все остальное не удается, если пользователь имеет ниже, чем API 9 (ниже, чем Gingerbread), сбросил свое устройство или "безопасный".ANDROID_ID "возвращает " null", то просто ID возвращается будет исключительно на основе их Android информации об устройстве. Это где столкновения могут случаться.

изменения:

  • Удалено ' Android.SECURE_ID ' из-за заводских сбросов может привести к изменению значения
  • отредактировал код для изменения в API
  • изменен псевдо

пожалуйста, взгляните на метод ниже:

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

New (для приложений с рекламой и Google Play Services):

из консоли разработчика Google Play:

начиная с 1 августа 2014, политика программы разработчика Google Play требуется все новые загрузки приложений и обновления для использования рекламного идентификатора в замените любые другие постоянные идентификаторы для любых рекламных целей. Учить больше

реализация:

разрешение:

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

код:

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

Источник/Документы:

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

важно:

предполагается, что реклама ID полностью заменить существующий использование других идентификаторов для целей рекламы (например, использование ANDROID_ID в настройках.Secure), когда доступны сервисы Google Play. Случаи где службы Google Play недоступны, указывается GooglePlayServicesNotAvailableException выбрасывается getAdvertisingIdInfo ().

предупреждение, пользователи могут сброс:

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

я попытался ссылаться на каждую ссылку, из которой я взял информацию. Если вы отсутствуете и должны быть включены, пожалуйста, прокомментируйте!

Google Player Services InstanceID

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


Как упоминает Дэйв Уэбб,блог разработчика Android имеет статью что это покрывает. Их предпочтительным решением является отслеживание установок приложений, а не устройств, и это будет хорошо работать для большинства случаев использования. В блоге покажу вам необходимый код, чтобы сделать эту работу, и я рекомендую вам проверить его.

однако сообщение в блоге продолжает обсуждать решения, если вам нужен идентификатор устройства, а не идентификатор установки приложения. Я говорил с кем-то в Google, чтобы получить некоторые дополнительные разъяснения по нескольким пунктам в случае, если вам нужно это сделать. Вот что я обнаружил об идентификаторах устройств, которые не упоминаются в вышеупомянутом сообщении в блоге:

  • android_id является предпочтительным идентификатором устройства. ANDROID_ID является абсолютно надежным на версиях Android =2.3. Только 2.2 имеет проблемы, упомянутые в сообщении.
  • на несколько устройств нескольких производителей влияет ошибка ANDROID_ID в 2.2.
  • насколько я смог определить, все уязвимые устройства тот же ANDROID_ID, которая составляет 9774d56d682e549c. Который также является тем же идентификатором устройства, о котором сообщает эмулятор, btw.
  • Google считает, что OEMs исправили проблему для многих или большинства своих устройств, но я смог проверить, что по состоянию на начало апреля 2011 года, по крайней мере, все еще довольно легко найти устройства, которые имеют сломанные ANDROID_ID.

основываясь на рекомендациях Google, я реализовал класс, который будет генерировать уникальный UUID для каждого устройства, используя ANDROID_ID в качестве семени, где это необходимо, возвращаясь к TelephonyManager.getDeviceId () по мере необходимости, и если это не удается, прибегая к случайно сгенерированному уникальному UUID, который сохраняется при перезапуске приложения (но не при повторной установке приложения).

обратите внимание, что для устройств, которые должны иметь резервный идентификатор устройства, уникальный идентификатор будет упорствуют через сброс фабрики. Это что-то знать. Если вам нужно убедиться, что заводская перезагрузка сбросит Ваш уникальный идентификатор, вы можете рассмотреть возможность возврата непосредственно к случайному UUID вместо идентификатора устройства.

опять же, этот код предназначен для идентификатора устройства, а не ID установки приложения. В большинстве случаев идентификатор установки приложения-это, вероятно, то, что вы ищете. Но если вам нужен ID устройства, то следующий код будет работать на вы.

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

вот код, который Reto Meier использовал в Google I / O презентация в этом году, чтобы получить уникальный идентификатор для пользователя:

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

Если вы пару это с стратегии резервного копирования для отправки настроек в облако (также описано в Рето-х говорить, у вас должен быть идентификатор, который привязывается к пользователю и прилипает после того, как устройство было стерто или даже заменено. Я планирую использовать это в аналитике в будущем (другими словами, я еще не сделал этого бит :).


также вы можете рассмотреть MAC-адрес адаптера Wi-Fi. Извлекается таким образом:

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

требуется разрешение android.permission.ACCESS_WIFI_STATE в манифесте.

сообщается, что он доступен, даже если Wi-Fi не подключен. Если Джо из ответа выше дает этому попробовать на своих многочисленных устройствах, это было бы неплохо.

на некоторых устройствах он недоступен при выключенном Wi-Fi.

Примечание: Из Android 6.x, он возвращает последовательный поддельный mac-адрес: 02:00:00:00:00:00


есть довольно полезная информация здесь.

он охватывает пять различных типов идентификаторов:

  1. IMEI (только для Android устройств с использованием телефона; потребности android.permission.READ_PHONE_STATE)
  2. псевдо-уникальный ID (для всех устройств Android)
  3. Android ID (может быть null, может изменяться при сбросе заводских настроек, может быть изменен на корневом телефоне)
  4. WLAN MAC-адрес строка (должен android.permission.ACCESS_WIFI_STATE)
  5. BT MAC-адрес строка (устройства с Bluetooth, потребности android.permission.BLUETOOTH)

официальный блог разработчиков Android теперь имеет полную статью как раз об этой теме, Идентификация Установки Приложений.


At Google I / O Reto Meier выпустила надежный ответ на то, как подойти к этому, который должен удовлетворить большинство разработчиков, чтобы отслеживать пользователей через установки. Энтони Нолан показывает направление в своем ответе, но я подумал, что напишу полный подход, чтобы другие могли легко увидеть, как это сделать (мне потребовалось некоторое время, чтобы выяснить детали).

этот подход даст вам анонимный, безопасный идентификатор пользователя, который будет постоянным для пользователя в разных устройства (на основе основной учетной записи Google) и между установками. Основной подход заключается в создании случайного идентификатора пользователя и сохранении его в общих настройках приложений. Затем вы используете агент резервного копирования Google для хранения общих настроек, связанных с учетной записью Google в облаке.

давайте пройдем через полный подход. Во-первых, нам нужно создать резервную копию для наших SharedPreferences с помощью службы резервного копирования Android. Начните с регистрации вашего приложения через http://developer.android.com/google/backup/signup.html.

Google будет дать вам ключ службы резервного копирования, который необходимо добавить в манифест. Вы также должны сказать приложению использовать BackupAgent следующим образом:

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

затем вам нужно создать агент резервного копирования и сказать ему использовать вспомогательный агент для sharedpreferences:

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

для завершения резервного копирования вам необходимо создать экземпляр BackupManager в вашей основной деятельности:

BackupManager backupManager = new BackupManager(context);

наконец, создайте идентификатор пользователя, если он еще не существует, и сохраните его в 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;
}

этот User_ID теперь будет сохраняться на всех установках, даже если пользователь перемещает устройство.

для получения дополнительной информации об этом подходе см. разговор Рето.

и для получения полной информации о том, как реализовать агент резервного копирования см. Резервное Копирование Данных. Я особенно рекомендую раздел внизу на тестирование, поскольку резервное копирование не происходит мгновенно, и поэтому для тестирования вам нужно заставить резервное копирование.


следующий код возвращает серийный номер устройства с помощью скрытого API Android. Но этот код не работает на вкладке Samsung Galaxy, потому что " ro.serialno " не установлен на этом устройстве.

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

}

Я думаю, что это верный способ построения скелета уникальный идентификатор... проверить его.

псевдо-уникальный ID, который работает на всех устройствах Android Некоторые устройства не имеют телефона (например. Таблетки) или по какой-то причине вы не хотите включать разрешение READ_PHONE_STATE. Вы все еще можете прочитать детали, такие как версия ROM, имя производителя, тип процессора и другие детали оборудования, которые будут хорошо подходить, если вы хотите использовать ID для проверки серийного ключа или других общих целей. Этот ID, вычисленный таким образом, не будет уникальным: можно найти два устройства с одинаковым ID (на основе одного и того же оборудования и образа ROM), но изменения в реальных приложениях незначительны. Для этого можно использовать класс 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

большинство членов сборки-строки, то, что мы здесь делаем, - это взять их длину и преобразовать ее по модулю в цифру. У нас есть 13 таких цифр, и мы добавляем еще две спереди (35), чтобы иметь тот же идентификатор размера, ЧТО и IMEI (15 десятичные знаки.) Есть и другие возможности здесь хорошо, просто взгляните на эти строки. Возвращает что-то вроде 355715565309247. Специального разрешения не требуется, что делает такой подход очень удобным.


(дополнительная информация: приведенная выше техника была скопирована из статьи на Карман Магия.)


используя приведенный ниже код, вы можете получить уникальный идентификатор устройства Android OS в виде строки.

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

на серийный поле было добавлено к Build класс в API уровня 9 (Android 2.3-Gingerbread). В документации говорится, что он представляет серийный номер оборудования. Таким образом, он должен быть уникальным, если он существует на устройстве.

Я не знаю, действительно ли он поддерживается (=не null) всеми устройствами с уровнем API >= 9.


одна вещь, которую я добавлю - у меня есть одна из этих уникальных ситуаций.

использование:

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

оказывается, что, хотя мой планшет Viewsonic G сообщает DeviceID, который не является нулевым, каждый планшет G сообщает одно и то же число.

делает его интересным, играя "Pocket Empires", который дает вам мгновенный доступ к чьей-то учетной записи на основе" уникального " DeviceID.

мое устройство не имеет сотового радио.


подробные инструкции о том, как получить уникальный идентификатор для каждого устройства Android, с которого установлено приложение, см. В официальном блоге разработчиков Android Идентификация Установки Приложений.

Кажется, что лучший способ для вас, чтобы создать его самостоятельно при установке и впоследствии прочитать его, когда приложение будет повторно запущен.

Я лично считаю это приемлемым, но не идеальным. Нет идентификатора, предоставленного Android работает во всех случаях, так как большинство из них зависят от состояния радио телефона (Wi-Fi вкл/выкл, сотовая связь вкл/выкл, Bluetooth вкл/выкл). Другие, как Settings.Secure.ANDROID_ID должно быть реализовано производителем и не гарантируется уникальность.

ниже приведен пример записи данных в установка файл, который будет храниться вместе с любыми другими данными, которые приложение сохраняет локально.

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

добавить ниже код в файл класса:

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

добавить в AndroidManifest.XML-код:

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

уникальный идентификатор устройства Android OS устройства в виде строки, используя TelephonyManager и ANDROID_ID получается:

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

но я настоятельно рекомендую метод, предложенный Google, см. Идентификация Установки Приложений.


существует множество различных подходов к работе с этими ANDROID_ID вопросы (может быть null иногда или устройства определенной модели всегда возвращают один и тот же ID) с плюсами и минусами:

  • реализация пользовательского алгоритма генерации идентификаторов (на основе свойств устройства, которые должны быть статическими и не будут меняться - > кто знает)
  • злоупотребление другими идентификаторами, такими как IMEI, серийный номер, Wi-Fi / Bluetooth-MAC-адрес (они не будут существовать на всех устройствах или дополнительные разрешения становятся необходимыми)

Я сам предпочитаю использовать существующую реализацию OpenUDID (см. https://github.com/ylechelle/OpenUDID) для Android (см.https://github.com/vieux/OpenUDID). Легко интегрировать и использовать ANDROID_ID с отступлениями для тех вопросов, упомянутых выше.


как о IMEI. Это уникально для Android или других мобильных устройств.


мои два цента-NB это для уникальный идентификатор устройства (err) - не установка, как обсуждалось в блог разработчиков Android.

отметим, что решение предоставленный @emmby возвращается в идентификатор приложения, поскольку SharedPreferences не синхронизируются между процессами (см. здесь и здесь). Поэтому я избегал этого.

вместо этого я инкапсулировал различные стратегии для получения идентификатора (устройства) в перечислении - изменение порядка констант перечисления влияет на приоритет различных способов получения идентификатора. Возвращается первый ненулевой идентификатор или создается исключение (в соответствии с хорошей практикой Java не давать null значение). Так, например, у меня есть Телефония, но хорошим выбором по умолчанию будет ANDROID_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);
        }
    }
}

вот как я генерирую уникальный идентификатор:

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

другой способ-использовать /sys/class/android_usb/android0/iSerial в приложение без каких-либо разрешений.

[email protected]:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
[email protected]:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5

чтобы сделать это в Java, нужно просто использовать FileInputStream, чтобы открыть файл iSerial и прочитать символы. Просто убедитесь, что вы обернули его в обработчик исключений, потому что не все устройства имеют этот файл.

по крайней мере, следующие устройства, как известно, этот файл читаемый в мире:

  • Galaxy Nexus
  • Nexus S
  • Motorola Планшет с 3G
  • Toshiba AT300
  • HTC One V
  • мини MK802
  • Samsung Galaxy S II

вы также можете увидеть мой блог утечка серийного номера оборудования Android в непривилегированные приложения где я обсуждаю, какие другие файлы доступны для информации.


для аппаратного распознавания конкретного устройства Android вы можете проверить MAC-адреса.

вы можете сделать это таким образом:

в AndroidManifest.в XML

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

теперь в вашем коде:

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

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

в каждом устройстве Android их, по крайней мере, интерфейс "wlan0"-это чип WI-FI. Этот код работает даже тогда, когда WI-FI не включен.

С. П. Их куча других интерфейсов, которые вы получите из списка содержит Mac, но это может меняться между телефонами.


Я использую следующий код, чтобы получить IMEI или используйте Secure.ANDROID_ID в качестве альтернативы, когда устройство не имеет возможности телефона:

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

более конкретно, Settings.Secure.ANDROID_ID. Это 64-разрядное количество, которое создается и сохраняется при первой загрузке устройства. Оно сбрасывается при очистке устройства.

ANDROID_ID кажется хорошим выбором для уникального идентификатора устройства. Есть и минусы: Во-первых, он не на 100% надежен на выпусках Android до 2.2 (“Froyo”). кроме того, была по крайней мере одна широко наблюдаемая ошибка в популярном телефоне от крупного производителя, где каждый экземпляр имеет тот же ANDROID_ID.


идентификатор экземпляра Google

выпущен на I / O 2015; на Android требуется play services 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

похоже, что Google намерен использовать этот идентификатор для идентификации установок на Android, Chrome и iOS.

он идентифицирует установку, а не устройство, но опять же, ANDROID_ID (который является принятым ответом) теперь больше не идентифицирует устройства. Во время выполнения ARC для каждой установки создается новый ANDROID_ID (подробности здесь), как и этот новый идентификатор экземпляра. Кроме того, я думаю, что идентификация установок (а не устройств) - это то, что большинство из нас на самом деле ищет.

преимущества экземпляра ID

Мне кажется, что Google намерен использовать его для этого цель (идентификация ваших установок), она является кросс-платформенной и может использоваться для ряда других целей (см. ссылки выше).

Если вы используете GCM, то вам в конечном итоге понадобится использовать этот идентификатор экземпляра, потому что он нужен для получения маркера GCM (который заменяет старый идентификатор регистрации GCM).

недостатки/проблемы

в текущей реализации (GPS 7.5) идентификатор экземпляра извлекается с сервера при запросе приложения он. Это означает, что вызов выше является блокирующим вызовом - в моем ненаучном тестировании он занимает 1-3 секунды, если устройство находится в сети, и 0,5 - 1,0 секунды, если оффлайн (предположительно, это то, как долго он ждет, прежде чем сдаться и генерировать случайный идентификатор). Это было протестировано в Северной Америке на Nexus 5 с Android 5.1.1 и GPS 7.5.

Если вы используете ID для целей, которые они предполагают, например. аутентификация приложения, идентификация приложения , GCM-я думаю, что это 1-3 секунды может быть неприятностью (в зависимости в вашем приложении, конечно).


Android device mac id также уникальный id, он не изменится, предположим, если мы отформатируем само устройство, используя следующий код, чтобы получить MAC id

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

также не забудьте добавить соответствующие разрешения на ваш AndroidManifest.в XML

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

здесь есть 30+ ответов, и некоторые из них одинаковы, а некоторые уникальны. Этот ответ основан на немногих из этих ответов. Один из них-ответ @Lenn Dolling.

он объединяет 3 идентификатора и создает 32-значную шестнадцатеричную строку. Это сработало очень хорошо для меня.

3 идентификатор:
псевдо-ID - он генерируется на основе спецификаций физического устройства
ANDROID_ID - Settings.Secure.ANDROID_ID
Адрес Bluetooth - Bluetooth адаптер адрес

он вернет что-то вроде этого: 551F27C060712A72730B0A0F734064B1

Примечание: Вы всегда можете добавить больше идентификаторов в longId строку. Например, серийный№. адрес адаптера wifi. ИМЭИ. Таким образом, Вы делаете его более уникальным для каждого устройства.

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

Google теперь имеет идентификатор рекламы.
Это также можно использовать, но обратите внимание, что:

идентификатор рекламы-это пользовательский, уникальный, сбрасываемый идентификатор

и

позволяет пользователям сбросить свой идентификатор или отказаться от рекламы на основе интересов в приложениях Google Play.

поэтому, хотя этот идентификатор может измениться, кажется, что скоро у нас может не быть выбора, зависит от цели этот идентификатор.

дополнительная информация @ develper.android

копировать-вставить здесь код

HTH


TelephonyManger.getDeviceId() возвращает уникальный идентификатор устройства, например IMEI для GSM и MEID или ESN для телефонов CDMA.

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

но я рекомендую использовать:

настройки.Безопасный.ANDROID_ID Это возвращает идентификатор Android в виде уникальной 64-разрядной шестнадцатеричной строки.

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

иногда TelephonyManger.getDeviceId() вернет null, поэтому для обеспечения уникального идентификатора вы будете использовать этот метод:

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