Necesito usar una identificación única para una aplicación de Android y pensé que el número de serie del dispositivo sería un buen candidato. ¿Cómo recupero el número de serie de un dispositivo Android en mi aplicación?
Necesito usar una identificación única para una aplicación de Android y pensé que el número de serie del dispositivo sería un buen candidato. ¿Cómo recupero el número de serie de un dispositivo Android en mi aplicación?
Respuestas:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemService es un método de la clase Activity. getDeviceID () devolverá el MDN o MEID del dispositivo según la radio que utilice el teléfono (GSM o CDMA).
Cada dispositivo DEBE devolver un valor único aquí (suponiendo que sea un teléfono). Esto debería funcionar para cualquier dispositivo Android con una ranura SIM o radio CDMA. Estás solo con ese microondas con Android ;-)
Como menciona Dave Webb, el Blog para desarrolladores de Android tiene un artículo que cubre esto.
Hablé con alguien de Google para obtener aclaraciones adicionales sobre algunos elementos. Esto es lo que descubrí que NO se menciona en la publicación del blog antes mencionada:
De acuerdo con las recomendaciones de Google, implementé una clase que generará un UUID único para cada dispositivo, usando ANDROID_ID como semilla cuando corresponda, recurriendo a TelephonyManager.getDeviceId () según sea necesario, y si eso falla, recurriendo a un UUID único generado aleatoriamente que persiste en los reinicios de la aplicación (pero no en las reinstalaciones de la aplicación).
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) {
}
Este código devuelve el número de serie del dispositivo mediante una API de Android oculta.
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
Sin embargo, no se garantiza que la ID de Android sea un identificador único.
getContentResolver
está regresando null
. Sin embargo, puede valer la pena abrir una pregunta y publicar su código.
Hay una publicación excelente en el Blog de desarrolladores de Android que habla de esto .
Se recomienda no usarlo TelephonyManager.getDeviceId()
ya que no funciona en dispositivos Android que no son teléfonos como tabletas, requiere elREAD_PHONE_STATE
permiso y no funciona de manera confiable en todos los teléfonos.
En su lugar, puede utilizar uno de los siguientes:
La publicación analiza los pros y los contras de cada uno y vale la pena leerlo para que pueda determinar cuál sería el mejor para su uso.
Para obtener un número simple que sea exclusivo del dispositivo y constante durante toda su vida (salvo que se realice un restablecimiento de fábrica o piratería), use Settings.Secure.ANDROID_ID .
String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Para usar el número de serie del dispositivo (el que se muestra en "Configuración del sistema / Acerca de / Estado") si está disponible y recurrir al ID de Android:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);
El IMEI es bueno pero solo funciona en dispositivos Android con teléfono. También debe considerar la compatibilidad con tabletas u otros dispositivos Android que no tengan teléfono.
Tiene algunas alternativas como: miembros de la clase de compilación, BT MAC, WLAN MAC o incluso mejor, una combinación de todos estos.
He explicado estos detalles en un artículo de mi blog, consulte: http://www.pocketmagic.net/?p=1662
Dado que ninguna respuesta aquí menciona una identificación perfecta y a prueba de fallas que es PERSISTENTE a través de las actualizaciones del sistema y existe en TODOS los dispositivos (principalmente debido al hecho de que no hay una solución individual de Google), decidí publicar un método que es la siguiente mejor opción es combinar dos de los identificadores disponibles y una verificación para elegir entre ellos en tiempo de ejecución.
Antes del código, 3 hechos:
TelephonyManager.getDeviceId()
(akaIMEI) no funcionará bien o en absoluto para dispositivos que no sean GSM, 3G, LTE, etc., pero siempre devolverá una ID única cuando el hardware relacionado esté presente , incluso cuando no se inserte una SIM o incluso cuando no exista una ranura para SIM ( algunos OEM han hecho esto).
Dado que Gingerbread (Android 2.3) android.os.Build.SERIAL
debe existir en cualquier dispositivo que no proporcione IMEI , es decir, que no tenga presente el hardware mencionado anteriormente, según la política de Android.
Debido al hecho (2.), al menos uno de estos dos identificadores únicos SIEMPRE estará presente , y SERIAL puede estar presente al mismo tiempo que el IMEI.
Nota: Los hechos (1.) y (2.) se basan en declaraciones de Google
SOLUCIÓN
Con los hechos anteriores, uno siempre puede tener un identificador único al verificar si hay hardware vinculado a IMEI, y recurrir a SERIAL cuando no lo es, ya que no se puede verificar si el SERIAL existente es válido. La siguiente clase estática presenta 2 métodos para verificar dicha presencia y usar IMEI o 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;
}
}
Yo aconsejaría sobre el uso getCleartextID_HARDCHECK
. Si el reflejo no se pega en su entorno, utilice el getCleartextID_SIMCHECK
método en su lugar, pero tenga en cuenta que debe adaptarse a sus necesidades específicas de presencia de SIM.
PD : tenga en cuenta que los OEM tienen logrado bloquear SERIAL contra la política de Google (varios dispositivos con la misma SERIAL), y Google, como se indicó, hay al menos un caso conocido en un gran OEM (no divulgado y no sé qué marca lo es, supongo que Samsung).
Descargo de responsabilidad : Esto responde a la pregunta original de obtener una ID de dispositivo única, pero el OP introdujo ambigüedad al afirmar que necesita una ID única para una APLICACIÓN. Incluso si para tales escenarios Android_ID sería mejor, NO FUNCIONARÁ después de, digamos, una copia de seguridad de titanio de una aplicación a través de 2 instalaciones de ROM diferentes (incluso puede ser la misma ROM). Mi solución mantiene una persistencia que es independiente de un flash o un restablecimiento de fábrica, y solo fallará cuando se produzca una manipulación de IMEI o SERIAL a través de hacks / modificaciones de hardware.
Hay problemas con todos los enfoques anteriores. En Google i / o, Reto Meier lanzó una respuesta sólida sobre cómo abordar esto, que debería satisfacer las necesidades de la mayoría de los desarrolladores de rastrear usuarios en todas las instalaciones.
Este enfoque le brindará una identificación de usuario segura y anónima que será persistente para el usuario en diferentes dispositivos (incluidas las tabletas, según la cuenta principal de Google) y en todas las instalaciones en el mismo dispositivo. El enfoque básico es generar una identificación de usuario aleatoria y almacenarla en las preferencias compartidas de las aplicaciones. Luego, usa el agente de respaldo de Google para almacenar las preferencias compartidas vinculadas a la cuenta de Google en la nube.
Repasemos el enfoque completo. Primero necesitamos crear una copia de seguridad para nuestras SharedPreferences usando el servicio de copia de seguridad de Android. Comience registrando su aplicación a través de este enlace: http://developer.android.com/google/backup/signup.html
Google le dará una clave de servicio de respaldo que debe agregar al manifiesto. También debe indicarle a la aplicación que use BackupAgent de la siguiente manera:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
Luego, debe crear el agente de respaldo y decirle que use el agente auxiliar para las preferencias compartidas:
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);
}
}
Para completar la copia de seguridad, debe crear una instancia de BackupManager en su actividad principal:
BackupManager backupManager = new BackupManager(context);
Finalmente, cree una ID de usuario, si aún no existe, y guárdela en 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;
}
Este User_ID ahora será persistente en todas las instalaciones, incluso si el usuario cambia de dispositivo.
Para obtener más información sobre este enfoque, consulte la charla de Reto aquí. http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
Y para obtener detalles completos sobre cómo implementar el agente de respaldo, consulte el sitio para desarrolladores aquí: http://developer.android.com/guide/topics/data/backup.html Recomiendo particularmente la sección en la parte inferior sobre pruebas como lo hace el respaldo no suceda instantáneamente y, por lo tanto, para probar debe forzar la copia de seguridad.
Otra forma es usar / sys / class / android_usb / android0 / iSerial en una aplicación sin ningún permiso.
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
Para hacer esto en Java, uno solo usaría un FileInputStream para abrir el archivo iSerial y leer los caracteres. Solo asegúrese de envolverlo en un controlador de excepciones porque no todos los dispositivos tienen este archivo.
Se sabe que al menos los siguientes dispositivos tienen este archivo legible en todo el mundo:
También puede ver la publicación de mi blog aquí: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html donde analizo qué otros archivos están disponibles para obtener información.
Como dice @haserman:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
Pero es necesario incluir el permiso en el archivo de manifiesto:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
ID de dispositivo único del dispositivo con sistema operativo Android como cadena.
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);
}
pero recomiendo encarecidamente este método sugerido por Google:
Build.SERIAL
es la forma más sencilla de hacerlo, aunque no es del todo confiable, ya que puede estar vacío o, a veces, devolver un valor diferente ( prueba 1 , prueba 2 ) del que puede ver en la configuración de su dispositivo.
Hay varias formas de obtener ese número según el fabricante del dispositivo y la versión de Android, así que decidí compilar todas las soluciones posibles que pude encontrar en una sola esencia . Aquí hay una versión simplificada:
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;
}
Sé que esta pregunta es antigua, pero se puede hacer en una línea de código.
String deviceID = Build.SERIAL;
Encontré que la clase de ejemplo publicada por @emmby arriba es un excelente punto de partida. Pero tiene un par de defectos, como lo mencionan otros carteles. El principal es que persiste el UUID en un archivo XML innecesariamente y, a partir de entonces, siempre lo recupera de este archivo. Esto abre la clase a un truco fácil: cualquier persona con un teléfono rooteado puede editar el archivo XML para obtener un nuevo UUID.
Actualicé el código para que solo persista en XML si es absolutamente necesario (es decir, cuando se usa un UUID generado aleatoriamente) y modifiqué la lógica según la respuesta de @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;
}
Si. Es un número de serie de hardware del dispositivo y es único. Entonces, en el nivel de API 2.3 y superior, puede usar android.os.Build.ANDROID_ID para obtenerlo. Para niveles de API inferiores a 2.3, utilice TelephonyManager.getDeviceID () .
puede leer esto http://android-developers.blogspot.in/2011/03/identifying-app-installations.html