unico - uuid android




Existe um ID de dispositivo Android exclusivo? (20)

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/


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 .


Aqui está o código que Reto Meier usou na apresentação do Google I / O este ano para obter um ID exclusivo para o usuário:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";

public synchronized static String id(Context context) {
    if (uniqueID == null) {
        SharedPreferences sharedPrefs = context.getSharedPreferences(
                PREF_UNIQUE_ID, 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();
        }
    }
    return uniqueID;
}

Se você combinar isso com uma estratégia de backup para enviar preferências para a nuvem (também descrita na talk do Reto, você deve ter um ID que se conecte a um usuário e fique por perto após o dispositivo ter sido limpo ou mesmo substituído. em analítica daqui para frente (em outras palavras, eu ainda não fiz isso).


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

No I / O do Google, Reto Meier divulgou uma resposta robusta sobre como abordar isso, que deve atender à maioria dos desenvolvedores, a fim de rastrear os usuários nas instalações. Anthony Nolan mostra a direção em sua resposta, mas eu pensei em escrever a abordagem completa para que os outros possam ver facilmente como fazê-lo (demorei um pouco para descobrir os detalhes).

Essa abordagem oferecerá a você um ID de usuário anônimo e seguro, que será persistente para o usuário em diferentes dispositivos (com base na conta principal do Google) e nas instalações. A abordagem básica é gerar um ID de usuário aleatório e armazená-lo nas preferências compartilhadas dos aplicativos. Em seguida, você usa o agente de backup do Google para armazenar as preferências compartilhadas vinculadas à conta do Google na nuvem.

Vamos percorrer a abordagem completa. Primeiro, precisamos criar um backup para nossas SharedPreferences usando o Serviço de Backup do Android. Comece registrando seu aplicativo por meio de http://developer.android.com/google/backup/signup.html .

O Google fornecerá uma chave de serviço de backup que você precisará 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 informá-lo para usar o agente auxiliar para sharedpreferences:

public class MyBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

Para completar 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 no 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 será persistente nas instalações, mesmo que o usuário mova o dispositivo.

Para mais informações sobre essa abordagem, veja talk .

E para detalhes completos sobre como implementar o agente de backup, consulte Data Backup . Eu particularmente recomendo a seção na parte inferior no teste como o backup não acontece instantaneamente e assim para testar você tem que forçar o backup.



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;

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


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

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

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

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.


Usando o código abaixo, você pode obter o ID exclusivo do dispositivo de um dispositivo Android OS como uma string.

deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

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


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

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.


Meus dois centavos - NB isso é para um dispositivo (err) ID único - não a instalação como discutido no blog dos desenvolvedores do Android .

Note que a solution fornecida por @emmby recai em um ID por aplicativo, pois as SharedPreferences não são sincronizadas entre os processos (veja here e here ). Então evitei tudo isso.

Em vez disso, encapsulei as várias estratégias para obter um ID (dispositivo) em um enum - alterar a ordem das constantes de enum afeta a prioridade das várias maneiras de obter o ID. O primeiro ID não nulo é retornado ou uma exceção é lançada (conforme boas práticas Java de não dar um significado nulo). Então, por exemplo, eu tenho o TELEPHONY primeiro - mas uma boa escolha padrão seria o ANDROID_ID beta:

public static String getDeviceId(Context ctx)
{
    TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

    String tmDevice = tm.getDeviceId();
    String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
    String serial = null;
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;

    if(tmDevice != null) return "01" + tmDevice;
    if(androidId != null) return "02" + androidId;
    if(serial != null) return "03" + serial;
    // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)

    return null;
}

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


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.


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




uniqueidentifier