unico Existe um ID de dispositivo Android exclusivo?




uuid android (24)

O ID de dispositivo único de um dispositivo Android OS como String, usando TelephonyManagere ANDROID_ID, é obtido por:

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 um método sugerido pelo Google, consulte Identificando instalações de aplicativos .

Os dispositivos Android têm um ID único e, em caso afirmativo, qual é uma maneira simples de acessá-lo usando Java?


Última atualização: 6/2/15

Depois de ler todas as postagens do sobre como criar uma ID exclusiva, o blog de desenvolvedores do Google e a documentação do Android, sinto como se a "Pseudo ID" fosse a melhor opção possível.

Problema principal: hardware vs software

Hardware

  • Os usuários podem alterar seu hardware, tablet ou telefone Android, de modo que IDs únicos baseados em hardware não são boas ideias para rastrear usuários
  • Para o TRACKING HARDWARE , essa é uma ótima ideia

Programas

  • Os usuários podem limpar / alterar sua ROM se estiverem enraizados
  • Você pode rastrear usuários em várias plataformas (iOS, Android, Windows e Web)
  • A melhor maneira de rastrear um usuário individual com o consentimento deles é simplesmente fazer com que eles efetuem login (faça isso sem problemas usando o OAuth)

Resumo geral com o Android

- Garantir exclusividade (incluir dispositivos com raiz) para API> = 9/10 (99,5% dos dispositivos Android)

- Nenhuma permissão extra

Código Psuedo:

if API >= 9/10: (99.5% of devices)

return unique ID containing serial id (rooted devices may be different)

else

return unique ID of build information (may overlap data - API < 9)

Obrigado ao @stansult por postar todas as nossas opções (nesta pergunta do ).

Lista de opções - razões porque / porque não usá-las:

  • E-mail do usuário - Software

    • O usuário pode alterar o e-mail - ALTAMENTE improvável
    • API 5+ <uses-permission android:name="android.permission.GET_ACCOUNTS" /> ou
    • API 14+ <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> ( Como obter o endereço de e-mail principal do dispositivo Android )
  • Número de telefone do usuário - Software

    • Os usuários podem alterar números de telefone - ALTAMENTE improvável
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • IMEI - Hardware (apenas telefones, precisa de android.permission.READ_PHONE_STATE )

    • A maioria dos usuários odeia o fato de que diz "Telefonemas" na permissão. Alguns usuários dão classificações ruins, porque acreditam que você está simplesmente roubando suas informações pessoais, quando tudo o que você realmente quer fazer é acompanhar as instalações dos dispositivos. É óbvio que você está coletando dados.
    • <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  • ID do Android - Hardware (pode ser nulo, pode ser alterado após a redefinição de fábrica, pode ser alterado em um dispositivo com raiz)

    • Como pode ser "nulo", podemos verificar "nulo" e alterar seu valor, mas isso significa que ele não será mais exclusivo.
    • Se você tiver um usuário com um dispositivo de redefinição de fábrica, o valor poderá ter sido alterado ou alterado no dispositivo raiz, para que possa haver entradas duplicadas se você estiver controlando as instalações do usuário.
  • Endereço MAC WLAN - Hardware (precisa android.permission.ACCESS_WIFI_STATE )

    • Essa pode ser a segunda melhor opção, mas você ainda está coletando e armazenando um identificador exclusivo que vem diretamente de um usuário. Isso é óbvio que você está coletando dados.
    • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
  • Endereço MAC Bluetooth - Hardware (dispositivos com Bluetooth, precisa de android.permission.BLUETOOTH )

    • A maioria dos aplicativos no mercado não usa Bluetooth e, portanto, se seu aplicativo não usa Bluetooth e você o inclui, o usuário pode ficar desconfiado.
    • <uses-permission android:name="android.permission.BLUETOOTH "/>
  • Pseudo-Unique ID - Software (para todos os dispositivos Android)

    • Muito possível, pode conter colisões - Veja meu método postado abaixo!
    • Isso permite que você tenha um ID "quase exclusivo" do usuário sem levar nada que seja privado. Você pode criar seu próprio ID anônimo a partir das informações do dispositivo.

