Como posso detectar quando um aplicativo Android está sendo executado no emulador?

313

Gostaria que meu código fosse executado de maneira um pouco diferente ao executar no emulador e ao executar em um dispositivo. ( Por exemplo , usando 10.0.2.2 em vez de um URL público para executar automaticamente em um servidor de desenvolvimento.) Qual é a melhor maneira de detectar quando um aplicativo Android está sendo executado no emulador?

Joe Ludwig
fonte
2
Pode dar uma olhada android.os.Build.
Yanchenko
11
Surpreenda-me ... O Google deve ter uma maneira padrão de fazer isso?
precisa saber é o seguinte
@kreker qual é o problema que você está enfrentando nas soluções existentes?
Khemraj
Problemas de fraude @Khemraj. Cara mal pode zombar alguns sensores e alterar algumas cordas para fingir dispositivo real
kreker

Respostas:

159

Que tal esta solução:

    fun isProbablyAnEmulator() = Build.FINGERPRINT.startsWith("generic")
            || Build.FINGERPRINT.startsWith("unknown")
            || Build.MODEL.contains("google_sdk")
            || Build.MODEL.contains("Emulator")
            || Build.MODEL.contains("Android SDK built for x86")
            || Build.BOARD == "QC_Reference_Phone" //bluestacks
            || Build.MANUFACTURER.contains("Genymotion")
            || Build.HOST.startsWith("Build") //MSI App Player
            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
            || "google_sdk" == Build.PRODUCT

Observe que alguns emuladores falsificam especificações exatas de dispositivos reais; portanto, pode ser impossível detectá-lo.

Aqui está um pequeno trecho que você pode criar no APK para mostrar várias coisas sobre ele e adicionar suas próprias regras:

        textView.text = "FINGERPRINT:${Build.FINGERPRINT}\n" +
                "MODEL:${Build.MODEL}\n" +
                "MANUFACTURER:${Build.MANUFACTURER}\n" +
                "BRAND:${Build.BRAND}\n" +
                "DEVICE:${Build.DEVICE}\n" +
                "BOARD:${Build.BOARD}\n" +
                "HOST:${Build.HOST}\n" +
                "PRODUCT:${Build.PRODUCT}\n"
desenvolvedor android
fonte
9
É assim que o Facebook detecta emuladores no React-Native
Vaiden
Era para isso que eu precisava atualizar depois de usar a resposta do @Aleadam por um tempo (ele parou de funcionar para mim).
ckbhodge
@ Sid O que deve ser adicionado a ele?
desenvolvedor android
2
@Sid Você já imprimiu várias variáveis ​​da classe Build lá? Nada parece especial? Você já tentou isso: github.com/framgia/android-emulator-detector ?
desenvolvedor Android
1
@DrDeo Você pode adicionar uma verificação da versão atual usando o BuildConfig.DEBUG ou criar sua própria versão com sua própria variável personalizada. Você também pode usar o Proguard para fazer com que essa função sempre retorne falsa, ou algo assim (você pode remover logs, por exemplo, como mostrado aqui: medium.com/tixdo-labs/… , talvez seja possível também)
desenvolvedor android
118

Um sems comum a ser Build.FINGERPRINT.contains("generic")

Aleadam
fonte
Isso funciona mesmo com o Galaxy Tab Emulator. A resposta preferida não foi.
BufferStack
10
Por favor, indique se uma impressão digital contendo "genérico" é um emulador ou o dispositivo. Essa informação é fundamental, mas não fornecida.
James Cameron
2
Emulator - a julgar pelos comentários antes de seu :)
Dori
8
Isso retorna verdadeiro em meus dispositivos executando o CyanogenMod, então cuidado.
ardevd
8
A documentação do Android diz que você não deve tentar interpretar o FINGERPRINTvalor.
Gnuf 14/12/2015
64

Bem, o ID do Android não funciona para mim. No momento, estou usando:

