web-dev-qa-db-fra.com

Comment détecter une application Android exécutée dans l'émulateur?

J'aimerais que mon code soit exécuté de manière légèrement différente lors de l'exécution sur l'émulateur par rapport à l'exécution sur un périphérique. (Par exemple, en utilisant 10.0.2.2 au lieu d'une URL publique pour s'exécuter automatiquement sur un serveur de développement.) Quel est le meilleur moyen de détecter le moment où une application Android s'exécute dans le émulateur?

289
Joe Ludwig

Que diriez-vous de cette solution:

public static boolean isEmulator() {
    return 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.MANUFACTURER.contains("Genymotion")
            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
            || "google_sdk".equals(Build.PRODUCT);
}
138
android developer

Un point commun semble être Build.FINGERPRINT.contains("generic")

114
Aleadam

Eh bien Android id ne fonctionne pas pour moi, j'utilise actuellement:

"google_sdk".equals( Build.PRODUCT );
64
Marcus

Sur la base d’allusions d’autres réponses, c’est probablement le moyen le plus robuste:

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

31
Vitali

Que diriez-vous du code ci-dessous pour savoir si votre application a été signée avec la clé de débogage? il ne détecte pas l'émulateur mais cela pourrait fonctionner pour vous?

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;

} 
20
Jeff S

Ce code fonctionne pour moi

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

Si cet appareil n'a pas de carte SIM, il reprend la chaîne vide: ""

Étant donné que Android émulateur renvoie toujours "Android" en tant qu'opérateur de réseau, j'utilise le code ci-dessus.

13
J.J. Kim

J'ai essayé plusieurs techniques, mais j'ai opté pour une version légèrement révisée de la vérification du Build.PRODUCT ci-dessous. Cela semble varier un peu d'un émulateur à l'autre, c'est pourquoi j'ai les 3 vérifications que j'ai actuellement. J'imagine que j'aurais pu vérifier si product.contains ("sdk"), mais que le contrôle ci-dessous était un peu plus sûr.

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 - J'ai constaté que Build.BRAND = "générique" sur mon Kindle Fire et que certains des émulateurs n'avaient pas "Android" pour l'opérateur réseau.

11
Patrick

Les deux éléments suivants sont définis sur "google_sdk":

Build.PRODUCT
Build.MODEL

Il devrait donc être suffisant d’utiliser l’une ou l’autre des lignes suivantes.

"google_sdk".equals(Build.MODEL)

ou

"google_sdk".equals(Build.PRODUCT)
11
Sileria

Je cherche juste _sdk, _sdk_ ou sdk_, ou même simplement sdk partie dans Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
10
S.D.

Je n'ai jamais trouvé un bon moyen de savoir si vous êtes dans l'émulateur.

mais si vous avez juste besoin de détecter si vous êtes dans un environnement de développement, vous pouvez le faire:

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

J'espère que cette aide ....

9
Etherpulse

Voici ma solution (cela ne fonctionne que si vous exécutez un serveur Web sur votre ordinateur de débogage): J'ai créé une tâche en arrière-plan qui démarre au démarrage de l'application. Il cherche http://10.0.2.2 et s'il existe, il modifie un paramètre global (IsDebug) en true. C'est un moyen silencieux de savoir où vous courez.

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 l'activité principale surCreate:

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

Je ne sais pas s'il existe de meilleurs moyens de détecter l'émulateur, mais l'émulateur aura le fichier init.goldfish.rc dans le répertoire racine.

C'est le script de démarrage spécifique à l'émulateur, et il ne devrait pas en être de même sur une version non-émulateur.

7

utiliser cette fonction:

 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;

    }
7
AndroidCrop

Google utilise ce code dans le plugin device-info de Flutter pour déterminer si le périphérique est un émulateur:

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

De la batterie, l'émulateur: La source d'alimentation est toujours un chargeur CA. La température est toujours 0.