Eu sei que não há nenhuma maneira 'perfeita' de obter um ID único sem usar permissões; No entanto, às vezes, precisamos apenas rastrear a instalação do dispositivo. Quando se trata de criar um ID único, podemos criar um 'pseudo id único' baseado apenas em informações que a API do Android nos fornece sem usar permissões extras. Dessa forma, podemos mostrar o respeito do usuário e tentar oferecer uma boa experiência ao usuário também.

Com um ID pseudo-exclusivo, você realmente só se depara com o fato de que pode haver duplicatas com base no fato de que existem dispositivos semelhantes. Você pode ajustar o método combinado para torná-lo mais exclusivo; no entanto, alguns desenvolvedores precisam rastrear instalações de dispositivos e isso fará o truque ou o desempenho com base em dispositivos semelhantes.

API> = 9:

Se o dispositivo Android deles for a API 9 ou superior, isso é garantido como único devido ao campo "Build.SERIAL".

LEMBRE-SE , tecnicamente, você está perdendo apenas cerca de 0,5% dos usuários com API <9 . Então você pode se concentrar no resto: Isso é 99,5% dos usuários!

API <9:

Se o dispositivo Android do usuário for menor que a API 9; esperançosamente, eles não fizeram um reset de fábrica e seu 'Secure.ANDROID_ID' será preservado ou não 'null'. (veja http://developer.android.com/about/dashboards/index.html )

Se todo o resto falhar:

Se tudo mais falhar, se o usuário tiver menos que a API 9 (menor que Gingerbread), tiver redefinido o dispositivo ou 'Secure.ANDROID_ID' retornar 'null', simplesmente o ID retornado será baseado apenas nas informações do dispositivo Android. É aqui que as colisões podem acontecer.

Alterar:

  • Removido 'Android.SECURE_ID' por causa das redefinições de fábrica pode fazer com que o valor mude
  • Editou o código para alterar na API
  • Mudou o pseudo

Por favor, dê uma olhada no método abaixo:

/**
 * Return pseudo unique ID
 * @return ID
 */
public static String getUniquePsuedoID() {
    // If all else fails, if the user does have lower than API 9 (lower
    // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
    // returns 'null', then simply the ID returned will be solely based
    // off their Android device information. This is where the collisions
    // can happen.
    // Thanks http://www.pocketmagic.net/?p=1662!
    // Try not to use DISPLAY, HOST or ID - these items could change.
    // If there are collisions, there will be overlapping data
    String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);

    // Thanks to @Roman SL!
    // https://.com/a/4789483/950427
    // Only devices with API >= 9 have android.os.Build.SERIAL
    // http://developer.android.com/reference/android/os/Build.html#SERIAL
    // If a user upgrades software or roots their device, there will be a duplicate entry
    String serial = null;
    try {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();

        // Go ahead and return the serial for api => 9
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        // String needs to be initialized
        serial = "serial"; // some value
    }

    // Thanks @Joe!
    // https://.com/a/2853253/950427
    // Finally, combine the values we have found by using the UUID class to create a unique identifier
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

Novo (para aplicativos com anúncios e serviços do Google Play):

No console do desenvolvedor do Google Play:

A partir de 1º de agosto de 2014, a Política do programa para desenvolvedores do Google Play exigirá que todos os novos uploads e atualizações de aplicativos usem o código de publicidade em vez de outros identificadores persistentes para fins publicitários. Saber mais

Implementação :

Permissão:

<uses-permission android:name="android.permission.INTERNET" />

Código:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...

// Do not call this function from the main thread. Otherwise, 
// an IllegalStateException will be thrown.
public void getIdThread() {

  Info adInfo = null;
  try {
    adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);

  } catch (IOException exception) {
    // Unrecoverable error connecting to Google Play services (e.g.,
    // the old version of the service doesn't support getting AdvertisingId).

  } catch (GooglePlayServicesAvailabilityException exception) {
    // Encountered a recoverable error connecting to Google Play services. 

  } catch (GooglePlayServicesNotAvailableException exception) {
    // Google Play services is not available entirely.
  }
  final String id = adInfo.getId();
  final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

Fonte / Docs:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

Importante:

Pretende-se que o ID de publicidade substitua completamente o uso existente de outros identificadores para fins de anúncios (como o uso de ANDROID_ID em Settings.Secure) quando o Google Play Services estiver disponível. Os casos em que o Google Play Services não está disponível são indicados por um GooglePlayServicesNotAvailableException lançado por getAdvertisingIdInfo ().

Atenção, os usuários podem redefinir:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

Tentei fazer referência a todos os links dos quais tirei informações. Se você está faltando e precisa ser incluído, por favor, comente!

InstanceID dos serviços do Google Player

https://developers.google.com/instance-id/


ID da instância do Google

Lançado na I / O 2015; no Android requer serviços de reprodução 7.5.

https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation

InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
String id = iid.getId();  // blocking call

Parece que o Google pretende que esse código seja usado para identificar instalações no Android, no Chrome e no iOS.

Ele identifica uma instalação em vez de um dispositivo, mas, novamente, ANDROID_ID (que é a resposta aceita) agora não identifica mais os dispositivos. Com o tempo de execução do ARC, um novo ANDROID_ID é gerado para cada instalação ( detalhes aqui ), assim como este novo ID de instância. Além disso, acho que identificar instalações (não dispositivos) é o que a maioria de nós está realmente procurando.

As vantagens do ID da instância

Parece-me que o Google pretende que ele seja usado para essa finalidade (identificando suas instalações), ele é de plataforma cruzada e pode ser usado para várias outras finalidades (consulte os links acima).

Se você usa o GCM, eventualmente precisará usar esse ID da instância porque precisa dele para obter o token do GCM (que substitui o antigo ID de registro do GCM).

As desvantagens / problemas

Na implementação atual (GPS 7.5), o ID da instância é recuperado de um servidor quando seu aplicativo o solicita. Isso significa que a chamada acima é uma chamada de bloqueio - no meu teste não científico leva de 1 a 3 segundos se o dispositivo estiver on-line e de 0,5 a 1,0 segundo se estiver off-line (presumivelmente, quanto tempo ele aguarda antes de desistir e gerar um ID aleatório). Isso foi testado na América do Norte no Nexus 5 com Android 5.1.1 e GPS 7.5.

Se você usar o ID para os fins que eles pretendem - por exemplo. autenticação de aplicativos, identificação de aplicativos, GCM - acho que esses 1-3 segundos podem ser um incômodo (dependendo do aplicativo, é claro).


Como Dave Webb menciona, o Android Developer Blog tem um artigo que aborda isso. Sua solução preferida é acompanhar as instalações de aplicativos em vez de dispositivos, e isso funcionará bem para a maioria dos casos de uso. A postagem do blog mostrará o código necessário para que isso funcione e eu recomendo que você verifique isso.

No entanto, o post do blog continua discutindo soluções se você precisar de um identificador de dispositivo em vez de um identificador de instalação de aplicativo. Falei com alguém no Google para obter esclarecimentos adicionais sobre alguns itens, caso você precise fazer isso. Aqui está o que eu descobri sobre identificadores de dispositivos que NÃO são mencionados na postagem do blog acima mencionada:

  • ANDROID_ID é o identificador de dispositivo preferido. ANDROID_ID é perfeitamente confiável em versões do Android <= 2.1 ou> = 2.3. Apenas 2,2 tem os problemas mencionados no post.
  • Vários dispositivos de vários fabricantes são afetados pelo bug ANDROID_ID no 2.2.
  • Até onde eu consegui determinar, todos os dispositivos afetados possuem o mesmo ANDROID_ID , que é 9774d56d682e549c . Qual é também o mesmo id do dispositivo relatado pelo emulador, btw.
  • O Google acredita que os OEMs corrigiram o problema em muitos ou muitos de seus dispositivos, mas pude verificar que, pelo menos até o início de abril de 2011, ainda é muito fácil encontrar dispositivos que tenham o ANDROID_ID quebrado.

Com base nas recomendações do Google, implementei uma classe que gerará um UUID exclusivo para cada dispositivo, usando ANDROID_ID como a semente, quando apropriado, recorrendo ao TelephonyManager.getDeviceId () conforme necessário e, se isso falhar, recorrendo a um UUID exclusivo gerado aleatoriamente que é persistente nas reinicializações de aplicativos (mas não nas reinstalações de aplicativos).

Observe que, para dispositivos que precisam fazer fallback no ID do dispositivo, o ID exclusivo persistirá nas redefinições de fábrica. Isso é algo para estar ciente. Se você precisar garantir que uma redefinição de fábrica redefina sua ID exclusiva, convém considerar voltar diretamente ao UUID aleatório em vez da ID do dispositivo.

Novamente, esse código é para um ID de dispositivo, não um ID de instalação de aplicativo. Para a maioria das situações, um ID de instalação do aplicativo é provavelmente o que você está procurando. Mas se você precisar de um ID de dispositivo, o código a seguir provavelmente funcionará para você.

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 volatile 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)) {
                                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;
    }
}