"google_sdk".equals( Build.PRODUCT );
Marcus
fonte
35
Qualquer pessoa que esteja lendo isso pode estar interessada em saber que essa sequência parece ter sido alterada para 'sdk', em vez de 'google_sdk'.
Daniel Sloof
15
@ Daniel: Eu uso 2.3.3 com a API do Google e diz 'google_sdk'. Parece que é 'google_sdk' para AVD com API do Google e 'sdk' para as normais.
Randy Sugianto 'Yuku'
3
O emulador Intel retorna "full_x86" para que eu não conte com esse método.
user462982
3
@GlennMaynard O formulário inverso é feio, mas prático: Build.PRODUCT pode ser nulo, enquanto "google_sdk" não pode, portanto, este formulário evita um possível erro de referência nula.
Rupert Rawnsley
4
Incluindo mais casos: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Alberto Alonso Ruibal
31

Com base nas dicas de outras respostas, esta é provavelmente a maneira mais robusta:

isEmulator = "goldfish".equals(Build.HARDWARE)

Vitali
fonte
Sim. Ao contrário do Build.PRODUCT, o Build.HARDWARE (peixe dourado) é o mesmo para o SDK e o AOSP oficiais. Antes da API 8, você precisa usar a reflexão para acessar o campo HARDWARE.
David Chandler
4
Eu iria comisEmulator = Build.HARDWARE.contains("golfdish")
holmes
7
@holmes: typo, s / b "peixinho"
Noah
7
Para a imagem Android 5.1 x86_64 (e provavelmente outras imagens mais recentes de 64 bits), seria "ranchu" em vez de "peixinho".
warbi
28

O Google usa esse código no plug-in de informações do dispositivo do Flutter para determinar se o dispositivo é um emulador:

private boolean isEmulator() {
    return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
        || Build.FINGERPRINT.startsWith("generic")
        || Build.FINGERPRINT.startsWith("unknown")
        || Build.HARDWARE.contains("goldfish")
        || Build.HARDWARE.contains("ranchu")
        || Build.MODEL.contains("google_sdk")
        || Build.MODEL.contains("Emulator")
        || Build.MODEL.contains("Android SDK built for x86")
        || Build.MANUFACTURER.contains("Genymotion")
        || Build.PRODUCT.contains("sdk_google")
        || Build.PRODUCT.contains("google_sdk")
        || Build.PRODUCT.contains("sdk")
        || Build.PRODUCT.contains("sdk_x86")
        || Build.PRODUCT.contains("vbox86p")
        || Build.PRODUCT.contains("emulator")
        || Build.PRODUCT.contains("simulator");
}
Rockney
fonte
20

Que tal algo como o código abaixo para saber se seu aplicativo foi assinado com a chave de depuração? não está detectando o emulador, mas pode funcionar para o seu propósito?

public void onCreate Bundle b ) {
   super.onCreate(savedInstanceState);
   if ( signedWithDebugKey(this,this.getClass()) ) {
     blah blah blah
   }

  blah 
    blah 
      blah

}

static final String DEBUGKEY = 
      "get the debug key from logcat after calling the function below once from the emulator";    


public static boolean signedWithDebugKey(Context context, Class<?> cls) 
{
    boolean result = false;
    try {
        ComponentName comp = new ComponentName(context, cls);
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(),PackageManager.GET_SIGNATURES);
        Signature sigs[] = pinfo.signatures;
        for ( int i = 0; i < sigs.length;i++)
        Log.d(TAG,sigs[i].toCharsString());
        if (DEBUGKEY.equals(sigs[0].toCharsString())) {
            result = true;
            Log.d(TAG,"package has been signed with the debug key");
        } else {
            Log.d(TAG,"package signed with a key other than the debug key");
        }

    } catch (android.content.pm.PackageManager.NameNotFoundException e) {
        return false;
    }

    return result;

} 
Jeff S
fonte
1
Obrigado por este código. Eu verifiquei e está funcionando, mas lidar com a chave de depuração longa pode ser doloroso, mas é feito apenas uma vez. Esta é a única solução confiável , pois todas as outras respostas comparam parte da cadeia de informações de compilação do SO com uma cadeia estática, e isso pode e foi alterado nas versões do Android SDK e também pode ser forjado por compilações personalizadas do Android.
ZoltanF
Eu acho que é a única solução confiável. No entanto, a chave de depuração pode mudar mais rapidamente do que queremos.
Rds
2
Uma maneira melhor de fazer isso é BuildConfig.DEBUG.
Mygod 15/05/19
13

