Muszę używać unikalnego identyfikatora aplikacji na Androida i pomyślałem, że numer seryjny urządzenia będzie dobrym kandydatem. Jak odzyskać numer seryjny urządzenia z systemem Android w mojej aplikacji?
Muszę używać unikalnego identyfikatora aplikacji na Androida i pomyślałem, że numer seryjny urządzenia będzie dobrym kandydatem. Jak odzyskać numer seryjny urządzenia z systemem Android w mojej aplikacji?
Odpowiedzi:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemService to metoda z klasy Activity. getDeviceID () zwróci MDN lub MEID urządzenia w zależności od tego, jakiego radia używa telefon (GSM lub CDMA).
Każde urządzenie MUSI zwrócić tutaj unikalną wartość (zakładając, że jest to telefon). To powinno działać na każdym urządzeniu z Androidem z gniazdem karty SIM lub radiem CDMA. Dzięki tej kuchence mikrofalowej z systemem Android jesteś sam ;-)
Jak wspomina Dave Webb, na blogu programistów Androida znajduje się artykuł na ten temat.
Rozmawiałem z kimś w Google, aby uzyskać dodatkowe wyjaśnienia dotyczące kilku kwestii. Oto, co odkryłem, a NIE zostało wspomniane we wspomnianym poście na blogu:
Opierając się na zaleceniach Google, zaimplementowałem klasę, która będzie generować unikalny UUID dla każdego urządzenia, używając ANDROID_ID jako zarodka tam, gdzie to konieczne, w razie potrzeby powracając do TelephonyManager.getDeviceId (), a jeśli to się nie powiedzie, uciekając się do losowo wygenerowanego unikalnego UUID który jest utrwalany po ponownym uruchomieniu aplikacji (ale nie podczas ponownych instalacji aplikacji).
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 static volatile 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;
}
}
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) {
}
Ten kod zwraca numer seryjny urządzenia przy użyciu ukrytego interfejsu API systemu Android.
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
Chociaż nie ma gwarancji, że identyfikator Androida będzie unikalnym identyfikatorem.
getContentResolver
wraca null
. Warto jednak otworzyć pytanie i zamieścić swój kod.
Na blogu programistów Androida znajduje się świetny post omawiający to .
Odradza używanie, TelephonyManager.getDeviceId()
ponieważ nie działa na urządzeniach z Androidem, które nie są telefonami, takimi jak tablety, wymaga READ_PHONE_STATE
pozwolenia i nie działa niezawodnie na wszystkich telefonach.
Zamiast tego możesz użyć jednego z następujących:
W poście omówiono zalety i wady każdego z nich i warto go przeczytać, abyś mógł ustalić, który z nich będzie najlepszy do Twojego użytku.
Aby uzyskać prosty numer, który jest unikalny dla urządzenia i niezmienny przez cały okres jego eksploatacji (z wyjątkiem przywrócenia ustawień fabrycznych lub włamań), użyj opcji Settings.Secure.ANDROID_ID .
String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Aby użyć numeru seryjnego urządzenia (tego pokazanego w „Ustawieniach systemu / Informacje / Stan”), jeśli jest dostępny, i wrócić do identyfikatora Androida:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);
IMEI jest dobry, ale działa tylko na urządzeniach z Androidem z telefonem. Powinieneś rozważyć obsługę tabletów lub innych urządzeń z Androidem, które nie mają telefonu.
Masz kilka alternatyw, takich jak: Kompiluj członków klasy, BT MAC, WLAN MAC lub jeszcze lepiej - kombinacja wszystkich tych.
Wyjaśniłem te szczegóły w artykule na moim blogu, patrz: http://www.pocketmagic.net/?p=1662
Ponieważ żadna odpowiedź nie wspomina o idealnym, niezawodnym identyfikatorze, który jest zarówno TRWAŁY dzięki aktualizacjom systemu, jak i istnieje na WSZYSTKICH urządzeniach (głównie ze względu na brak indywidualnego rozwiązania od Google), zdecydowałem się opublikować metodę, która jest Następną najlepszą rzeczą jest połączenie dwóch dostępnych identyfikatorów i sprawdzenie, czy wybierzesz między nimi w czasie wykonywania.
Przed kodem, 3 fakty:
TelephonyManager.getDeviceId()
(akaIMEI) nie będzie działać dobrze lub w ogóle nie będzie działać na urządzeniach innych niż GSM, 3G, LTE itp., ale zawsze zwróci unikalny identyfikator, gdy powiązany jest sprzęt , nawet gdy nie jest włożona karta SIM lub nawet gdy nie ma gniazda SIM ( niektórzy producenci OEM to zrobili).
Ponieważ Gingerbread (Android 2.3) android.os.Build.SERIAL
musi istnieć na każdym urządzeniu, które nie zapewnia IMEI , tj. Nie ma wspomnianego sprzętu, zgodnie z zasadami Androida.
Z uwagi na fakt (2.), co najmniej jeden z tych dwóch unikalnych identyfikatorów będzie ZAWSZE obecny , a SERIAL może być obecny w tym samym czasie co IMEI.
Uwaga: Fakty (1.) i (2.) opierają się na oświadczeniach Google
ROZWIĄZANIE
Biorąc pod uwagę powyższe fakty, zawsze można mieć unikalny identyfikator, sprawdzając, czy istnieje sprzęt powiązany z IMEI, i powrócić do SERIALU, gdy go nie ma, ponieważ nie można sprawdzić, czy istniejący SERIAL jest ważny. Poniższa klasa statyczna przedstawia 2 metody sprawdzania takiej obecności i korzystania z IMEI lub SERIAL:
import java.lang.reflect.Method;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
public class IDManagement {
public static String getCleartextID_SIMCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(isSIMAvailable(mContext,telMgr)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId());
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);
// return Settings.Secure.ANDROID_ID;
return android.os.Build.SERIAL;
}
}
public static String getCleartextID_HARDCHECK (Context mContext){
String ret = "";
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if(telMgr != null && hasTelephony(mContext)){
Log.i("DEVICE UNIQUE IDENTIFIER",telMgr.getDeviceId() + "");
return telMgr.getDeviceId();
}
else{
Log.i("DEVICE UNIQUE IDENTIFIER", Settings.Secure.ANDROID_ID);
// return Settings.Secure.ANDROID_ID;
return android.os.Build.SERIAL;
}
}
public static boolean isSIMAvailable(Context mContext,
TelephonyManager telMgr){
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
return false;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
return false;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
return false;
case TelephonyManager.SIM_STATE_READY:
return true;
case TelephonyManager.SIM_STATE_UNKNOWN:
return false;
default:
return false;
}
}
static public boolean hasTelephony(Context mContext)
{
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (tm == null)
return false;
//devices below are phones only
if (Build.VERSION.SDK_INT < 5)
return true;
PackageManager pm = mContext.getPackageManager();
if (pm == null)
return false;
boolean retval = false;
try
{
Class<?> [] parameters = new Class[1];
parameters[0] = String.class;
Method method = pm.getClass().getMethod("hasSystemFeature", parameters);
Object [] parm = new Object[1];
parm[0] = "android.hardware.telephony";
Object retValue = method.invoke(pm, parm);
if (retValue instanceof Boolean)
retval = ((Boolean) retValue).booleanValue();
else
retval = false;
}
catch (Exception e)
{
retval = false;
}
return retval;
}
}
Radziłbym używać getCleartextID_HARDCHECK
. Jeśli odbicie nie trzyma się w Twoim otoczeniu, użyj getCleartextID_SIMCHECK
zamiast tego metody, ale weź pod uwagę, że powinna być dostosowana do Twoich konkretnych potrzeb w zakresie obecności karty SIM.
PS : Proszę zauważyć, że producentom OEM udało się wyprowadzić błąd SERIAL z zasadami Google (wiele urządzeń z tym samym SERIALEM), a Google, jak stwierdzono, istnieje co najmniej jeden znany przypadek w przypadku dużego producenta OEM (nie ujawniono i nie wiem, która marka to też, zgaduję, Samsung).
Zastrzeżenie : To odpowiedź na pierwotne pytanie o uzyskanie unikalnego identyfikatora urządzenia, ale OP wprowadził niejednoznaczność, stwierdzając, że potrzebuje unikalnego identyfikatora dla aplikacji. Nawet jeśli w takich scenariuszach Android_ID byłby lepszy, NIE BĘDZIE DZIAŁAŁ po, powiedzmy, kopii zapasowej Titanium aplikacji poprzez 2 różne instalacje ROM (może to być nawet ten sam ROM). Moje rozwiązanie zachowuje trwałość, która jest niezależna od flashowania lub resetowania do ustawień fabrycznych i zawiedzie tylko wtedy, gdy nastąpi manipulacja IMEI lub SERIAL przez hacki / modyfikacje sprzętowe.
Z wszystkimi powyższymi podejściami są problemy. W Google i / o Reto Meier wydał solidną odpowiedź na to, jak podejść do tego problemu, która powinna zaspokoić potrzeby większości programistów w zakresie śledzenia użytkowników w różnych instalacjach.
Takie podejście zapewnia anonimowy, bezpieczny identyfikator użytkownika, który będzie trwały dla użytkownika na różnych urządzeniach (w tym tabletach, w oparciu o podstawowe konto Google) i podczas instalacji na tym samym urządzeniu. Podstawowym podejściem jest wygenerowanie losowego identyfikatora użytkownika i zapisanie go we wspólnych preferencjach aplikacji. Następnie korzystasz z agenta kopii zapasowych Google do przechowywania wspólnych preferencji połączonych z kontem Google w chmurze.
Przejdźmy przez pełne podejście. Najpierw musimy utworzyć kopię zapasową naszych SharedPreferences przy użyciu usługi Android Backup Service. Zacznij od rejestracji aplikacji za pomocą tego linku: http://developer.android.com/google/backup/signup.html
Google dostarczy Ci zapasowy klucz serwisowy, który musisz dodać do manifestu. Musisz także powiedzieć aplikacji, aby używała BackupAgent w następujący sposób:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
Następnie musisz utworzyć agenta kopii zapasowych i powiedzieć mu, aby używał agenta pomocniczego dla wspólnych preferencji:
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);
}
}
Aby zakończyć tworzenie kopii zapasowej, musisz utworzyć instancję BackupManager w swojej głównej aktywności:
BackupManager backupManager = new BackupManager(context);
Na koniec utwórz identyfikator użytkownika, jeśli jeszcze nie istnieje, i zapisz go w 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;
}
Ten identyfikator_użytkownika będzie teraz trwały we wszystkich instalacjach, nawet jeśli użytkownik zmieni urządzenia.
Aby uzyskać więcej informacji na temat tego podejścia, zobacz wykład Reto tutaj http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
Aby uzyskać szczegółowe informacje o tym, jak wdrożyć agenta kopii zapasowych, odwiedź witrynę programistów tutaj: http://developer.android.com/guide/topics/data/backup.html Szczególnie polecam sekcję na dole dotyczącą testowania, ponieważ robi to kopia zapasowa nie dzieje się natychmiast, więc aby przetestować, musisz wymusić tworzenie kopii zapasowej.
Innym sposobem jest użycie / sys / class / android_usb / android0 / iSerial w aplikacji bez jakichkolwiek uprawnień.
user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root root 4096 2013-01-10 21:08 iSerial
user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial
0A3CXXXXXXXXXX5
Aby to zrobić w Javie, wystarczy użyć FileInputStream, aby otworzyć plik iSerial i odczytać znaki. Tylko pamiętaj, aby umieścić go w obsłudze wyjątków, ponieważ nie wszystkie urządzenia mają ten plik.
Przynajmniej następujące urządzenia są znane z tego, że ten plik jest czytelny dla wszystkich:
Możesz również zobaczyć mój post na blogu tutaj: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html, gdzie omawiam, jakie inne pliki są dostępne dla informacji.
Jak mówi @haserman:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
Konieczne jest jednak uwzględnienie pozwolenia w pliku manifestu:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Unikalny identyfikator urządzenia z systemem operacyjnym Android jako ciąg.
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);
}
ale zdecydowanie polecam tę metodę sugerowaną przez Google:
Build.SERIAL
to najprostszy sposób, chociaż nie do końca niezawodny, ponieważ może być pusty lub czasami zwracać inną wartość ( dowód 1 , dowód 2 ) niż to, co możesz zobaczyć w ustawieniach urządzenia.
Istnieje kilka sposobów uzyskania tego numeru w zależności od producenta urządzenia i wersji Androida, więc zdecydowałem się skompilować każde możliwe rozwiązanie, które mogłem znaleźć w jednym skrócie . Oto uproszczona wersja:
public static String getSerialNumber() {
String serialNumber;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
serialNumber = (String) get.invoke(c, "gsm.sn1");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "ril.serialnumber");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "ro.serialno");
if (serialNumber.equals(""))
serialNumber = (String) get.invoke(c, "sys.serialnumber");
if (serialNumber.equals(""))
serialNumber = Build.SERIAL;
// If none of the methods above worked
if (serialNumber.equals(""))
serialNumber = null;
} catch (Exception e) {
e.printStackTrace();
serialNumber = null;
}
return serialNumber;
}
Wiem, że to pytanie jest stare, ale można to zrobić w jednej linii kodu
String deviceID = Build.SERIAL;
Uważam, że przykładowa klasa opublikowana przez @emmby powyżej jest świetnym punktem wyjścia. Ale ma kilka wad, o których wspominają inne plakaty. Głównym z nich jest to, że niepotrzebnie utrwala identyfikator UUID w pliku XML, a następnie zawsze pobiera go z tego pliku. To otwiera klasę na łatwy hack: każdy, kto ma zrootowany telefon, może edytować plik XML, aby nadać sobie nowy identyfikator UUID.
Zaktualizowałem kod, aby zachowywał się w formacie XML tylko wtedy, gdy jest to absolutnie konieczne (np. Podczas korzystania z losowo wygenerowanego identyfikatora UUID) i ponownie rozłożyłem logikę zgodnie z odpowiedzią @Brill Pappin:
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 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) || (androidId == null) ) {
final String deviceId = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE )).getDeviceId();
if (deviceId != null)
{
uuid = UUID.nameUUIDFromBytes(deviceId.getBytes("utf8"));
}
else
{
uuid = UUID.randomUUID();
// Write the value out to the prefs file so it persists
prefs.edit().putString(PREFS_DEVICE_ID, uuid.toString() ).commit();
}
}
else
{
uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
/**
* 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;
}
Tak. Jest to numer seryjny sprzętu urządzenia i jest unikalny. Tak więc na poziomie API 2.3 i nowszym możesz użyć android.os.Build.ANDROID_ID, aby go pobrać. Dla poziomu API poniżej 2.3 użyj TelephonyManager.getDeviceID () .
możesz przeczytać ten http://android-developers.blogspot.in/2011/03/identifying-app-installations.html