Eu acho que isso é certo maneira fogo de construir um esqueleto para uma identificação única ... confira.

ID pseudo-exclusivo, que funciona em todos os dispositivos Android Alguns dispositivos não têm um telefone (por exemplo, Tablets) ou, por algum motivo, você não deseja incluir a permissão READ_PHONE_STATE. Você ainda pode ler detalhes como Versão da ROM, Nome do fabricante, Tipo de CPU e outros detalhes de hardware, que serão bem adequados se você quiser usar a ID para uma verificação de chave serial ou outras finalidades gerais. O ID computado dessa maneira não será exclusivo: é possível encontrar dois dispositivos com o mesmo ID (com base no mesmo hardware e na imagem da ROM), mas as alterações em aplicativos reais são insignificantes. Para este propósito, você pode usar a classe Build:

String m_szDevIDShort = "35" + //we make this look like a valid IMEI
            Build.BOARD.length()%10+ Build.BRAND.length()%10 +
            Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
            Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
            Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
            Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
            Build.TAGS.length()%10 + Build.TYPE.length()%10 +
            Build.USER.length()%10 ; //13 digits

A maioria dos membros do Build são strings, o que estamos fazendo aqui é pegar o tamanho e transformá-lo via módulo em um dígito. Temos 13 desses dígitos e estamos adicionando mais dois na frente (35) para ter a mesma identificação de tamanho que o IMEI (15 dígitos). Há outras possibilidades aqui estão bem, basta dar uma olhada nessas seqüências. Retorna algo parecido 355715565309247. Nenhuma permissão especial é necessária, tornando essa abordagem muito conveniente.