Et vous pouvez utiliser Build.Host pour enregistrer la valeur de l'hôte, un émulateur différent ayant une valeur d'hôte différente.

6
Louie Liu

Toutes les réponses en une seule méthode

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

Une autre option serait d'examiner la propriété ro.hardware et de voir si elle est définie sur le poisson rouge. Malheureusement, il ne semble pas y avoir de moyen facile de faire cela à partir de Java, mais c’est trivial à partir de C en utilisant property_get () .

5
Tim Kryger

J'ai trouvé le nouvel émulateur Build.HARDWARE = "ranchu".

Référence: https://groups.google.com/forum/#!topic/Android-emulator-dev/dltBnUW_Hz

Et aussi j’ai trouvé le Android moyen officiel de vérifier si l’émulateur était ou non.Je pense que c’est une bonne référence pour nous.

Depuis Android API niveau 23 [Android 6.0]

package com.Android.internal.util;

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

Nous avons ScreenShapeHelper.IS_EMULATOR pour vérifier si l'émulateur.

Depuis Android API niveau 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");

}

Nous avons Build.IS_EMULATOR pour vérifier si l'émulateur.

La façon dont l’officiel vérifie si l’émulateur n’est pas nouvelle, et peut-être aussi insuffisante, mentionne également les réponses ci-dessus.

Mais cela peut peut-être nous montrer que l'officiel fournira le moyen à l'officiel de vérifier si l'émulateur est ou non.

En utilisant les moyens mentionnés ci-dessus, nous pouvons maintenant utiliser les deux moyens de vérifier si l'émulateur est utilisé.

Comment accéder au paquetage com.Android.internal et à @hide

et attendez l'ouverture officielle du SDK.

5
ifeegoo

Ma recommandation:

essayez this de github.

Détection facile _ de l'émulateur Android

  • Vérifié sur des appareils réels dans une batterie de serveurs ( https://aws.Amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Emulateur Android
  • Andy 46.2.207.0
  • MEmu jouer
  • Nox App Player
  • Koplayer
  • .....

Comment utiliser un exemple:

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

                    }
                });
5
Saeed

La solution suggérée ci-dessus pour vérifier le Android_ID a fonctionné pour moi jusqu'à ce que je mette à jour aujourd'hui les derniers outils SDK publiés avec Android 2.2.

Par conséquent, je suis actuellement passé à la solution suivante qui fonctionne jusqu'à présent avec le désavantage, mais il est nécessaire de définir l'autorisation de lecture 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);
    }
} 
5
Juri

vous pouvez vérifier le numéro IMEI, http://developer.Android.com/reference/Android/telephony/TelephonyManager.html#getDeviceId%28%29

si je me souviens de l'émulateur, ce retour 0. Cependant, il n'y a pas de documentation que je puisse trouver qui garantisse cela. bien que l'émulateur puisse ne pas toujours renvoyer 0, il semble assez sûr qu'un téléphone enregistré ne renverrait pas 0. Que se passerait-il sur un appareil autre qu'un téléphone Android, ou sans carte SIM installée ou qui ne l'est pas ne sont pas actuellement inscrits sur le réseau?

semble que ce serait une mauvaise idée, de dépendre de cela.

cela signifie également que vous devez demander la permission de lire l'état du téléphone, ce qui est mauvais si vous n'en avez pas déjà besoin pour autre chose.

sinon, il y a toujours quelque chose à faire avant que vous ne génériez votre application signée.

4
Jeff
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

Cela devrait retourner vrai si l'application est en cours d'exécution sur un émulateur.

Nous devons faire attention à ne pas détecter tous les émulateurs car il n'y a que plusieurs émulateurs différents. C'est facile à vérifier. Nous devons nous assurer que les périphériques actuels ne sont pas détectés en tant qu'émulateur.

J'ai utilisé l'application appelée " Android Device Info Share " pour vérifier cela.

Sur cette application, vous pouvez voir différents types d'informations sur de nombreux appareils (probablement la plupart des appareils dans le monde; si l'appareil que vous utilisez est absent de la liste, il sera ajouté automatiquement).