Este código funciona para mim

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = tm.getNetworkOperatorName();
if("Android".equals(networkOperator)) {
    // Emulator
}
else {
    // Device
}

Caso esse dispositivo não possua um cartão SIM, ele retira a string vazia: ""

Como o emulador do Android sempre executa o "Android" como operador de rede, eu uso o código acima.

JJ Kim
fonte
3
O que um dispositivo sem um cartão SIM (como um tablet) retorna?
Rds
Executando o emulador para Android 2.1. Este código estava funcionando para mim, mas desde a atualização do Cordova para 2.7.0, a variável Context parece estar indefinida ou algo assim. Aqui está o erro que estou recebendo no ADT: "O contexto não pode ser resolvido para uma variável". Além disso, de acordo com o comentário acima, este NÃO é um método confiável (embora eu realmente não o tenha falhado).
Rustavore 17/05
2
@rds dispositivos que não têm um cartão SIM retorna string vazia ( "")
JJ Kim
Não há como ter esse valor com o emulador? porque eu gostaria de bloquear todos os usuários se eles não tiverem cartões SIM.
c-an
12

Eu tentei várias técnicas, mas resolvi usar uma versão revisada para verificar o Build.PRODUCT como abaixo. Isso parece variar bastante de emulador para emulador, é por isso que tenho as 3 verificações que tenho atualmente. Acho que poderia ter verificado se product.contains ("sdk"), mas achei a verificação abaixo um pouco mais segura.

public static boolean isAndroidEmulator() {
    String model = Build.MODEL;
    Log.d(TAG, "model=" + model);
    String product = Build.PRODUCT;
    Log.d(TAG, "product=" + product);
    boolean isEmulator = false;
    if (product != null) {
        isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
    }
    Log.d(TAG, "isEmulator=" + isEmulator);
    return isEmulator;
}

Para sua informação, descobri que meu Kindle Fire tinha Build.BRAND = "generic" e alguns dos emuladores não tinham "Android" para a operadora de rede.

Patrick
fonte
11

Os seguintes itens estão definidos como "google_sdk":

Build.PRODUCT
Build.MODEL

Portanto, deve ser suficiente usar uma das seguintes linhas.

"google_sdk".equals(Build.MODEL)

ou

"google_sdk".equals(Build.PRODUCT)
Sileria
fonte
Ao executar o emulador x86 no Windows, o Build.Product é sdk_x86.
Edward Brey 14/10
verificar com o produto não é um boa escolha como ele retorna vários valores de diferentes emuladores
Beeing Jk
10

Acabei de olhar para _sdk, _sdk_ou sdk_, ou mesmo apenas sdkparte Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
SD
fonte
3
Por que não apenas contains("sdk")? A única diferença (além de ser mais rápida) é que, matches(".*_?sdk_?.*")se houver um caractere antes ou depois do sdk, ele deverá ser um sublinhado '_', que não é tão importante assim.
Nulano 28/01
9

Eu nunca encontrei uma boa maneira de saber se você está no emulador.

mas se você apenas precisar detectar se está em um ambiente de desenvolvimento, poderá fazer o seguinte:

     if(Debug.isDebuggerConnected() ) {
        // Things to do in debug environment...
    }

Espero que esta ajuda ....

Etherpulse
fonte
8