(Informação extra: A técnica acima foi copiada de um artigo no here .)


Para obter instruções detalhadas sobre como obter um identificador exclusivo para cada dispositivo Android do qual o seu aplicativo está instalado, consulte a publicação oficial do Android Developers Blog android-developers.blogspot.com/2011/03/… .

Parece que a melhor maneira é você mesmo gerar uma após a instalação e, posteriormente, lê-la quando o aplicativo é relançado.

Eu pessoalmente acho isso aceitável, mas não ideal. Nenhum identificador fornecido pelo Android funciona em todas as instâncias, pois a maioria depende dos estados de rádio do telefone (ativação / desativação de Wi-Fi, ativação / desativação de celular, ativação / desativação de Bluetooth). Os outros, como Settings.Secure.ANDROID_IDdevem ser implementados pelo fabricante e não são garantidos para ser exclusivo.

A seguir, um exemplo de gravação de dados em um arquivo de instalação que seria armazenado junto com quaisquer outros dados que o aplicativo salva localmente.

public class Installation {
    private static String sID = null;
    private static final String INSTALLATION = "INSTALLATION";

    public synchronized static String id(Context context) {
        if (sID == null) {
            File installation = new File(context.getFilesDir(), INSTALLATION);
            try {
                if (!installation.exists())
                    writeInstallationFile(installation);
                sID = readInstallationFile(installation);
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return sID;
    }

    private static String readInstallationFile(File installation) throws IOException {
        RandomAccessFile f = new RandomAccessFile(installation, "r");
        byte[] bytes = new byte[(int) f.length()];
        f.readFully(bytes);
        f.close();
        return new String(bytes);
    }

    private static void writeInstallationFile(File installation) throws IOException {
        FileOutputStream out = new FileOutputStream(installation);
        String id = UUID.randomUUID().toString();
        out.write(id.getBytes());
        out.close();
    }
}

Há informações bastante úteis here .

Abrange cinco tipos diferentes de identificação:

  1. IMEI (somente para dispositivos Android com uso do telefone; precisa de android.permission.READ_PHONE_STATE )
  2. ID pseudo-exclusiva (para todos os dispositivos Android)
  3. ID do Android (pode ser nulo, pode ser alterado após a redefinição de fábrica, pode ser alterado no telefone com root)
  4. Cadeia de endereços MAC WLAN (precisa de android.permission.ACCESS_WIFI_STATE )
  5. String de endereço MAC BT (dispositivos com Bluetooth, precisa android.permission.BLUETOOTH )

O Google agora tem um código de publicidade .
Isso também pode ser usado, mas observe que:

O código de publicidade é um ID exclusivo, exclusivo e reajustável do usuário

e

permite que os usuários redefinam o identificador ou desativem anúncios com base em interesses nos aplicativos do Google Play.

Portanto, embora esse id possa mudar, parece que em breve podemos não ter escolha , depende do propósito desse id.

http://developer.android.com/google/play-services/id.html

Copie e cole o código aqui

HTH


Mais especificamente Settings.Secure.ANDROID_ID,. Essa é uma quantidade de 64 bits gerada e armazenada quando o dispositivo é inicializado pela primeira vez. É redefinido quando o dispositivo é limpo.

ANDROID_IDparece uma boa escolha para um identificador de dispositivo único. Existem desvantagens: primeiro, ele não é 100% confiável em lançamentos do Android anteriores ao 2.2. (“Froyo”).Além disso, houve pelo menos um bug amplamente observado em um celular popular de um grande fabricante, onde cada instância tem o mesmo ANDROID_ID.


TelephonyManger.getDeviceId () Retorna o ID exclusivo do dispositivo, por exemplo, o IMEI para GSM e o MEID ou ESN para telefones CDMA.

final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
String myAndroidDeviceId = mTelephony.getDeviceId(); 

Mas eu recomendo usar:

Settings.Secure.ANDROID_ID que retorna o Android ID como uma string hexadecimal exclusiva de 64 bits.

    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

Às vezes, TelephonyManger.getDeviceId () retornará null, portanto, para assegurar um ID único, você utilizará este método:

public String getUniqueID(){    
    String myAndroidDeviceId = "";
    TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    if (mTelephony.getDeviceId() != null){
        myAndroidDeviceId = mTelephony.getDeviceId(); 
    }else{
         myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
    }
    return myAndroidDeviceId;
}

Uma coisa eu adicionarei - eu tenho uma dessas situações únicas.

Usando:

deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);

Acontece que, embora meu Viewsonic G Tablet relate um DeviceID que não seja Null, cada G Tablet informa o mesmo número.

Torna interessante a reprodução do "Pocket Empires", que oferece acesso instantâneo à conta de alguém com base no DeviceID "exclusivo".

Meu dispositivo não tem um rádio celular.


Eu uso o seguinte código para obter o IMEIou usar o Secure. ANDROID_IDcomo alternativa, quando o dispositivo não tem recursos de telefone:

String identifier = null;
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
if (tm != null)
      identifier = tm.getDeviceId();
if (identifier == null || identifier .length() == 0)
      identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);

