Como encontrar o número de série do dispositivo Android?


115

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?


2
Não se esqueça de adicionar android: name = "android.permission.READ_PHONE_STATE" ao seu manifesto
Michael SIlveus


Se quiser obter um ID exclusivo sem nenhuma permissão, você pode usar esta biblioteca para gerar um ID exclusivo por dispositivo com Identity.getDeviceId (contexto) ou um identificador para a instalação do seu aplicativo via Identity.getInstallationId (contexto) .
caw

Respostas:


105
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 ;-)


@Hasemam Isso não está funcionando para mim, apresentando o erro "Forçar fechamento"
Paresh Mayani

23
@Hasemam está funcionando bem agora após adicionar a permissão <uses-permission android: name = "android.permission.READ_PHONE_STATE"> </uses-permission> no arquivo androidManifest.xml.
Paresh Mayani de

23
Há alguns conselhos no blog do desenvolvedor Android oficial sobre como usar este identificador: android-developers.blogspot.com/2011/03/...
David Snabel-Caunt

8
além do microondas com Android, que tal um Tablet com Android? :)
ajacian81

21
Este método deve ser evitado, ele funcionará em telefones, mas não funcionará em dispositivos sem um chip de telefone (tablets são um exemplo). A partir de 2.3, você pode usar android.os.Build.SERIAL, mas verifique o blog do desenvolvedor que @DavidCaunt sugeriu.
John Mitchell

71

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:

  • ANDROID_ID é a solução preferida. ANDROID_ID é perfeitamente confiável nas versões do Android <= 2.1 ou> = 2.3. Apenas 2.2 tem os problemas mencionados no post.
  • Vários dispositivos de diversos fabricantes são afetados pelo bug ANDROID_ID no 2.2.
  • Pelo que pude determinar, todos os dispositivos afetados têm o mesmo ANDROID_ID , que é 9774d56d682e549c . Que também é o mesmo id de dispositivo relatado pelo emulador, btw.
  • O Google acredita que os OEMs corrigiram o problema para muitos ou a maioria de seus dispositivos, mas pude verificar que desde o início de abril de 2011, pelo menos, ainda é muito fácil encontrar dispositivos com o ANDROID_ID quebrado.

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;
    }
}

1
Quais permissões são necessárias para um aplicativo usar isso?
Dave L.

1
<uses-permission android: name = "android.permission.READ_PHONE_STATE"> </uses-permission>
Gabrielle

1
@ ef2011 é o padrão de bloqueio verificado duas vezes: en.wikipedia.org/wiki/Double-checked_locking
emmby

3
Obrigado por publicar. Mas o que impede alguém com um telefone enraizado de simplesmente editar device_id.xml para inserir um novo UUID de sua escolha? (ou seja, para contornar uma verificação de 'avaliação gratuita') Não seria melhor se a classe apenas armazenasse o valor em um arquivo de preferência se tivesse que recorrer ao método de ID aleatório? Caso contrário, não há necessidade de persistir entre as execuções do aplicativo; é mais seguro gerar novamente.
Carlos P

1
"ANDROID_ID" é a solução preferida ". Observe que ANDROID_ID não identifica mais um dispositivo de maneira exclusiva: stackoverflow.com/a/13465373/150016
Tom

32
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.


7
isso me dá o mesmo valor que recebo com android.os.Build.SERIAL
josephus,

Estou enganado ou este número de série é o mesmo em todos os dispositivos com uma rom personalizada específica? O número de série do meu dispositivo (no inicializador de dispositivo eclipse) mostra 01234567890ABC para um telefone com uma rom personalizada.
Peterdk

@Peterdk no meu dispositivo com cianogênio-9 ambos os métodos (pré-andy-9 como na resposta e o mais fácil disponível a partir de andy-9) relatam s / n correto (o mesmo que no adesivo do fabricante). No entanto, pode depender de uma versão específica da ROM personalizada. Qual rom / versão você está usando?
morgwai

16
String deviceId = Settings.System.getString(getContentResolver(),
                                Settings.System.ANDROID_ID);

Porém, não é garantido que o Android ID seja um identificador exclusivo.


@Paresh Mayani, É difícil dizer qual pode ser o problema sem olhar para o código. Minha única suposição é que getContentResolverestá voltando null. No entanto, pode valer a pena abrir uma pergunta e postar seu código.
Anthony Forloney

4
Este ID vem da conta Google associada ao telefone. O simulador normalmente não possui um. Um telefone de verdade também pode não ter um. Além disso, está documentado como "pode ​​ser alterado na redefinição de fábrica" ​​e pode ser alterado arbitrariamente a qualquer momento em um telefone com acesso root. Use por sua conta e risco. Não há boa alternativa - outros IDs de dispositivo provisórios ou não estão universalmente disponíveis, ou não são exclusivos, ou ambos. Veja outras respostas para o resto desta triste história.
Seva Alekseyev

14

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:

  • Endereço MAC
  • Número de série
  • ANDROID_ID

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.


+1, oi dave, obrigado pelo esclarecimento porque neste momento estou desenvolvendo um aplicativo para tablet, onde preciso ter o ID exclusivo do dispositivo Android, então o que devo usar para obter o dispositivo Android exclusivo?
Paresh Mayani

12

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);

resposta direta !!
faris faris

Build.SERİAL obsoleto em java
Eyyüp Alkış

7

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


6

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:

  1. 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).

  2. 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.

  3. 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_SIMCHECKmé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.


5

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.


2

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:

  • Galaxy Nexus
  • Nexus S
  • Motorola Xoom 3g
  • Toshiba AT300
  • HTC One V
  • Mini MK802
  • Samsung Galaxy S II

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.


Obrigado por postar sua resposta! Por favor, certifique-se de ler o FAQ sobre autopromoção com atenção. Observe também que é necessário que você publique um aviso de isenção de responsabilidade sempre que criar um link para seu próprio site / produto.
Andrew Barber

1

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"/>

1

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:

Identificação de instalações de aplicativos


1

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;
}

0

Eu sei que esta pergunta é antiga, mas pode ser feita em uma linha de código

String deviceID = Build.SERIAL;


AFAIK, isso mudará após a atualização do sistema operacional do dispositivo, por exemplo, de 4.4.2 para 4.4.4 ou qualquer outro.
Den Drobiazko

-1

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;
    }

Colocar o id em preferências compartilhadas compromete o objetivo original de obter um id realmente único. Por exemplo, se você quiser usar esse id como chave para algumas restrições, ficará ferrado quando usuários habilidosos fizerem root em um dispositivo e obtiverem acesso ao seu arquivo de preferências compartilhado. Seu conteúdo pode ser copiado, o que significa ...
Eugene Wechsler

há também um outro erro na resposta do MB e na sua .. Se você usar randomUUID como um deviceID e appID, ele funciona para todos os dispositivos em todo o boord, independentemente de serem telefones ou não ou se forem dispositivos google exp ou não.
Fred Grott

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.