Есть ли у устройств Android уникальный идентификатор, и если да, то каков простой способ получить к нему доступ с помощью Java?
Вопрос
Есть ли уникальный идентификатор устройства Android?
- Если вы используете ANDROID_ID, обязательно прочтите этот ответ и эта ошибка < / а>. Dheeraj Vepakomma 16.01.2013
- Ваше решение здесь: stackoverflow.com/a/63481350/7135685 Mujahid Khan 19.08.2020
Ответы
Ответ 1 · рейтинг 2128 · Anthony Forloney
Settings.Secure#ANDROID_ID возвращает идентификатор Android в виде уникальный для каждого пользователя 64-битное шестнадцатеричное нить.
import android.provider.Settings.Secure;
private String android_id = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
Также прочтите Рекомендации для уникальных идентификаторов: https://developer.android.com/training/articles/user-data-ids
Ответ 2 · рейтинг 1172 · Joe
ОБНОВЛЕНИЕ. В последних версиях Android многие проблемы с ANDROID_ID были решены, и я считаю, что в таком подходе больше нет необходимости. Взгляните на ответ Энтони.
Полное раскрытие: в моем приложении изначально использовался приведенный ниже подход, но он больше не используется, и теперь мы используем подход, описанный в Блог разработчиков Android, на которую ссылается ответ emmby (а именно , создание и сохранение UUID#randomUUID()).
На этот вопрос есть много ответов, большинство из которых будут работать только в некоторых случаях, и, к сожалению, этого недостаточно.
На основании моих тестов устройств (всех телефонов, хотя бы один из которых не активирован):
- Все протестированные устройства вернули значение
TelephonyManager.getDeviceId() - Все устройства GSM (все протестированы с SIM-картой) вернули значение
TelephonyManager.getSimSerialNumber() - Все устройства CDMA вернули нулевое значение для
getSimSerialNumber()(как и ожидалось) - Все устройства с добавленной учетной записью Google вернули значение для
ANDROID_ID - Все устройства CDMA вернули одно и то же значение (или производное от одного и того же значения) для
ANDROID_IDиTelephonyManager.getDeviceId()- до тех пор, пока учетная запись Google была добавлена во время настройки. - У меня еще не было возможности протестировать устройства 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" />
библиотеки импорта
import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;
Ответ 3 · рейтинг 448 · Jared Burrows
# Последнее обновление: 02.06.15
Прочитав все сообщения Stack Overflow о создании уникального идентификатора, блог разработчиков Google и документацию по Android, я чувствую, что "Псевдоидентификатор" - лучший из возможных вариантов.
Главный вопрос: аппаратное обеспечение против программного обеспечения
Аппаратное обеспечение
- Пользователи могут менять свое оборудование, планшет Android или телефон, поэтому уникальные идентификаторы, основанные на оборудовании, не подходят для ОТСЛЕЖИВАНИЯ ПОЛЬЗОВАТЕЛЕЙ.
- Для ОТСЛЕЖИВАНИЯ ОБОРУДОВАНИЯ это отличная идея.
Программное обеспечение
- Пользователи могут стереть / изменить свое ПЗУ, если они рутированы
- Вы можете отслеживать пользователей на разных платформах (iOS, Android, Windows и Интернет)
- Лучшее, что нужно для ОТСЛЕЖИВАНИЯ ИНДИВИДУАЛЬНОГО ПОЛЬЗОВАТЕЛЯ с его согласия, - просто попросить его войти в систему (сделать это легко с помощью OAuth).
# Общая поломка с Android
### - Гарантия уникальности (включая рутированные устройства) для API ›= 9/10 (99,5% устройств Android) ### - Без дополнительных разрешений
Псевдокод:
if API >= 9/10: (99.5% of devices)
return unique ID containing serial id (rooted devices may be different)
else
return the unique ID of build information (may overlap data - API < 9)
Спасибо @stansult за публикацию всех наших вариантов (в этом вопросе о переполнении стека).
## Список опций - причины, почему / почему их не использовать:
Электронная почта пользователя - Программное обеспечение
Пользователь мог изменить адрес электронной почты - ВЕЛИКОЛЕПНО
API 5+
<uses-permission android:name="android.permission.GET_ACCOUNTS" />илиAPI 14+
<uses-permission android:name="android.permission.READ_PROFILE" /><uses-permission android:name="android.permission.READ_CONTACTS" />(Как получить основной адрес электронной почты)Номер телефона пользователя - программное обеспечение
Пользователи могут менять номера телефонов - Маловероятно
<uses-permission android:name="android.permission.READ_PHONE_STATE" />IMEI - оборудование (только телефоны, требуется
android.permission.READ_PHONE_STATE)Большинство пользователей ненавидят тот факт, что в разрешении указано "Телефонные звонки". Некоторые пользователи дают плохие оценки, потому что считают, что вы просто крадете их личную информацию, тогда как все, что вам действительно нужно, - это отслеживать установки устройств. Очевидно, что вы собираете данные.
Идентификатор Android - оборудование (может быть нулевым, может измениться после сброса настроек, может быть изменен на устройстве с рутированным доступом)
Поскольку он может иметь значение "null", мы можем проверить наличие "null" и изменить его значение, но это означает, что оно больше не будет уникальным.
Если у вас есть пользователь с устройством сброса к заводским настройкам, значение могло быть изменено или изменено на рутированном устройстве, поэтому могут быть повторяющиеся записи, если вы отслеживаете установки пользователей.
MAC-адрес WLAN - оборудование (требуется
android.permission.ACCESS_WIFI_STATE)Это может быть второй лучший вариант, но вы по-прежнему собираете и храните уникальный идентификатор, который исходит непосредственно от пользователя. Очевидно, что вы собираете данные.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>MAC-адрес Bluetooth - оборудование (для устройств с Bluetooth требуется
android.permission.BLUETOOTH)Большинство приложений на рынке не используют Bluetooth, поэтому, если ваше приложение не использует Bluetooth и вы его включаете, пользователь может заподозрить подозрение.
<uses-permission android:name="android.permission.BLUETOOTH "/>Псевдоуникальный идентификатор - программное обеспечение (для всех устройств Android)
Очень возможно, могут содержать коллизии - см. Мой метод, опубликованный ниже!
Это позволяет вам получить "почти уникальный" идентификатор пользователя, не забирая ничего личного. Вы можете создать свой собственный анонимный идентификатор на основе информации об устройстве.
Я знаю, что не существует "идеального" способа получить уникальный идентификатор без использования разрешений; однако иногда нам действительно нужно только отслеживать установку устройства. Когда дело доходит до создания уникального идентификатора, мы можем создать "псевдоуникальный идентификатор" исключительно на основе информации, которую предоставляет нам Android API, без использования дополнительных разрешений. Таким образом, мы можем проявить уважение к пользователю и попытаться также предложить им хороший пользовательский опыт.
С псевдоуникальным идентификатором вы действительно сталкиваетесь только с тем фактом, что могут быть дубликаты, основанные на том факте, что существуют похожие устройства. Вы можете настроить комбинированный метод, чтобы сделать его более уникальным; однако некоторым разработчикам необходимо отслеживать установку устройств, и это поможет или повысит производительность на основе аналогичных устройств.
## API ›= 9:
Если их устройство Android имеет API 9 или более поздней версии, это гарантированно будет уникальным из-за поля "Build.SERIAL".
ПОМНИТЕ, что технически вы упускаете только около 0,5% пользователей у кого есть API ‹9. Так что можете сосредоточиться на остальном: это 99,5% пользователей!
## API ‹9:
Если Android-устройство пользователя ниже API 9; Надеюсь, они не сбросили настройки до заводских, и их Secure.ANDROID_ID будет сохранен или не будет иметь значение null. (см. http://developer.android.com/about/dashboards/index.html )
##Если все остальное терпит неудачу:
Если все остальное не помогает, если у пользователя ниже API 9 (ниже, чем Gingerbread), он сбросил свое устройство или Secure.ANDROID_ID возвращает значение null, тогда просто возвращаемый идентификатор будет основан исключительно на информации об их устройстве 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();
}
# Новое (для приложений с рекламой и сервисов Google Play):
В консоли разработчика 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.
##Важный:
Предполагается, что рекламный идентификатор полностью заменит существующее использование других идентификаторов в рекламных целях (например, использование ANDROID_ID в Settings.Secure), когда доступны Сервисы Google Play. Случаи, когда Сервисы Google Play недоступны, указываются исключением GooglePlayServicesNotAvailableException, создаваемым getAdvertisingIdInfo ().
## Предупреждение, пользователи могут сбросить:
http://en.kioskea.net/faq/34732-android-reset-your-advertising-id
Я попытался сослаться на каждую ссылку, по которой брал информацию. Если вас что-то не хватает и вы должны быть включены, прокомментируйте!
Идентификатор экземпляра сервисов Google Player
Ответ 4 · рейтинг 346 · emmby
Как упоминает Дэйв Уэбб, в блоге разработчиков Android есть статья Это покрывает это. Их предпочтительное решение - отслеживать установки приложений, а не устройств, и это хорошо работает для большинства случаев использования. Сообщение в блоге покажет вам код, необходимый для работы, и я рекомендую вам его проверить.
Однако в сообщении блога обсуждаются решения, если вам нужен идентификатор устройства, а не идентификатор установки приложения. Я поговорил с кем-то в Google, чтобы получить дополнительные разъяснения по некоторым вопросам, если вам это понадобится. Вот что я обнаружил об идентификаторах устройств, которые НЕ упоминаются в вышеупомянутом сообщении в блоге:
- ANDROID_ID - предпочтительный идентификатор устройства. ANDROID_ID идеально подходит для версий Android ‹= 2.1 или> = 2.3. Только 2.2 имеет проблемы, упомянутые в посте.
- Несколько устройств от нескольких производителей подвержены ошибке ANDROID_ID в 2.2.
- Насколько мне удалось определить, все затронутые устройства имеют один и тот же ANDROID_ID, который 9774d56d682e549c. Это тот же идентификатор устройства, о котором сообщает эмулятор, кстати.
- Google считает, что OEM-производители исправили проблему для многих или большинства своих устройств, но я смог убедиться, что, по крайней мере, на начало апреля 2011 года все еще довольно легко найти устройства со сломанным ANDROID_ID.
Основываясь на рекомендациях Google, я реализовал класс, который будет генерировать уникальный UUID для каждого устройства, используя ANDROID_ID в качестве начального значения там, где это необходимо, при необходимости прибегая к TelephonyManager.getDeviceId (), а если это не удается, прибегая к случайному сгенерированному уникальному идентификатору UUID. который сохраняется при перезапуске приложения (но не при повторной установке приложения).
Обратите внимание, что для устройств, которые должны использовать резервный идентификатор устройства, уникальный идентификатор БУДЕТ сохраняться при заводских сбросах. Об этом следует помнить. Если вам нужно убедиться, что при сбросе к заводским настройкам ваш уникальный идентификатор будет сброшен, вы можете рассмотреть возможность возврата непосредственно к случайному UUID, а не к идентификатору устройства.
Опять же, этот код предназначен для идентификатора устройства, а не идентификатора установки приложения. В большинстве случаев вам, вероятно, нужен идентификатор установки приложения. Но если вам нужен идентификатор устройства, то следующий код, вероятно, вам подойдет.
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;
}
}
Ответ 5 · рейтинг 185 · Anthony Nolan
Вот код, который Рето Мейер использовал в презентации 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;
}
Если вы объедините это со стратегией резервного копирования для отправки настроек в облако (также описанной в Reto talk, у вас должен быть идентификатор, который привязан к пользователю и остается после очистки устройства или даже замены. Я планирую использовать его в аналитике. в будущем (другими словами, я еще не сделал этого :).
Ответ 6 · рейтинг 105 · Seva Alekseyev
Также вы можете рассмотреть 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
Ответ 7 · рейтинг 89 · stansult
Здесь есть довольно полезная информация .
Он охватывает пять различных типов идентификаторов:
- IMEI (только для устройств Android с телефоном; требуется
android.permission.READ_PHONE_STATE) - Псевдоуникальный идентификатор (для всех устройств Android)
- Android ID (может быть пустым, может измениться после сброса настроек, может быть изменен на телефоне с рутированным доступом)
- Строка MAC-адреса WLAN (требуется
android.permission.ACCESS_WIFI_STATE) - Строка MAC-адреса BT (для устройств с Bluetooth требуется
android.permission.BLUETOOTH)
Ответ 8 · рейтинг 80 · Nikita Kurtin
Это простой вопрос, на который нет простого ответа.
Более того, все существующие ответы здесь устарели или ненадежны.
Итак, если вы ищете решение в 2020 году.
Вот несколько вещей, о которых следует помнить:
Все аппаратные идентификаторы (SSAID, IMEI, MAC и т. Д.) Ненадежны для устройств, не принадлежащих Google (все, кроме пикселей и нексусов), которые составляют более 50% активных устройств во всем мире. Поэтому в официальном передовых методах работы с идентификаторами Android четко указано:
Избегайте использования аппаратных идентификаторов, таких как SSAID (Android ID), IMEI, MAC-адрес и т. д.
Это делает большинство приведенных выше ответов недействительными. Также из-за различных обновлений безопасности Android некоторые из них требуют более новых и более строгих разрешений времени выполнения, которые могут быть просто отклонены пользователем.
В качестве примера CVE-2018-9489, который влияет на все упомянутые выше методы на основе WIFI.
Это делает эти идентификаторы не только ненадежными, но и во многих случаях недоступными.
Проще говоря: не используйте эти методы.
Многие другие ответы здесь предлагают использовать AdvertisingIdClient, который также несовместим, так как его дизайн должен использоваться только для профилирования рекламы. Это также указано в официальном справочнике.
Используйте рекламный идентификатор только для профилей пользователей или вариантов использования рекламы
Это не только ненадежно для идентификации устройства, но вы также должны следовать политика конфиденциальности пользователей в отношении отслеживания рекламы, в которой четко указано, что пользователь может сбросить или заблокировать ее в любой момент.
Так что тоже не используйте его.
Поскольку у вас не может быть желаемого статического глобально уникального и надежного идентификатора устройства. Официальный справочник Android предлагает:
По возможности используйте FirebaseInstanceId или GUID, хранящийся в частном порядке для всех других случаев использования, кроме предотвращения мошенничества с платежами и телефонной связи.
Это уникально для установки приложения на устройство, поэтому, когда пользователь удаляет приложение, оно стирается, поэтому оно не на 100% надежно, но это еще одна лучшая вещь.
Чтобы использовать FirebaseInstanceId, добавьте последнюю зависимость обмена сообщениями firebase в свой gradle
implementation 'com.google.firebase:firebase-messaging:20.2.4'
И используйте приведенный ниже код в фоновом потоке:
String reliableIdentifier = FirebaseInstanceId.getInstance().getId();
Если вам нужно сохранить идентификацию устройства на удаленном сервере, сохраняйте его не как есть (обычный текст), а как хеш с солью.
Сегодня это не только лучшая практика, вы фактически должны делать это по закону в соответствии с GDPR - идентификаторы и аналогичные правила.
Ответ 9 · рейтинг 53 · BoD
В официальном блоге разработчиков Android теперь есть полная статья именно на эту тему, Идентификация Установки приложений.
Ответ 10 · рейтинг 47 · TechnoTony
На странице Google I / O Рето Мейер опубликовал подробный ответ о том, как подойти к этому, который должен соответствовать требованиям большинства разработчиков. пользователей в разных установках. Энтони Нолан показывает направление в своем ответе, но я подумал, что напишу полный подход, чтобы другие могли легко увидеть, как это сделать (мне потребовалось время, чтобы выяснить детали).
Такой подход предоставит вам анонимный, безопасный идентификатор пользователя, который будет постоянным для пользователя на разных устройствах (на основе основной учетной записи Google) и между установками. Базовый подход - создать случайный идентификатор пользователя и сохранить его в общих настройках приложений. Затем вы используете агент резервного копирования Google, чтобы сохранить общие настройки, связанные с учетной записью Google, в облаке.
Давайте рассмотрим полный подход. Во-первых, нам нужно создать резервную копию наших SharedPreferences с помощью Android Backup Service. Начните с регистрации своего приложения через 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>
Затем вам нужно создать агент резервного копирования и указать ему использовать вспомогательный агент для общих настроек:
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 в вашем основном Activity:
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 теперь будет постоянным для всех установок, даже если пользователь перемещает устройство.
Для получения дополнительной информации об этом подходе см. Выступление Рето.
А для получения полной информации о том, как реализовать агент резервного копирования, см. Резервное копирование данных em. >. Я особенно рекомендую раздел внизу, посвященный тестированию, поскольку резервное копирование не происходит мгновенно, и поэтому для тестирования вам нужно принудительно выполнить резервное копирование.
Ответ 11 · рейтинг 43 · Lenn Dolling
Я думаю, что это верный способ создания скелета для уникального идентификатора ... проверьте это.
Псевдоуникальный идентификатор, который работает на всех устройствах Android. На некоторых устройствах нет телефона (например, планшеты), или по какой-то причине вы не хотите включать разрешение READ_PHONE_STATE. Вы по-прежнему можете читать такие детали, как версия ПЗУ, название производителя, тип процессора и другие сведения об оборудовании, которые хорошо подойдут, если вы хотите использовать идентификатор для проверки серийного ключа или других общих целей. Вычисленный таким образом идентификатор не будет уникальным: можно найти два устройства с одинаковым идентификатором (на основе одного и того же оборудования и образа ПЗУ), но изменения в реальных приложениях незначительны. Для этого вы можете использовать класс 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
Большинство членов Build являются строками, и мы здесь берем их длину и преобразуем ее по модулю в цифру. У нас есть 13 таких цифр, и мы добавляем еще две впереди (35), чтобы иметь идентификатор того же размера, что и IMEI (15 цифр). Здесь есть и другие возможности, просто взгляните на эти строки. Возвращает что-то вроде 355715565309247. Специального разрешения не требуется, что делает такой подход очень удобным.
(Дополнительная информация: описанная выше техника была скопирована из статьи на Pocket Magic.)
Ответ 12 · рейтинг 40 · Roman SL
Следующий код возвращает серийный номер устройства с помощью скрытого Android API. Но этот код не работает на Samsung Galaxy Tab, потому что "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) {
}
Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.
Похожие материалы
- Использовать основной поток после длительной работы в сети
- Android объединяет два вызова Firestore в один обратный вызов
- Преобразование ада обратного вызова в отложенный объект
- Как показать мое приложение в приложениях выбора, когда кто-то нажимает динамическую ссылку firebase?
- Как сгенерировать уникальный идентификатор хоста?
- Как убедиться, что SQLite никогда не создает строку с одним и тем же идентификатором дважды?