O mac id do dispositivo Android também tem um ID exclusivo, ele não será alterado se o formato do dispositivo for usado usando o seguinte código para obter o ID do dispositivo

WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();
String address = info.getMacAddress();

Também não esqueça de adicionar as permissões apropriadas no seu AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

Existem mais de 30 respostas aqui e algumas são iguais e algumas são únicas. Esta resposta é baseada em algumas dessas respostas. Uma delas é a resposta de @Lenn Dolling.

Ele combina 3 IDs e cria uma string hexadecimal de 32 dígitos. Isso funcionou muito bem para mim.

3 IDs são:
Pseudo-ID - É gerado com base nas especificações do dispositivo físico
ANDROID_ID - Settings.Secure.ANDROID_ID
Endereço Bluetooth - Endereço do adaptador Bluetooth

Ele retornará algo assim: 551F27C060712A72730B0A0F734064B1

Nota: Você sempre pode adicionar mais IDs à longIdstring. Por exemplo, nº de série. endereço do adaptador wifi. IMEI. Desta forma, você está tornando mais exclusivo por dispositivo.

@SuppressWarnings("deprecation")
@SuppressLint("HardwareIds")
public static String generateDeviceIdentifier(Context context) {

        String pseudoId = "35" +
                Build.BOARD.length() % 10 +
                Build.BRAND.length() % 10 +
                Build.CPU_ABI.length() % 10 +
                Build.DEVICE.length() % 10 +
                Build.DISPLAY.length() % 10 +
                Build.HOST.length() % 10 +
                Build.ID.length() % 10 +
                Build.MANUFACTURER.length() % 10 +
                Build.MODEL.length() % 10 +
                Build.PRODUCT.length() % 10 +
                Build.TAGS.length() % 10 +
                Build.TYPE.length() % 10 +
                Build.USER.length() % 10;

        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String btId = "";

        if (bluetoothAdapter != null) {
            btId = bluetoothAdapter.getAddress();
        }

        String longId = pseudoId + androidId + btId;

        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(longId.getBytes(), 0, longId.length());

            // get md5 bytes
            byte md5Bytes[] = messageDigest.digest();

            // creating a hex string
            String identifier = "";

            for (byte md5Byte : md5Bytes) {
                int b = (0xFF & md5Byte);

                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    identifier += "0";
                }

                // add number to string
                identifier += Integer.toHexString(b);
            }

            // hex string to uppercase
            identifier = identifier.toUpperCase();
            return identifier;
        } catch (Exception e) {
            Log.e("TAG", e.toString());
        }
        return "";
}

