¿Cómo puedo detectar cuando una aplicación de Android se está ejecutando en el emulador?

313

Me gustaría que mi código se ejecute de manera ligeramente diferente cuando se ejecute en el emulador que cuando se ejecute en un dispositivo. ( Por ejemplo , usando 10.0.2.2 en lugar de una URL pública para ejecutar automáticamente en un servidor de desarrollo). ¿Cuál es la mejor manera de detectar cuándo una aplicación de Android se ejecuta en el emulador?

Joe Ludwig
fuente
2
Podría echar un vistazo android.os.Build.
Yanchenko
11
Sorprendeme ... Google debería tener una forma estándar de hacer esto?
powder366
@kreker, ¿cuál es el problema que enfrenta en las soluciones existentes?
Khemraj
@Khemraj problemas de fraude. Chico mal puede burlarse de algunos sensores y cambiar algunos hilos para fingir verdadero dispositivo
kreker

Respuestas:

159

¿Qué tal esta solución?

    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

Tenga en cuenta que algunos emuladores falsifican especificaciones exactas de dispositivos reales, por lo que puede ser imposible detectarlo.

Aquí hay un pequeño fragmento que puede hacer en el APK para mostrar varias cosas al respecto, para que pueda agregar sus propias reglas:

        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"
desarrollador de Android
fuente
99
Así es como Facebook detecta los emuladores en React-Native
Vaiden
Esto es lo que tuve que actualizar después de usar la respuesta de @Aleadam durante bastante tiempo (dejó de funcionar para mí).
ckbhodge
@Sid ¿Qué se debe agregar para ello?
Desarrollador de Android
2
@Sid ¿Ha impreso varias variables de clase de construcción allí? ¿Nada parece especial? ¿Has probado esto: github.com/framgia/android-emulator-detector ?
Desarrollador de Android
1
@DrDeo Puede agregar una verificación de la compilación actual usando BuildConfig.DEBUG, o crear su propia compilación con su propia variable personalizada. También puede usar Proguard para hacer que esta función siempre devuelva falso, o algo así (puede eliminar registros, por ejemplo, como se muestra aquí: medium.com/tixdo-labs/… , así que tal vez eso también sea posible)
desarrollador de Android
118

Uno común parece ser Build.FINGERPRINT.contains("generic")

Aleadam
fuente
Esto funciona incluso con Galaxy Tab Emulator. La respuesta que más le gustó no.
BufferStack
10
Indique si una huella digital que contiene "genérico" es un emulador o el dispositivo. Esa información es clave pero no se proporciona.
James Cameron
2
Emulador - a juzgar por los comentarios antes que los tuyos :)
Dori
8
Esto se cumple en mis dispositivos que ejecutan CyanogenMod, así que tenga cuidado.
ardevd
8
La documentación de Android dice que no debe intentar interpretar el FINGERPRINTvalor.
gnuf
64

Bueno, la identificación de Android no funciona para mí, actualmente estoy usando:

"google_sdk".equals( Build.PRODUCT );
Marcus
fuente
35
Cualquiera que lea esto puede estar interesado en saber que esta cadena parece haber cambiado a 'sdk', en lugar de 'google_sdk'.
Daniel Sloof
15
@Daniel: uso 2.3.3 con la API de Google y dice 'google_sdk'. Parece que es 'google_sdk' para AVD con API de Google y 'sdk' para los normales.
Randy Sugianto 'Yuku'
3
El emulador de Intel devuelve "full_x86" para que no cuente con este método.
user462982
3
@GlennMaynard La forma inversa es fea, pero práctica: Build.PRODUCT podría ser nulo mientras que "google_sdk" no puede, por lo tanto, esta forma evita un posible error de referencia nula.
Rupert Rawnsley
44
Incluyendo más casos: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Alberto Alonso Ruibal
31

Según las sugerencias de otras respuestas, esta es probablemente la forma más sólida:

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

Vitali
fuente
Si. A diferencia de Build.PRODUCT, Build.HARDWARE (goldfish) es el mismo para el SDK y AOSP oficiales. Sin embargo, antes de API 8, debe usar la reflexión para acceder al campo HARDWARE.
David Chandler
44
Me gustaría ir conisEmulator = Build.HARDWARE.contains("golfdish")
Holmes
77
@holmes: error tipográfico, s / b "goldfish"
Noah
77
Para la imagen Android 5.1 x86_64 (y probablemente otras imágenes más recientes de 64 bits) que sería "ranchu" en lugar de "goldfish".
warbi
28