4
kanji

J'ai rassemblé toutes les réponses à cette question et mis au point une fonction permettant de détecter si Android est en cours d'exécution sur un vm/émulateur:

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

Testé sur Emulator, Genymotion et Bluestacks (1er octobre 2015).

3
Pedro Lobito

Ça marche pour moi

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
3
jens.riboe

Placez un fichier dans le système de fichiers de l'émulateur. comme le fichier n'existera pas sur le périphérique réel, celui-ci devrait être stable, fiable et facile à corriger en cas de coupure.

3
Aaron Digulla

En fait, Android_ID sur 2.2 est toujours égal à 9774D56D682E549C (selon ce fil + mes propres expériences).

Donc, vous pouvez vérifier quelque chose comme ceci:

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

Pas la plus jolie, mais ça fait le travail.

3
Eric Eijkelenboom

Comme le moteur d'émulation sous-jacent de Genymotion est VirtualBox, cela ne changera pas de sitôt, le code suivant est le plus fiable:

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

Quel que soit le code utilisé pour détecter un émulateur, il est vivement recommandé d'écrire des tests unitaires couvrant toutes les valeurs Build.FINGERPRINT, Build.HARDWARE et Build.MANUFACTURER dont vous dépendez. Voici quelques exemples de tests:

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

... et voici notre code (journaux de débogage et commentaires supprimés pour plus de concision):

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;
    }
}
2
Dan J

Vérification des réponses, aucune d’entre elles n’a fonctionné avec les émulateurs LeapDroid, Droid4x ou Andy,

Ce qui fonctionne pour tous les cas est le suivant:

 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;
}
2
leon karabchesvky

Une autre option consiste à vérifier si vous êtes en mode débogage ou en mode production:

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

simple et fiable.

Pas tout à fait la réponse à la question, mais dans la plupart des cas, vous voudrez peut-être distinguer les sessions de débogage/test des sessions de la vie de votre base d’utilisateurs.

Dans mon cas, je règle dryRun () sur Google Analytics en mode débogage pour que cette approche fonctionne parfaitement pour moi.


Pour les utilisateurs plus avancés, il existe une autre option. Variantes de construction:

dans le fichier de notation de votre application, ajoutez une nouvelle variante:

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

Dans votre code, vérifiez le type de construction:

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

Vous avez maintenant la possibilité de créer 3 types différents de votre application.

1
mikes
if ("sdk".equals( Build.PRODUCT )) {
 // Then you are running the app on the emulator.
        Log.w("MyAPP", "\n\n  Emulator \n\n"); 
}
1
Abhishek Bedi
if (Build.BRAND.equalsIgnoreCase("generic")) {
    // Is the emulator
}

Toutes les références BUILD sont des valeurs build.prop. Par conséquent, vous devez tenir compte du fait que si vous voulez inclure cela dans le code de version, vous pouvez avoir certains utilisateurs avec root qui ont modifié leur code pour une raison quelconque. Il n’existe virtuellement aucune modification nécessitant l’utilisation de générique comme marque, à moins d’essayer spécifiquement d’émuler l’émulateur.

Fingerprint est la compilation de compilation et la signature de compilation du noyau. Il existe des versions qui utilisent générique, généralement directement à partir de Google.

Sur un périphérique qui a été modifié, l'IMEI peut également être mis à zéro, ce qui est peu fiable, sauf si vous bloquez complètement les périphériques modifiés.

Goldfish est la base Android à partir de laquelle tous les autres appareils sont étendus. CHAQUE APPAREIL Android a un init.goldfish.rc sauf s’il a été piraté et retiré pour des raisons inconnues.

1
Abandoned Cart

Cela a fonctionné pour moi au lieu de startsWith: Build.FINGERPRINT.contains("generic")

Pour plus de vérifier ce lien: https://Gist.github.com/espinchi/168abf054425893d86d1

0
imsrgadich