Para reconhecimento de hardware de um dispositivo Android específico, você pode verificar os endereços MAC.

você pode fazer assim:

em AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />

agora no seu código:

List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());

for (NetworkInterface interface : interfacesList) {
   // This will give you the interface MAC ADDRESS
   interface.getHardwareAddress();
}

Em todos os dispositivos Android, é pelo menos uma interface "wlan0" que é o chip WI-FI. Este código funciona mesmo quando o WI-FI não está ligado.

PS O seu é um monte de outras interfaces que você irá obter na lista contendo MACS Mas isso pode mudar entre os telefones.


ATUALIZAÇÃO : a partir das versões recentes do Android, muitos dos problemas com o ANDROID_ID foram resolvidos e acredito que essa abordagem não é mais necessária. Por favor, dê uma olhada na resposta de Anthony .

Divulgação completa: meu aplicativo usava a abordagem abaixo originalmente, mas não usa mais essa abordagem, e agora usamos a abordagem descrita na entrada do android-developers.blogspot.com/2011/03/… do android-developers.blogspot.com/2011/03/… que os links de resposta do emmby (ou seja, gerar e salvar um UUID#randomUUID() ).

Há muitas respostas a essa pergunta, a maioria das quais funcionará apenas "algumas" vezes e, infelizmente, isso não é suficiente.

Com base nos meus testes de dispositivos (todos os telefones, pelo menos um deles não está ativado):

  1. Todos os dispositivos testados retornaram um valor para TelephonyManager.getDeviceId()
  2. Todos os dispositivos GSM (todos testados com um SIM) retornaram um valor para TelephonyManager.getSimSerialNumber()
  3. Todos os dispositivos CDMA retornaram null para getSimSerialNumber() (conforme esperado)
  4. Todos os dispositivos com uma conta do Google adicionada retornaram um valor para ANDROID_ID
  5. Todos os dispositivos CDMA retornaram o mesmo valor (ou derivação do mesmo valor) para ANDROID_ID e TelephonyManager.getDeviceId() - desde que uma conta do Google tenha sido adicionada durante a configuração.
  6. Eu ainda não tive a chance de testar dispositivos GSM sem SIM, um dispositivo GSM sem nenhuma conta do Google adicionada ou qualquer um dos dispositivos no modo avião.

Então, se você quer algo único para o próprio dispositivo, o TM.getDeviceId() deve ser suficiente. Obviamente, alguns usuários são mais paranóicos do que outros, portanto, pode ser útil misturar 1 ou mais desses identificadores, de modo que a string ainda seja virtualmente exclusiva para o dispositivo, mas não identifique explicitamente o dispositivo real do usuário. Por exemplo, usando String.hashCode() , combinado com um UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);

final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

pode resultar em algo como: 00000000-54b3-e7c7-0000-000046bffd97

Isso funciona bem o suficiente para mim.

Como Richard menciona abaixo, não se esqueça de que você precisa de permissão para ler as propriedades do TelephonyManager , então adicione isso ao seu manifesto:

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

importar libs

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

Um campo Serial foi adicionado à Buildclasse no nível 9 da API (Android 2.3 - Gingerbread). A documentação diz que representa o número de série do hardware. Assim, deve ser único, se existir no dispositivo.

Eu não sei se é realmente suportado (= não nulo) por todos os dispositivos com nível de API> = 9 embora.