Google usa este código en el complemento de información del dispositivo de Flutter para determinar si el dispositivo es un 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
fuente
20

¿Qué tal algo como el siguiente código para saber si su aplicación se firmó con la clave de depuración? no detecta el emulador pero podría funcionar para tu 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
fuente
1
Gracias por este código. Lo he comprobado y está funcionando, aldo hacer frente a la clave de depuración larga puede ser doloroso, pero se hace solo una vez. Esta es la única solución confiable , ya que todas las otras respuestas comparan alguna parte de la cadena de información de compilación del sistema operativo con una cadena estática, y esto puede y fue cambiado sobre las versiones de Android SDK, y también puede ser forjado por compilaciones de Android personalizadas.
ZoltanF
Creo que es la única solución confiable. Sin embargo, la clave de depuración puede cambiar más rápido de lo que queremos.
rds
2
Una mejor manera de hacer esto es BuildConfig.DEBUG.
Mygod
13

Este código me funciona

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

En caso de que el dispositivo no tenga tarjeta SIM, vuelve a ejecutar la cadena vacía: ""

Como el emulador de Android siempre vuelve a ejecutar "Android" como operador de red, utilizo el código anterior.

JJ Kim
fuente
3
¿Qué devuelve un dispositivo sin una tarjeta SIM (como una tableta)?
rds
Ejecutando emulador para Android 2.1. Este código funcionaba para mí, pero desde que actualicé Cordova a 2.7.0, la variable Contexto parece no estar definida o algo así. Aquí está el error que recibo en ADT: "El contexto no se puede resolver en una variable". Además, según el comentario anterior, este NO es un método confiable (aunque en realidad no me ha fallado).
Rustavore
2
@rds Los dispositivos que no tienen una tarjeta SIM devuelve una cadena vacía ("")
JJ Kim
¿No hay forma de tener este valor con el emulador? porque me gustaría bloquear a todos los usuarios si no tienen ninguna tarjeta SIM.
c-an
12

Probé varias técnicas, pero me decidí por una versión ligeramente revisada de comprobar Build.PRODUCT como se muestra a continuación. Esto parece variar bastante de un emulador a otro, por eso tengo las 3 comprobaciones que tengo actualmente. Supongo que podría haber verificado si product.contains ("sdk"), pero pensé que la comprobación a continuación era un poco más 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;
}

FYI: descubrí que mi Kindle Fire tenía Build.BRAND = "genérico", y algunos de los emuladores no tenían "Android" para el operador de red.

Patricio
fuente
11

Tanto lo siguiente se establece en "google_sdk":

Build.PRODUCT
Build.MODEL

Por lo tanto, debería ser suficiente para usar cualquiera de las siguientes líneas.

"google_sdk".equals(Build.MODEL)

o

"google_sdk".equals(Build.PRODUCT)
Sileria
fuente
Al ejecutar el emulador x86 en Windows, Build.Product es sdk_x86.
Edward Brey
verificar con PRODUCT no es una buena opción, ya que devuelve varios valores de diferentes emuladores
Beeing Jk
10

Solo busco _sdk, _sdk_o sdk_, o incluso solo sdkparticipo Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
Dakota del Sur
fuente
3
¿Por qué no solo contains("sdk")? La única diferencia (además de ser más rápido) es que matches(".*_?sdk_?.*")requiere que si hay un carácter antes o después de sdk, debe ser un guión bajo '_', que no es tan importante verificar.
Nulano
9

Nunca encontré una buena manera de saber si estás en el emulador.

pero si solo necesita detectar si está en un entorno de desarrollo, puede hacer esto:

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

Espero que esto ayude....

Etherpulse
fuente
8

usa esta función:

 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
fuente
7

No sé si hay mejores formas de detectar el emu, pero el emulador tendrá el archivo init.goldfish.rcen el directorio raíz.

Es el script de inicio específico del emulador, y no debería estar allí en una compilación que no sea un emulador.

