В официальной Google-группе, посвященной Android'у, время от времени появляются жалобы разработчиков о том, что трудно найти уникальные, надежные и стабильные идентификаторы для Android-устройств.
В блоге android-developers был опубликован небольшой топик, посвященный тому, как отслеживать индивидуальные установки приложений. Думаю, кому-то это будет полезно.
Существует немало причин, по которым разработчики хотят отслеживать отдельные установки своих приложений. Некоторые просто вызывают метод TelephonyManager.getDeviceId() и используют это значение для идентификации отдельной установки. С этим есть некоторые проблемы: Во-первых, уникальность ID не гарантируется. Во-вторых, даже если это работает, то значение может пережить так называемый «Factory Reset» (сброс всех установок к начальным), что в конечном итоге может привести к неприятной ошибке, если один из покупателей/установщиков очистит свой девайс, и потом передаст его кому-то другому.
Чтобы отслеживать установки можно использовать UUID как идентификатор, и затем просто каждый раз создавать новый, при первом запуске приложения. Ниже набросок класса «Installation» (установка) с одним статическим методом Installation.id(Context context). Дальше всё зависит от вашей фантазии — можно дописывать различную специфичную для устройства информацию в файл INSTALLATION.
Представим себе, что вы хотите получить уникальный идентификатор отдельного устройства. Так или иначе, эта задача непростая.
Ранее, когда каждое Android-устройство было телефоном, то всё было просто: метод TelephonyManager.getDeviceId() возвращал IMEI, MEID, или ESN телефона, который гарантированно был уникален.
Однако, при этом подходе возникает ряд проблем:
Можно попробовать возвращать mac адрес для устройств, у которых есть Bluetooth или Wi-Fi. Это также не рекомендуется, потому что, во-первых, далеко не все устройства имеют Wi-Fi. Во-вторых, если модуль Wi-Fi не включен, то получить mac адрес не удастся.
С версии Android 2.3 (Gingerbread) можно получить серийный номер через android.os.Build.SERIAL. Для версий ниже 2.3, lopatoid описал способ в комментариях.
Более точно, это Settings.Secure.ANDROID_ID. Это 64-битное значение, которое генерируется при первой загрузке устройства, оно сбрасывается при очистке устройства (Factory Reset, etc.)
В принципе, ANDROID_ID неплохо подходит для идентификации устройства. Однако, у него есть некоторые недостатки: во-первых, он не на 100% надежен на версиях Android до 2.2 (Froyo). Во-вторых, существует один широко известный баг одного из производителей телефонов, из-за которого для всех устройств генерировался один и тот же ANDROID_ID.
Для большинства приложений главное — уникально идентифицировать отдельную установку, а не устройство. К счастью, это не трудно.
Есть много причин для того, чтобы избежать идентификации отдельных устройств. Для тех, кто всё-таки хочет попробовать, лучшим выбором, возможно, будет ANDROID_ID, с небольшой эвристикой для устаревших устройств.
В блоге android-developers был опубликован небольшой топик, посвященный тому, как отслеживать индивидуальные установки приложений. Думаю, кому-то это будет полезно.
Отслеживание установок
Существует немало причин, по которым разработчики хотят отслеживать отдельные установки своих приложений. Некоторые просто вызывают метод TelephonyManager.getDeviceId() и используют это значение для идентификации отдельной установки. С этим есть некоторые проблемы: Во-первых, уникальность ID не гарантируется. Во-вторых, даже если это работает, то значение может пережить так называемый «Factory Reset» (сброс всех установок к начальным), что в конечном итоге может привести к неприятной ошибке, если один из покупателей/установщиков очистит свой девайс, и потом передаст его кому-то другому.
Чтобы отслеживать установки можно использовать UUID как идентификатор, и затем просто каждый раз создавать новый, при первом запуске приложения. Ниже набросок класса «Installation» (установка) с одним статическим методом Installation.id(Context context). Дальше всё зависит от вашей фантазии — можно дописывать различную специфичную для устройства информацию в файл INSTALLATION.
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();
}
}
Идентификация устройств
Представим себе, что вы хотите получить уникальный идентификатор отдельного устройства. Так или иначе, эта задача непростая.
Ранее, когда каждое Android-устройство было телефоном, то всё было просто: метод TelephonyManager.getDeviceId() возвращал IMEI, MEID, или ESN телефона, который гарантированно был уникален.
Однако, при этом подходе возникает ряд проблем:
- Не телефоны. Wi-Fi устройства и музыкальные плейеры не имеют на борту телефонного оборудования, поэтому просто не в состоянии обеспечить эти идентификаторы.
- Постоянность. На устройствах, которые обеспечены телефонным модулем, эти идентификаторы не изменяются при сбросе всех настроек. Так что и приложение будет считать, что повторную установку подсчитывать не нужно.
- Дополнительные права. Требуется READ_PHONE_STATE, что раздражает клиентов, особенно, если приложение не использует телефонию.
- Баги. Бывает, что производители телефонов не следят за идентификаторами и вышеозначенный метод возвращает абракадабру.
Mac адрес
Можно попробовать возвращать mac адрес для устройств, у которых есть Bluetooth или Wi-Fi. Это также не рекомендуется, потому что, во-первых, далеко не все устройства имеют Wi-Fi. Во-вторых, если модуль Wi-Fi не включен, то получить mac адрес не удастся.
Серийный номер
С версии Android 2.3 (Gingerbread) можно получить серийный номер через android.os.Build.SERIAL. Для версий ниже 2.3, lopatoid описал способ в комментариях.
ANDROID_ID
Более точно, это Settings.Secure.ANDROID_ID. Это 64-битное значение, которое генерируется при первой загрузке устройства, оно сбрасывается при очистке устройства (Factory Reset, etc.)
В принципе, ANDROID_ID неплохо подходит для идентификации устройства. Однако, у него есть некоторые недостатки: во-первых, он не на 100% надежен на версиях Android до 2.2 (Froyo). Во-вторых, существует один широко известный баг одного из производителей телефонов, из-за которого для всех устройств генерировался один и тот же ANDROID_ID.
Вывод
Для большинства приложений главное — уникально идентифицировать отдельную установку, а не устройство. К счастью, это не трудно.
Есть много причин для того, чтобы избежать идентификации отдельных устройств. Для тех, кто всё-таки хочет попробовать, лучшим выбором, возможно, будет ANDROID_ID, с небольшой эвристикой для устаревших устройств.