Outra maneira é usar /sys/class/android_usb/android0/iSerialem um aplicativo sem qualquer permissão.

[email protected]:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
-rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
[email protected]:~$ 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, porque nem todos os dispositivos possuem esse arquivo.

Pelo menos os seguintes dispositivos são conhecidos por terem este arquivo legível:

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

Você também pode ver o meu post do blog Vazando o número de série do hardware do Android para aplicativos não privilegiados, onde discuto quais outros arquivos estão disponíveis para obter informações.


Há várias abordagens diferentes para contornar esses ANDROID_IDproblemas ( nullàs vezes, ou dispositivos de um modelo específico sempre retornam a mesma ID) com prós e contras:

  • Implementando um algoritmo de geração de ID personalizado (com base nas propriedades do dispositivo que devem ser estáticas e não serão alteradas -> quem sabe)
  • Abusar de outros IDs como IMEI , número de série, endereço Wi-Fi / Bluetooth-MAC (eles não existirão em todos os dispositivos ou permissões adicionais serão necessárias)

Eu mesmo prefiro usar uma implementação existente do OpenUDID (veja https://github.com/ylechelle/OpenUDID ) para Android (veja https://github.com/vieux/OpenUDID ). É fácil de integrar e faz uso de ANDROID_IDfallbacks para os problemas mencionados acima.


Aqui está como eu estou gerando o id único:

import android.Manifest.permission;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

// TODO : hash
public final class DeviceIdentifier {

    private DeviceIdentifier() {}

    /** @see http://code.google.com/p/android/issues/detail?id=10603 */
    private static final String ANDROID_ID_BUG_MSG = "The device suffers from "
        + "the Android ID bug - its ID is the emulator ID : "
        + IDs.BUGGY_ANDROID_ID;
    private static volatile String uuid; // volatile needed - see EJ item 71
    // need lazy initialization to get a context

    /**
     * Returns a unique identifier for this device. The first (in the order the
     * enums constants as defined in the IDs enum) non null identifier is
     * returned or a DeviceIDException is thrown. A DeviceIDException is also
     * thrown if ignoreBuggyAndroidID is false and the device has the Android ID
     * bug
     *
     * @param ctx
     *            an Android constant (to retrieve system services)
     * @param ignoreBuggyAndroidID
     *            if false, on a device with the android ID bug, the buggy
     *            android ID is not returned instead a DeviceIDException is
     *            thrown
     * @return a *device* ID - null is never returned, instead a
     *         DeviceIDException is thrown
     * @throws DeviceIDException
     *             if none of the enum methods manages to return a device ID
     */
    public static String getDeviceIdentifier(Context ctx,
            boolean ignoreBuggyAndroidID) throws DeviceIDException {
        String result = uuid;
        if (result == null) {
            synchronized (DeviceIdentifier.class) {
                result = uuid;
                if (result == null) {
                    for (IDs id : IDs.values()) {
                        try {
                            result = uuid = id.getId(ctx);
                        } catch (DeviceIDNotUniqueException e) {
                            if (!ignoreBuggyAndroidID)
                                throw new DeviceIDException(e);
                        }
                        if (result != null) return result;
                    }
                    throw new DeviceIDException();
                }
            }
        }
        return result;
    }

    private static enum IDs {
        TELEPHONY_ID {

            @Override
            String getId(Context ctx) {
                // TODO : add a SIM based mechanism ? tm.getSimSerialNumber();
                final TelephonyManager tm = (TelephonyManager) ctx
                        .getSystemService(Context.TELEPHONY_SERVICE);
                if (tm == null) {
                    w("Telephony Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.READ_PHONE_STATE);
                return tm.getDeviceId();
            }
        },
        ANDROID_ID {

            @Override
            String getId(Context ctx) throws DeviceIDException {
                // no permission needed !
                final String andoidId = Secure.getString(
                    ctx.getContentResolver(),
                    android.provider.Settings.Secure.ANDROID_ID);
                if (BUGGY_ANDROID_ID.equals(andoidId)) {
                    e(ANDROID_ID_BUG_MSG);
                    throw new DeviceIDNotUniqueException();
                }
                return andoidId;
            }
        },
        WIFI_MAC {

            @Override
            String getId(Context ctx) {
                WifiManager wm = (WifiManager) ctx
                        .getSystemService(Context.WIFI_SERVICE);
                if (wm == null) {
                    w("Wifi Manager not available");
                    return null;
                }
                assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess
                // getMacAddress() has no java doc !!!
                return wm.getConnectionInfo().getMacAddress();
            }
        },
        BLUETOOTH_MAC {

            @Override
            String getId(Context ctx) {
                BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
                if (ba == null) {
                    w("Bluetooth Adapter not available");
                    return null;
                }
                assertPermission(ctx, permission.BLUETOOTH);
                return ba.getAddress();
            }
        }
        // TODO PSEUDO_ID
        // http://www.pocketmagic.net/2011/02/android-unique-device-id/
        ;

        static final String BUGGY_ANDROID_ID = "9774d56d682e549c";
        private final static String TAG = IDs.class.getSimpleName();

        abstract String getId(Context ctx) throws DeviceIDException;

        private static void w(String msg) {
            Log.w(TAG, msg);
        }

        private static void e(String msg) {
            Log.e(TAG, msg);
        }
    }

    private static void assertPermission(Context ctx, String perm) {
        final int checkPermission = ctx.getPackageManager().checkPermission(
            perm, ctx.getPackageName());
        if (checkPermission != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Permission " + perm + " is required");
        }
    }

    // =========================================================================
    // Exceptions
    // =========================================================================
    public static class DeviceIDException extends Exception {

        private static final long serialVersionUID = -8083699995384519417L;
        private static final String NO_ANDROID_ID = "Could not retrieve a "
            + "device ID";

        public DeviceIDException(Throwable throwable) {
            super(NO_ANDROID_ID, throwable);
        }

        public DeviceIDException(String detailMessage) {
            super(detailMessage);
        }

        public DeviceIDException() {
            super(NO_ANDROID_ID);
        }
    }

    public static final class DeviceIDNotUniqueException extends
            DeviceIDException {

        private static final long serialVersionUID = -8940090896069484955L;

        public DeviceIDNotUniqueException() {
            super(ANDROID_ID_BUG_MSG);
        }
    }
}

Como sobre o IMEI . Isso é exclusivo para Android ou outros dispositivos móveis.


Além disso, você pode considerar o endereço MAC do adaptador Wi-Fi. Recuperado assim:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

Requer permissão android.permission.ACCESS_WIFI_STATE no manifesto.

Relatado para estar disponível mesmo quando o Wi-Fi não estiver conectado. Se o Joe da resposta acima testar esse em seus muitos dispositivos, seria legal.

Em alguns dispositivos, não está disponível quando o Wi-Fi está desativado.

OBSERVAÇÃO: no Android 6.x, ele retorna um endereço mac falso e consistente: 02:00:00:00:00:00


Adicione abaixo o código no arquivo de classe:

final TelephonyManager tm = (TelephonyManager) getBaseContext()
            .getSystemService(SplashActivity.TELEPHONY_SERVICE);
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    Log.v("DeviceIMEI", "" + tmDevice);
    tmSerial = "" + tm.getSimSerialNumber();
    Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
            android.provider.Settings.Secure.ANDROID_ID);
    Log.v("androidId CDMA devices", "" + androidId);
    UUID deviceUuid = new UUID(androidId.hashCode(),
            ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
    String deviceModelName = android.os.Build.MODEL;
    Log.v("Model Name", "" + deviceModelName);
    String deviceUSER = android.os.Build.USER;
    Log.v("Name USER", "" + deviceUSER);
    String devicePRODUCT = android.os.Build.PRODUCT;
    Log.v("PRODUCT", "" + devicePRODUCT);
    String deviceHARDWARE = android.os.Build.HARDWARE;
    Log.v("HARDWARE", "" + deviceHARDWARE);
    String deviceBRAND = android.os.Build.BRAND;
    Log.v("BRAND", "" + deviceBRAND);
    String myVersion = android.os.Build.VERSION.RELEASE;
    Log.v("VERSION.RELEASE", "" + myVersion);
    int sdkVersion = android.os.Build.VERSION.SDK_INT;
    Log.v("VERSION.SDK_INT", "" + sdkVersion);

Adicione em AndroidManifest.xml:

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

Settings.Secure#ANDROID_ID retorna o ID do Android como exclusivo para cada string hexadecimal de 64 bits.

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID); 




uniqueidentifier