use esta função:

 public static final boolean isEmulator() {

    int rating = 0;

    if ((Build.PRODUCT.equals("sdk")) || (Build.PRODUCT.equals("google_sdk"))
            || (Build.PRODUCT.equals("sdk_x86")) || (Build.PRODUCT.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MANUFACTURER.equals("unknown")) || (Build.MANUFACTURER.equals("Genymotion"))) {
        rating++;
    }
    if ((Build.BRAND.equals("generic")) || (Build.BRAND.equals("generic_x86"))) {
        rating++;
    }
    if ((Build.DEVICE.equals("generic")) || (Build.DEVICE.equals("generic_x86")) || (Build.DEVICE.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MODEL.equals("sdk")) || (Build.MODEL.equals("google_sdk"))
            || (Build.MODEL.equals("Android SDK built for x86"))) {
        rating++;
    }
    if ((Build.HARDWARE.equals("goldfish")) || (Build.HARDWARE.equals("vbox86"))) {
        rating++;
    }
    if ((Build.FINGERPRINT.contains("generic/sdk/generic"))
            || (Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86"))
            || (Build.FINGERPRINT.contains("generic/google_sdk/generic"))
            || (Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))) {
        rating++;
    }

    return rating > 4;

    }
AndroidCrop
fonte
7

Não sei se existem maneiras melhores de detectar a emu, mas o emulador terá o arquivo init.goldfish.rcno diretório raiz.

É o script de inicialização específico do emulador e não deve estar lá em uma compilação que não seja emulador.

Nils Pipenbrinck
fonte
Durante a inicialização do sistema Android, o kernel do Linux primeiro chama o processo de "init". init lê os arquivos "/init.rc" e "init.device.rc". "init.device.rc" é específico do dispositivo, no dispositivo virtual esse arquivo é chamado "init.goldfish.rc".
NET3
7

Aqui está minha solução (ela funciona apenas se você executar um servidor Web em sua máquina de depuração): Criei uma tarefa em segundo plano que é iniciada quando o aplicativo é iniciado. Ele procura por http://10.0.2.2 e, se existir, altera um parâmetro global (IsDebug) para true. É uma maneira silenciosa de descobrir onde você está executando.

public class CheckDebugModeTask extends AsyncTask<String, Void, String> {
public static boolean IsDebug = false;

public CheckDebugModeTask()
{

}

@Override
protected String doInBackground(String... params) {     
  try {
    HttpParams httpParameters = new BasicHttpParams();
    int timeoutConnection = 1000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    int timeoutSocket = 2000;
    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

    String url2 = "http://10.0.2.2";        
          HttpGet httpGet = new HttpGet(url2);
    DefaultHttpClient client = new DefaultHttpClient(httpParameters);

    HttpResponse response2 = client.execute(httpGet);
    if (response2 == null || response2.getEntity() == null || response2.getEntity().getContent() == null)
    return "";

    return "Debug";

} catch (Exception e) {
    return "";
}
}

@Override
protected void onPostExecute (String result)
{       
if (result == "Debug")
{
    CheckDebugModeTask.IsDebug = true;
}
}

da atividade principal do onCreate:

CheckDebugModeTask checkDebugMode = new CheckDebugModeTask();
checkDebugMode.execute("");
Eyal
fonte
7

Da bateria, o emulador: A fonte de energia é sempre o carregador CA. A temperatura é sempre 0.

E você pode usar Build.HOSTpara registrar o valor do host, emulador diferente tem valor de host diferente.

Louie Liu
fonte
Como você obtém a fonte de energia e a temperatura?
developer android
6

Encontrei o novo emulador Build.HARDWARE = "ranchu".

Referência: https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU

E também encontrei a maneira oficial do Android para verificar se o emulador ou não. Acho que é uma boa referência para nós.

Desde a API do Android, nível 23 [Android 6.0]

package com.android.internal.util;

/**
 * @hide
 */
public class ScreenShapeHelper {
    private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
}

Nós temos ScreenShapeHelper.IS_EMULATOR verificar se o emulador.

Desde o nível 24 da API do Android [Android 7.0]

package android.os;

/**
 * Information about the current build, extracted from system properties.
 */
public class Build {