Nils Pipenbrinck
fuente
Durante el inicio del sistema Android, el núcleo de Linux primero llama al proceso "init". init lee los archivos "/init.rc" y "init.device.rc". "init.device.rc" es específico del dispositivo, en el dispositivo virtual este archivo se llama "init.goldfish.rc".
NET3
7

Aquí está mi solución (funciona solo si ejecuta un servidor web en su máquina de depuración): he creado una tarea en segundo plano que se inicia cuando se inicia la aplicación. Busca http://10.0.2.2 y, si existe, cambia un parámetro global (IsDebug) a verdadero. Es una forma silenciosa de averiguar dónde está corriendo.

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

de la actividad principal en Crear:

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

Desde la batería, el emulador: la fuente de alimentación es siempre un cargador de CA. La temperatura siempre es 0.

Y puede usar Build.HOSTpara registrar el valor del host, un emulador diferente tiene un valor de host diferente.

Louie Liu
fuente
¿Cómo se obtiene la fuente de energía y la temperatura?
Desarrollador de Android el
6

Encontré el nuevo emulador Build.HARDWARE = "ranchu".

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

Y también encontré la forma oficial de Android de verificar si el emulador o no. Creo que es una buena referencia para nosotros.

Desde Android API Nivel 23 [Android 6.0]

package com.android.internal.util;

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

Tenemos ScreenShapeHelper.IS_EMULATORque verificar si el emulador.

Desde Android API Nivel 24 [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");

}

Tenemos Build.IS_EMULATORque verificar si el emulador.

La forma en que el oficial verifica si el emulador no es nuevo, y tal vez tampoco sea suficiente, también se mencionan las respuestas anteriores.

Pero esto quizás nos muestre que el oficial proporcionará la forma de verificar si el emulador es o no.

Al usar las formas mencionadas anteriormente, en este momento también podemos usar las dos formas para verificar si el emulador.

Cómo acceder al com.android.internalpaquete y@hide

y espere el SDK abierto oficial.

ifeegoo
fuente
5

Otra opción sería mirar la propiedad ro.hardware y ver si está establecida en goldfish. Desafortunadamente, no parece haber una manera fácil de hacer esto desde Java, pero es trivial desde C usando property_get () .

Tim Kryger
fuente
44
Esto parece funcionar desde el NDK. Incluya <sys / system_properties.h> y use __system_property_get ("ro.hardware", buf) luego verifique que buf sea "goldfish".
NuSkooler
5

La solución sugerida anteriormente para verificar si ANDROID_IDfuncionó para mí hasta que actualicé hoy a las últimas herramientas SDK lanzadas con Android 2.2.

Por lo tanto, actualmente cambié a la siguiente solución que funciona hasta ahora con la desventaja de que debes poner el permiso de lectura 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
fuente
5

