Preciso usar um ID exclusivo para um aplicativo Android e achei que o número de série do dispositivo seria um bom candidato. Como faço para recuperar o número de série de um dispositivo Android em meu aplicativo?
Preciso usar um ID exclusivo para um aplicativo Android e achei que o número de série do dispositivo seria um bom candidato. Como faço para recuperar o número de série de um dispositivo Android em meu aplicativo?
Respostas:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getSystemService é um método da classe Activity. getDeviceID () retornará o MDN ou MEID do dispositivo dependendo de qual rádio o telefone usa (GSM ou CDMA).
Cada dispositivo DEVE retornar um valor exclusivo aqui (presumindo que seja um telefone). Isso deve funcionar para qualquer dispositivo Android com um slot SIM ou rádio CDMA. Você está sozinho com aquele micro-ondas com Android ;-)
Como Dave Webb menciona, o Android Developer Blog tem um artigo que cobre isso.
Falei com alguém do Google para obter alguns esclarecimentos adicionais sobre alguns itens. Aqui está o que descobri que NÃO é mencionado na postagem do blog mencionada:
Com base nas recomendações do Google, implementei uma classe que irá gerar um UUID exclusivo para cada dispositivo, usando ANDROID_ID como a semente quando apropriado, recorrendo a TelephonyManager.getDeviceId () conforme necessário e, se isso falhar, recorrendo a um UUID exclusivo gerado aleatoriamente que persiste nas reinicializações do aplicativo (mas não nas reinstalações do aplicativo).
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 retorna o número de série do dispositivo usando uma API Android oculta.
String deviceId = Settings.System.getString(getContentResolver(),
Settings.System.ANDROID_ID);
Porém, não é garantido que o Android ID seja um identificador exclusivo.
getContentResolver
está voltando null
. No entanto, pode valer a pena abrir uma pergunta e postar seu código.
Há uma excelente postagem no blog do desenvolvedor Android discutindo isso .
Ele não recomenda o uso TelephonyManager.getDeviceId()
, pois não funciona em dispositivos Android que não sejam telefones, como tablets, requer oREAD_PHONE_STATE
permissão e não funciona de forma confiável em todos os telefones.
Em vez disso, você pode usar um dos seguintes:
A postagem discute os prós e os contras de cada um e vale a pena ler para que você possa descobrir qual é o melhor para seu uso.
Para obter um número simples que é exclusivo para o dispositivo e constante por toda a sua vida (exceto uma redefinição de fábrica ou invasão), use Settings.Secure.ANDROID_ID .
String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
Para usar o número de série do dispositivo (aquele mostrado em "Configurações do sistema / Sobre / Status"), se disponível, e retornar ao ID do Android:
String serialNumber = Build.SERIAL != Build.UNKNOWN ? Build.SERIAL : Secure.getString(getContentResolver(), Secure.ANDROID_ID);
O IMEI é bom, mas só funciona em aparelhos Android com telefone. Você deve considerar o suporte para tablets ou outros dispositivos Android também, que não possuem um telefone.
Você tem algumas alternativas, como: Construir membros da classe, BT MAC, WLAN MAC ou ainda melhor - uma combinação de todas essas.
Expliquei esses detalhes em um artigo no meu blog, consulte: http://www.pocketmagic.net/?p=1662
Uma vez que nenhuma resposta aqui menciona um ID perfeito e à prova de falhas que é PERSISTENTE por meio de atualizações do sistema e existe em TODOS os dispositivos (principalmente devido ao fato de que não há uma solução individual do Google), decidi postar um método que seja a próxima melhor coisa é combinar dois dos identificadores disponíveis e uma verificação para escolher entre eles em tempo de execução.
Antes do código, 3 fatos:
TelephonyManager.getDeviceId()
(akaIMEI) não funcionará bem ou de forma alguma para dispositivos não GSM, 3G, LTE, etc., mas sempre retornará um ID exclusivo quando o hardware relacionado estiver presente , mesmo quando nenhum SIM for inserido ou mesmo quando não houver slot de SIM ( alguns OEMs já fizeram isso).
Já o Gingerbread (Android 2.3) android.os.Build.SERIAL
deve existir em qualquer dispositivo que não forneça IMEI , ou seja, não tenha o referido hardware presente, conforme política do Android.
Devido ao fato (2.), pelo menos um desses dois identificadores exclusivos SEMPRE estará presente , e SERIAL pode estar presente ao mesmo tempo que o IMEI.
Observação: os fatos (1.) e (2.) são baseados nas declarações do Google
SOLUÇÃO
Com os fatos acima, sempre se pode ter um identificador único verificando se há hardware vinculado ao IMEI e voltar para SERIAL quando não houver, pois não se pode verificar se o SERIAL existente é válido. A seguinte classe estática apresenta 2 métodos para verificar tal presença e usando IMEI ou 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;
}
}
Eu aconselharia sobre como usar getCleartextID_HARDCHECK
. Se o reflexo não aderir ao seu ambiente, use o getCleartextID_SIMCHECK
método, mas leve em consideração que ele deve ser adaptado às suas necessidades específicas de presença do SIM.
PS : Observe que os OEMs conseguiram bugar SERIAL contra a política do Google (vários dispositivos com o mesmo SERIAL) e o Google, conforme declarado, há pelo menos um caso conhecido em um grande OEM (não divulgado e não sei qual marca ou é, suponho Samsung).
Isenção de responsabilidade : Isso responde à questão original de obter um ID de dispositivo exclusivo, mas o OP introduziu ambigüidade ao declarar que ele precisa de um ID exclusivo para um APP. Mesmo que para tais cenários o Android_ID fosse melhor, NÃO FUNCIONARÁ após, digamos, um Backup Titanium de um aplicativo por meio de 2 instalações de ROM diferentes (pode até ser a mesma ROM). Minha solução mantém a persistência que é independente de um flash ou reset de fábrica e só falhará quando ocorrer violação de IMEI ou SERIAL por meio de hacks / mods de hardware.
Existem problemas com todas as abordagens acima. No Google i / o, Reto Meier lançou uma resposta robusta sobre como abordar isso, o que deve atender às necessidades da maioria dos desenvolvedores de rastrear os usuários nas instalações.
Essa abordagem fornecerá a você um ID de usuário anônimo e seguro que será persistente para o usuário em diferentes dispositivos (incluindo tablets, com base na conta principal do Google) e em instalações no mesmo dispositivo. A abordagem básica é gerar um ID de usuário aleatório e armazená-lo nas preferências compartilhadas do aplicativo. Em seguida, você usa o agente de backup do Google para armazenar as preferências compartilhadas vinculadas à conta do Google na nuvem.
Vamos examinar a abordagem completa. Primeiro, precisamos criar um backup para nossas Preferências Compartilhadas usando o Android Backup Service. Comece registrando seu aplicativo por meio deste link: http://developer.android.com/google/backup/signup.html
O Google fornecerá a você uma chave de serviço de backup que você precisa adicionar ao manifesto. Você também precisa dizer ao aplicativo para usar o BackupAgent da seguinte maneira:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="your_backup_service_key" />
</application>
Em seguida, você precisa criar o agente de backup e dizer a ele para usar o agente auxiliar para preferências compartilhadas:
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 concluir o backup, você precisa criar uma instância do BackupManager em sua atividade principal:
BackupManager backupManager = new BackupManager(context);
Por fim, crie um ID de usuário, se ainda não existir, e armazene-o em 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 agora será persistente nas instalações, mesmo se o usuário trocar de dispositivo.
Para obter mais informações sobre essa abordagem, consulte a palestra de Reto aqui http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
E para obter todos os detalhes de como implementar o agente de backup, consulte o site do desenvolvedor aqui: http://developer.android.com/guide/topics/data/backup.html Eu recomendo particularmente a seção na parte inferior sobre testes como o backup faz não acontece instantaneamente e para testar você tem que forçar o backup.
Outra forma é usar / sys / class / android_usb / android0 / iSerial em um aplicativo sem nenhuma permissão.
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 fazer isso em java, basta usar um FileInputStream para abrir o arquivo iSerial e ler os caracteres. Apenas certifique-se de envolvê-lo em um manipulador de exceções, pois nem todos os dispositivos possuem esse arquivo.
Sabe-se que pelo menos os seguintes dispositivos têm este arquivo legível por todos:
Você também pode ver minha postagem do blog aqui: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html onde discuto quais outros arquivos estão disponíveis para informações.
Como @haserman diz:
TelephonyManager tManager = (TelephonyManager)myActivity.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
Mas é necessário incluir a permissão no arquivo de manifesto:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
ID de dispositivo exclusivo do dispositivo Android OS como string.
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);
}
mas eu recomendo fortemente este método sugerido pelo Google:
Build.SERIAL
é a maneira mais simples de fazer, embora não totalmente confiável, pois pode estar vazio ou às vezes retornar um valor diferente ( prova 1 , prova 2 ) do que você pode ver nas configurações do seu dispositivo.
Existem várias maneiras de obter esse número, dependendo do fabricante do dispositivo e da versão do Android, então decidi compilar todas as soluções possíveis que encontrei em uma única essência . Aqui está uma versão simplificada dele:
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;
}
Eu sei que esta pergunta é antiga, mas pode ser feita em uma linha de código
String deviceID = Build.SERIAL;
Achei a aula de exemplo postada por @emmby acima um ótimo ponto de partida. Mas tem algumas falhas, conforme mencionado por outros pôsteres. O principal é que ele persiste o UUID em um arquivo XML desnecessariamente e, a partir daí, sempre o recupera desse arquivo. Isso abre a classe para um hack fácil: qualquer pessoa com um telefone enraizado pode editar o arquivo XML para obter um novo UUID.
Eu atualizei o código para que ele persista em XML apenas se for absolutamente necessário (ou seja, ao usar um UUID gerado aleatoriamente) e refatorei a lógica de acordo com a resposta 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;
}
Sim. É um número de série do hardware do dispositivo e é único. Portanto, na API de nível 2.3 e acima, você pode usar android.os.Build.ANDROID_ID para obtê-lo. Para o nível de API abaixo de 2.3, use TelephonyManager.getDeviceID () .
você pode ler isto http://android-developers.blogspot.in/2011/03/identifying-app-installations.html