    /**
     * Whether this build was for an emulator device.
     * @hide
     */
    public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");

}

Nós temos Build.IS_EMULATOR verificar se o emulador.

A maneira como o funcionário verifica se o emulador não é novo, e também talvez não seja suficiente, as respostas acima também mencionaram.

Mas isso talvez nos mostre que o oficial fornecerá o caminho do oficial para verificar se o emulador ou não.

Como usamos todas as maneiras acima mencionadas, agora também podemos usar as duas maneiras para verificar se o emulador.

Como acessar o com.android.internalpacote e@hide

e aguarde o SDK oficial aberto.

ifeegoo
fonte
5

Outra opção seria olhar para a propriedade ro.hardware e ver se ela está definida como peixinho. Infelizmente, não parece haver uma maneira fácil de fazer isso em Java, mas é trivial em C usando property_get () .

Tim Kryger
fonte
4
Isso parece funcionar no NDK. Inclua <sys / system_properties.h> e use __system_property_get ("ro.hardware", buf) e verifique se buf é "peixinho".
NuSkooler 25/01
5

A solução sugerida acima para verificar se ANDROID_IDfuncionou para mim até que eu atualizei hoje as ferramentas mais recentes do SDK lançadas com o Android 2.2.

Portanto, atualmente mudei para a seguinte solução, que funciona até agora com a desvantagem, no entanto, é necessário colocar a permissão de leitura PHONE_STATE ( <uses-permission android:name="android.permission.READ_PHONE_STATE"/>)

private void checkForDebugMode() {
    ISDEBUGMODE = false; //(Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID) == null);

    TelephonyManager man = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
    if(man != null){
        String devId = man.getDeviceSoftwareVersion();
        ISDEBUGMODE = (devId == null);
    }
} 
Juri
fonte
5

Todas as respostas em um método

static boolean checkEmulator()
{
    try
    {
        String buildDetails = (Build.FINGERPRINT + Build.DEVICE + Build.MODEL + Build.BRAND + Build.PRODUCT + Build.MANUFACTURER + Build.HARDWARE).toLowerCase();

        if (buildDetails.contains("generic") 
        ||  buildDetails.contains("unknown") 
        ||  buildDetails.contains("emulator") 
        ||  buildDetails.contains("sdk") 
        ||  buildDetails.contains("genymotion") 
        ||  buildDetails.contains("x86") // this includes vbox86
        ||  buildDetails.contains("goldfish")
        ||  buildDetails.contains("test-keys"))
            return true;
    }   
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        TelephonyManager    tm  = (TelephonyManager) App.context.getSystemService(Context.TELEPHONY_SERVICE);
        String              non = tm.getNetworkOperatorName().toLowerCase();
        if (non.equals("android"))
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        if (new File ("/init.goldfish.rc").exists())
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    return false;
}
XXX
fonte
Agradável. init.goldfish.rcexiste apenas em emuladores; além disso, é uma boa verificação, além dos detalhes da compilação.
sud007 25/05
2
@ sud007 Existem muitos dispositivos por aí com `/init.goldfish.rc e isso levará a falsos positivos. Por exemplo, muitos dispositivos da série Samsung Galaxy.
Laur
@laalto você estava realmente correto. Descobri isso mais tarde e desculpas por me esquecer de atualizá-lo aqui.
sud007
test-keys tem gerado falsos positivos para mim.
Avi Parshan
Em quais dispositivos eles estão gerando falsos positivos?
Aman Verma
5

Minha recomendação:

tente isso no github.

Fácil de detectar emulador Android

  • Verificado em dispositivos reais no Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Emulador Android
  • Andy 46.2.207.0
  • MEmu play
  • Nox App Player
  • Koplayer
  • .....

Como usar com um exemplo:

EmulatorDetector.with(this)
                .setCheckTelephony(true)
                .addPackageName("com.bluestacks")
                .setDebug(true)
                .detect(new EmulatorDetector.OnEmulatorDetectorListener() {
                    @Override
                    public void onResult(boolean isEmulator) {

                    }
                });
Saeed
fonte
4

você pode verificar o número IMEI, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

se eu me lembro no emulador esse retorno 0. no entanto, não há documentação que eu possa encontrar que garanta isso. embora o emulador nem sempre retorne 0, parece bastante seguro que um telefone registrado não retorne 0. o que aconteceria em um dispositivo Android sem telefone, ou um sem um cartão SIM instalado ou um que não esteja registrado no momento rede?

parece que seria uma má ideia, depender disso.

isso também significa que você precisará pedir permissão para ler o estado do telefone, o que é ruim se você ainda não o exige para outra coisa.

caso contrário, sempre haverá uma inversão em algum lugar antes de você finalmente gerar seu aplicativo assinado.

Jeff
fonte
5
É provável que o IMEI também retorne 0em um tablet Android ou em um telefone sem cartão SIM.
Paul Lammertsma 11/03/11
Podemos editar o IMEI no emulador. portanto, isso pode não servir ao propósito. Além disso, a partir da API 29, não podemos acessar o IMEI.
Ananth
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

Isso deve retornar verdadeiro se o aplicativo estiver sendo executado em um emulador.

O que devemos ter cuidado é não detectar todos os emuladores, porque existem apenas vários emuladores diferentes. É fácil de verificar. Temos que garantir que os dispositivos reais não sejam detectados como um emulador.

Eu usei o aplicativo chamado " Android Device Info Share " para verificar isso.

Neste aplicativo, você pode ver vários tipos de informações de muitos dispositivos (provavelmente a maioria dos dispositivos no mundo; se o dispositivo que você estiver usando estiver ausente na lista, ele será adicionado automaticamente).

kanji
fonte
No meu Genymotion rodando em um mac Build.DEVICE = vbox86p
lxknvlk
4

Verificando as respostas, nenhuma delas funcionou ao usar emuladores LeapDroid, Droid4x ou Andy,

O que funciona para todos os casos é o seguinte:

 private static String getSystemProperty(String name) throws Exception {
    Class systemPropertyClazz = Class.forName("android.os.SystemProperties");
    return (String) systemPropertyClazz.getMethod("get", new Class[]{String.class}).invoke(systemPropertyClazz, new Object[]{name});
}

public boolean isEmulator() {
    boolean goldfish = getSystemProperty("ro.hardware").contains("goldfish");
    boolean emu = getSystemProperty("ro.kernel.qemu").length() > 0;
    boolean sdk = getSystemProperty("ro.product.model").equals("sdk");
    return goldfish || emu || sdk;
}
leon karabchesvky
fonte
1
# airpair.com/android/posts/…
Yousha Aleayoub 9/09/16
Andy_46.16_48 retorna "andy" para Build.HARDWARE
Doug Voss
Chumbo falso positivo para dispositivos Samsung série J. Usado seguinte para detectar emulador: github.com/gingo/android-emulator-detector
bluetoothfx
3

Na verdade, ANDROID_ID em 2.2 sempre é igual a 9774D56D682E549C (de acordo com este tópico + minhas próprias experiências).

Então, você pode verificar algo como isto:

String androidID = ...;
if(androidID == null || androidID.equals("9774D56D682E549C"))
    do stuff;

Não é a mais bonita, mas faz o trabalho.

Eric Eijkelenboom
fonte
8
Eu seria cuidadoso com isso por causa desse bug horrível: code.google.com/p/android/issues/detail?id=10603
Brandon O'Rourke em
3

Isso funciona para mim

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
fonte
3
o engenheiro de firmware que temos internamente não atualizou isso; obter o Build.Manufacturer em nosso hardware retornou "desconhecido". A impressão digital parece ser uma maneira melhor.
Alguém em algum lugar
3

Coloque um arquivo no sistema de arquivos do emulador; como o arquivo não existe no dispositivo real, ele deve ser estável, confiável e fácil de corrigir quando quebrar.

Aaron Digulla
fonte
3

Reuni todas as respostas sobre esta questão e criei uma função para detectar se o Android está sendo executado em um vm / emulator:

public boolean isvm(){


        StringBuilder deviceInfo = new StringBuilder();
        deviceInfo.append("Build.PRODUCT " +Build.PRODUCT +"\n");
        deviceInfo.append("Build.FINGERPRINT " +Build.FINGERPRINT+"\n");
        deviceInfo.append("Build.MANUFACTURER " +Build.MANUFACTURER+"\n");
        deviceInfo.append("Build.MODEL " +Build.MODEL+"\n");
        deviceInfo.append("Build.BRAND " +Build.BRAND+"\n");
        deviceInfo.append("Build.DEVICE " +Build.DEVICE+"\n");
        String info = deviceInfo.toString();


        Log.i("LOB", info);


        Boolean isvm = false;
        if(
                "google_sdk".equals(Build.PRODUCT) ||
                "sdk_google_phone_x86".equals(Build.PRODUCT) ||
                "sdk".equals(Build.PRODUCT) ||
                "sdk_x86".equals(Build.PRODUCT) ||
                "vbox86p".equals(Build.PRODUCT) ||
                Build.FINGERPRINT.contains("generic") ||
                Build.MANUFACTURER.contains("Genymotion") ||
                Build.MODEL.contains("Emulator") ||
                Build.MODEL.contains("Android SDK built for x86")
                ){
            isvm =  true;
        }


        if(Build.BRAND.contains("generic")&&Build.DEVICE.contains("generic")){
            isvm =  true;
        }

        return isvm;
    }

Testado em emulador, Genymotion e Bluestacks (1 de outubro de 2015).

CONvid19
fonte
3

Qualquer que seja o código que você usa para fazer a detecção de emulador, eu recomendo escrever testes de unidade para cobrir todas as Build.FINGERPRINT, Build.HARDWAREe Build.MANUFACTURERvalores que você está dependendo. Aqui estão alguns exemplos de testes:

@Test
public void testIsEmulatorGenymotion() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic/vbox86p/vbox86p:4.1.1/JRO03S/eng.buildbot.20150217.102902:userdebug/test-keys",
                    "vbox86", "Genymotion")).isTrue();

    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic/vbox86p/vbox86p:5.1/LMY47D/buildbot06092001:userdebug/test-keys", "vbox86",
                    "Genymotion")).isTrue();
}

@Test
public void testIsEmulatorDefaultAndroidEmulator() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic_x86/sdk_google_phone_x86/generic_x86:5.0.2/LSY66H/1960483:eng/test-keys", "goldfish",
                    "unknown")).isTrue();

    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/2469028:userdebug/test-keys",
                    "ranchu", "unknown")).isTrue();
}

@Test
public void testIsEmulatorRealNexus5() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator("google/hammerhead/hammerhead:6.0.1/MMB29K/2419427:user/release-keys",
                    "hammerhead", "LGE")).isFalse();
}

... e aqui está o nosso código (logs de depuração e comentários removidos por concisão):

public static boolean isRunningOnEmulator() {
    if (sIsRunningEmulator == null) {
        sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER);
    }

    return sIsRunningEmulator;
}

static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
    boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
    boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
            || manufacturer.equals("unknown");

    if (isEmulatorFingerprint && isEmulatorManufacturer) {
        return true;
    } else {
        return false;
    }
}
Dan J
fonte
2

Como o mecanismo de emulação subjacente do Genymotion é o VirtualBox e isso não mudará tão cedo, achei o código a seguir mais confiável:

   public static boolean isGenymotion() {
        return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
Nati Dykstein
fonte
2

Outra opção é verificar se você está no modo de depuração ou modo de produção:

if (BuildConfig.DEBUG) { Log.i(TAG, "I am in debug mode"); }

simples e confiável.

Não é totalmente a resposta da pergunta, mas na maioria dos casos você pode distinguir entre sessões de depuração / teste e sessões de vida da sua base de usuários.

No meu caso, defino o google analytics como dryRun () quando no modo de depuração, para que essa abordagem funcione totalmente bem para mim.


Para usuários mais avançados, há outra opção. variantes de construção gradle:

no arquivo de classificação do seu aplicativo, adicione uma nova variante:

buildTypes {
    release {
        // some already existing commands
    }
    debug {
        // some already existing commands
    }
    // the following is new
    test {
    }
}

No seu código, verifique o tipo de compilação:

if ("test".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Test build type"); }
 else if ("debug".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Debug build type"); }

Agora você tem a oportunidade de criar três tipos diferentes de seu aplicativo.

microfones
fonte