Todas las respuestas en un solo 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
fuente
Buena esa. init.goldfish.rcsolo existe en emuladores; Además, es un buen control en el futuro, además de los detalles de construcción.
sud007
2
@ sud007 Hay muchos dispositivos con `/init.goldfish.rc y esto conducirá a falsos positivos. Por ejemplo, muchos dispositivos de la serie Samsung Galaxy.
laalto
@laalto estabas realmente en lo correcto. Lo descubrí más tarde y me disculpo por haber olvidado actualizarlo aquí.
sud007
test-keys ha estado generando falsos positivos para mí.
Avi Parshan
¿En qué dispositivos están generando falsos positivos?
Aman Verma
5

Mi recomendación:

prueba esto desde github.

Emulador de Android fácil de detectar

  • Comprobado en dispositivos reales en Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Emulador de Android
  • Andy 46.2.207.0
  • MEmu play
  • Nox App Player
  • Koplayer
  • .....

Cómo usar con un ejemplo:

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

                    }
                });
Saeed
fuente
4

puede consultar el IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

Si recuerdo en el emulador este retorno 0. Sin embargo, no hay documentación que pueda encontrar que lo garantice. aunque el emulador no siempre devuelve 0, parece bastante seguro que un teléfono registrado no devuelva 0. lo que sucedería en un dispositivo Android que no sea un teléfono, o uno sin una tarjeta SIM instalada o una que no esté registrada actualmente en el ¿red?

Parece que sería una mala idea depender de eso.

también significa que necesitará pedir permiso para leer el estado del teléfono, lo cual es malo si no lo necesita para otra cosa.

si no es así, siempre hay algún cambio antes de que finalmente genere su aplicación firmada.

Jeff
fuente
55
Es probable que IMEI también regrese 0en una tableta Android o en un teléfono sin tarjeta SIM.
Paul Lammertsma
Podemos editar IMEI en el emulador. entonces esto puede no servir para el propósito. Además, a partir de API 29 no podemos acceder a IMEI.
Ananth
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

Esto debería volver verdadero si la aplicación se ejecuta en un emulador.

Lo que debemos tener cuidado es no detectar todos los emuladores porque solo hay varios emuladores diferentes. Es fácil de verificar. Tenemos que asegurarnos de que los dispositivos reales no se detecten como un emulador.

Utilicé la aplicación llamada " Compartir información del dispositivo Android " para verificar esto.

En esta aplicación, puede ver varios tipos de información de muchos dispositivos (probablemente la mayoría de los dispositivos en el mundo; si el dispositivo que está utilizando falta en la lista, se agregará automáticamente).

kanji
fuente
En mi Genymotion ejecutándose en una Mac Build.DEVICE = vbox86p
lxknvlk
4

Comprobando las respuestas, ninguna de ellas funcionó al usar emuladores LeapDroid, Droid4x o Andy,

Lo que funciona para todos los casos es lo siguiente:

 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
fuente
1
^ airpair.com/android/posts/…
Yousha Aleayoub
Andy_46.16_48 devuelve "andy" para Build.HARDWARE
Doug Voss
Plomo falso positivo para dispositivos Samsung J series. Se utiliza lo siguiente para detectar el emulador: github.com/gingo/android-emulator-detector
bluetoothfx
3

En realidad, ANDROID_ID en 2.2 siempre es igual a 9774D56D682E549C (de acuerdo con este hilo + mis propios experimentos).

Entonces, podría verificar algo como esto:

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

No es el más bonito, pero hace el trabajo.

Eric Eijkelenboom
fuente
8
Tendría cuidado con eso debido a este horrible error: code.google.com/p/android/issues/detail?id=10603
Brandon O'Rourke
3

Esto funciona para mi

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
fuente
3
el ingeniero de firmware que tenemos internamente no actualizó esto; conseguir Build.Manufactr en nuestro hardware devolvió "desconocido". La huella dactilar parece una mejor manera.
Alguien en algún lugar
3

Poner un archivo en el sistema de archivos del emulador; Como el archivo no existirá en el dispositivo real, debería ser estable, confiable y fácil de arreglar cuando se rompa.

Aaron Digulla
fuente
3

He recopilado todas las respuestas a esta pregunta y se me ocurrió una función para detectar si Android se está ejecutando en un vm / emulador:

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

Probado en Emulator, Genymotion y Bluestacks (1 de octubre de 2015).

CONvid19
fuente
3

Cualquiera que sea el código que se utiliza para realizar la detección de emulador, lo recomiendo mucho las pruebas de unidad de escritura para cubrir todo el Build.FINGERPRINT, Build.HARDWAREy Build.MANUFACTURERlos valores que están en función de. Aquí hay algunos ejemplos de pruebas:

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

... y aquí está nuestro código (registros de depuración y comentarios eliminados por concisión):

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

Como el motor de emulación subyacente para Genymotion es VirtualBox y eso no va a cambiar en el corto plazo, el siguiente código me pareció el más confiable:

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

Otra opción es verificar si está en modo de depuración o en modo de producción:

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

Simple y confiable.

No es totalmente la respuesta de la pregunta, pero en la mayoría de los casos es posible que desee distinguir entre sesiones de depuración / prueba y sesiones de vida de su base de usuarios.

En mi caso, configuré google analytics en dryRun () cuando estaba en modo de depuración, por lo que este enfoque funciona totalmente bien para mí.


Para usuarios más avanzados hay otra opción. variantes de construcción de gradle:

en el archivo gradle de su aplicación, agregue una nueva variante:

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

En su código verifique el tipo de compilación:

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

Ahora tienes la oportunidad de crear 3 tipos diferentes de tu aplicación.

Mike
fuente