Comment puis-je détecter le moment où une application Android s'exécute dans l'émulateur?

313

Je voudrais que mon code s'exécute légèrement différemment lors de l'exécution sur l'émulateur que lors de l'exécution sur un appareil. ( Par exemple , utiliser 10.0.2.2 au lieu d'une URL publique pour s'exécuter automatiquement sur un serveur de développement.) Quelle est la meilleure façon de détecter lorsqu'une application Android s'exécute dans l'émulateur?

Joe Ludwig
la source
2
Pourrait jeter un oeil à android.os.Build.
yanchenko
11
Etonnez-moi ... Google devrait avoir une façon standard de le faire?
powder366
@kreker quel est le problème auquel vous êtes confronté dans les solutions existantes?
Khemraj
Problèmes de fraude @Khemraj. Un méchant peut se moquer de certains capteurs et changer certaines chaînes pour faire semblant de véritable appareil
kreker

Réponses:

159

Que diriez-vous de cette solution:

    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

Notez que certains émulateurs simulent des spécifications exactes de vrais appareils, il peut donc être impossible de les détecter.

Voici un petit extrait que vous pouvez créer dans l'APK pour montrer diverses choses à ce sujet, afin que vous puissiez ajouter vos propres règles:

        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"
développeur android
la source
9
C'est ainsi que Facebook détecte les émulateurs dans React-Native
Vaiden
C'est ce que j'ai dû mettre à jour après avoir utilisé la réponse de @Aleadam pendant un certain temps (cela a cessé de fonctionner pour moi).
ckbhodge
@Sid Que faut-il y ajouter?
développeur Android
2
@Sid Y avez-vous imprimé diverses variables de classe Build? Rien ne semble spécial? Avez-vous essayé ceci: github.com/framgia/android-emulator-detector ?
développeur Android
1
@DrDeo Vous pouvez ajouter une vérification de la version actuelle à l'aide de BuildConfig.DEBUG, ou créer votre propre version avec votre propre variable personnalisée. Vous pouvez également être en mesure d'utiliser Proguard pour que cette fonction retourne toujours false, ou quelque chose (vous pouvez supprimer des journaux, par exemple, comme indiqué ici: medium.com/tixdo-labs/… , alors peut-être que c'est aussi possible)
développeur Android
118

Un sems commun à être Build.FINGERPRINT.contains("generic")

Aleadam
la source
Cela fonctionne même avec l'émulateur Galaxy Tab. La réponse la plus appréciée ne l'a pas fait.
BufferStack
10
Veuillez indiquer si une empreinte digitale contenant "générique" est un émulateur ou un périphérique. Cette information est essentielle mais non fournie.
James Cameron
2
Emulator - à en juger par les commentaires avant le vôtre :)
Dori
8
Cela revient vrai sur mes appareils exécutant CyanogenMod alors méfiez-vous.
ardevd
8
La documentation Android indique que vous ne devriez pas essayer d'interpréter la FINGERPRINTvaleur.
gnuf
64

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

"google_sdk".equals( Build.PRODUCT );
Marcus
la source
35
Quiconque lit ceci peut être intéressé de savoir que cette chaîne semble avoir changé en "sdk", plutôt qu'en "google_sdk".
Daniel Sloof
15
@Daniel: J'utilise 2.3.3 avec l'API Google et ça dit 'google_sdk'. Il semble que ce soit «google_sdk» pour AVD avec Google API et «sdk» pour les fichiers normaux.
Randy Sugianto 'Yuku'
3
L'émulateur Intel renvoie "full_x86" donc je ne compterais pas sur cette méthode.
user462982
3
@GlennMaynard La forme inverse est moche, mais pratique: Build.PRODUCT peut être nulle alors que "google_sdk" ne peut pas, donc cette forme évite une erreur potentielle de référence nulle.
Rupert Rawnsley
4
Y compris plus de cas: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Alberto Alonso Ruibal
31

Sur la base d'indices provenant d'autres réponses, c'est probablement le moyen le plus robuste:

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

Vitali
la source
Oui. Contrairement à Build.PRODUCT, Build.HARDWARE (poisson rouge) est le même pour le SDK officiel et l'AOSP. Avant l'API 8, vous devez cependant utiliser la réflexion pour accéder au champ HARDWARE.
David Chandler
4
J'irais avecisEmulator = Build.HARDWARE.contains("golfdish")
Holmes
7
@holmes: faute de frappe, s / b "poisson rouge"
Noah
7
Pour l'image Android 5.1 x86_64 (et probablement d'autres images 64 bits plus récentes), ce serait "ranchu" au lieu de "poisson rouge".
warbi
29

Google utilise ce code dans le plugin d'informations sur l' appareil de Flutter pour déterminer si l'appareil 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");
}
Rockney
la source
20

Que diriez-vous de quelque chose comme le 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 votre objectif?

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
la source
1
Merci pour ce code. J'ai vérifié et cela fonctionne, aldo faire face à la longue clé de débogage peut être douloureux mais cela n'est fait qu'une seule fois. Il s'agit de la seule solution fiable , car toutes les autres réponses comparent une partie de la chaîne d'informations de build du système d'exploitation avec une chaîne statique, et cela peut et a été modifié par rapport aux versions du SDK Android, et peut également être falsifié par des builds Android personnalisés.
ZoltanF
Je pense que c'est la seule solution fiable. Cependant, la clé de débogage peut changer plus rapidement que nous le souhaitons.
rds
2
Une meilleure façon de le faire est BuildConfig.DEBUG.
Mygod
13

Ce code fonctionne pour moi

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

Dans le cas où cet appareil ne possède pas de carte SIM, il retape la chaîne vide: ""

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

JJ Kim
la source
3
Que renvoie un appareil sans carte SIM (comme une tablette)?
rds
Émulateur en cours d'exécution pour Android 2.1. Ce code fonctionnait pour moi, mais depuis la mise à niveau de Cordova vers 2.7.0, la variable de contexte semble être indéfinie ou quelque chose. Voici l'erreur que j'obtiens dans ADT: "Le contexte ne peut pas être résolu en une variable." De plus, selon le commentaire ci-dessus, ce n'est PAS une méthode fiable (même si je ne l'ai pas fait échouer moi-même).
Rustavore
2
@rds Devices qui n'a pas de carte SIM renvoie une chaîne vide ("")
JJ Kim
N'y a-t-il aucun moyen d'avoir cette valeur avec l'émulateur? car j'aimerais bloquer tous les utilisateurs s'ils n'ont pas de carte SIM.
c-an
12

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 comme ci-dessous. Cela semble varier un peu d'émulateur en émulateur, c'est pourquoi j'ai les 3 contrôles que j'ai actuellement. Je suppose que j'aurais pu vérifier si product.contains ("sdk") mais j'ai pensé que la vérification ci-dessous était un peu plus sûre.

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

Pour info - j'ai trouvé que mon Kindle Fire avait Build.BRAND = "générique", et certains des émulateurs n'avaient pas "Android" pour l'opérateur réseau.

Patrick
la source
11

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

Build.PRODUCT
Build.MODEL

Il devrait donc suffire d'utiliser l'une des lignes suivantes.

"google_sdk".equals(Build.MODEL)

ou

"google_sdk".equals(Build.PRODUCT)
Sileria
la source
Lors de l'exécution de l'émulateur x86 sous Windows, Build.Product est sdk_x86.
Edward Brey du
vérifier avec PRODUCT n'est pas un bon choix car il renvoie différentes valeurs de différents émulateurs
Beeing Jk
10

Je cherche juste _sdk, _sdk_ou sdk_, ou même simplement je sdkparticipe à Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
Dakota du Sud
la source
3
Pourquoi pas juste contains("sdk")? La seule différence (en plus d'être plus rapide) est que matches(".*_?sdk_?.*"), s'il y a un caractère avant ou après sdk, ce doit être un trait de soulignement «_», ce qui n'est pas si important à vérifier.
Nulano
9

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

Etherpulse
la source
8

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

    }
AndroidCrop
la source
7

Je ne sais pas s'il existe de meilleures façons de détecter l'ému, mais l'émulateur aura le fichier init.goldfish.rcdans le répertoire racine.

Il s'agit du script de démarrage spécifique à l'émulateur, et il ne devrait pas être présent sur une version non émulateur.

Nils Pipenbrinck
la source
Lors du démarrage du système Android, le noyau Linux appelle d'abord le processus "init". init lit les fichiers "/init.rc" et "init.device.rc". "init.device.rc" est spécifique au périphérique, sur le périphérique virtuel ce fichier est appelé "init.goldfish.rc".
NET3
7

Voici ma solution (cela ne fonctionne que si vous exécutez un serveur Web sur votre machine de débogage): J'ai créé une tâche en arrière-plan qui démarre au démarrage de l'application. Il recherche http://10.0.2.2 et s'il existe, il change 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 surCréer:

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

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.HOSTpour enregistrer la valeur d'hôte, un émulateur différent a une valeur d'hôte différente.

Louie Liu
la source
Comment obtenez-vous la source d'alimentation et la température?
développeur Android
6

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

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

Et j'ai aussi trouvé la façon officielle d'Android de vérifier si l'émulateur ou non. Je pense que c'est une bonne référence pour nous.

Depuis Android API Level 23 [Android 6.0]

package com.android.internal.util;

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

Nous devons ScreenShapeHelper.IS_EMULATORvérifier si l'émulateur.

Depuis Android API Level 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 devons Build.IS_EMULATORvérifier si l'émulateur.

La façon dont le fonctionnaire vérifie si l'émulateur n'est pas nouveau, et peut-être pas assez, les réponses ci-dessus sont également mentionnées.

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

En utilisant les méthodes mentionnées ci-dessus, nous pouvons également utiliser les deux méthodes pour vérifier si l'émulateur.

Comment accéder au com.android.internalpackage et@hide

et attendez le SDK ouvert officiel.

ifeegoo
la source
5

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

Tim Kryger
la source
4
Cela semble fonctionner à partir du NDK. Incluez <sys / system_properties.h> et utilisez __system_property_get ("ro.hardware", buf) puis vérifiez que buf est "goldfish".
NuSkooler
5

La solution suggérée ci-dessus pour vérifier le ANDROID_IDfonctionnement 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 l'inconvénient cependant que vous devez mettre 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);
    }
} 
Juri
la source
5

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;
}
XXX
la source
Joli. init.goldfish.rcn'existe que dans les émulateurs; c'est en outre une bonne vérification à venir en plus des détails de construction.
sud007
2
@ sud007 Il existe de nombreux périphériques avec `/init.goldfish.rc et cela entraînera des faux positifs. Par exemple, de nombreux appareils de la série Samsung Galaxy.
laalto
@laalto vous aviez raison. J'ai découvert cela plus tard et je m'excuse d'avoir oublié de le mettre à jour ici.
sud007
test-keys a généré des faux positifs pour moi.
Avi Parshan
Sur quels appareils génèrent-ils des faux positifs?
Aman Verma
5

Ma recommandation:

essayez ceci depuis github.

Émulateur Android facile à détecter

  • Vérifié sur de vrais appareils dans Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Émulateur Android
  • Andy 46.2.207.0
  • MEmu jouer
  • Nox App Player
  • Koplayer
  • .....

Comment utiliser avec un exemple:

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

                    }
                });
Saeed
la source
4

vous pouvez vérifier l'IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

si je me souviens sur l'émulateur ce retour 0. cependant, il n'y a aucune documentation que je puisse trouver qui garantit cela. bien que l'émulateur ne retourne pas toujours 0, il semble assez sûr qu'un téléphone enregistré ne retournera pas 0. ce qui se passerait sur un appareil Android non-téléphone, ou un sans carte SIM installée ou un qui n'est pas actuellement enregistré sur le réseau?

semble que ce serait une mauvaise idée de dépendre de ça.

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

sinon, il y a toujours quelque chose à retourner avant de finalement générer votre application signée.

Jeff
la source
5
IMEI est également susceptible de revenir 0sur une tablette Android ou sur un téléphone sans carte SIM.
Paul Lammertsma
Nous pouvons éditer IMEI sur l'émulateur. donc cela peut ne pas servir le but. De plus, à partir de l'API 29, nous ne pouvons pas accéder à IMEI.
Ananth
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

Cela devrait retourner vrai si l'application s'exécute sur un émulateur.

Ce qu'il faut faire attention, ce n'est 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 appareils réels 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).

kanji
la source
Sur mon Genymotion fonctionnant sur un mac Build.DEVICE = vbox86p
lxknvlk
4

En vérifiant les réponses, aucun d'entre eux n'a fonctionné lors de l'utilisation d'é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;
}
leon karabchesvky
la source
1
^ airpair.com/android/posts/…
Yousha Aleayoub
Andy_46.16_48 renvoie "andy" pour Build.HARDWARE
Doug Voss
Plomb faux positif pour les appareils Samsung série J. Utilisé ci-dessous pour détecter l'émulateur: github.com/gingo/android-emulator-detector
bluetoothfx
3

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 le plus joli, mais ça fait l'affaire.

Eric Eijkelenboom
la source
8
Je serais prudent avec cela à cause de cet horrible bug: code.google.com/p/android/issues/detail?id=10603
Brandon O'Rourke
3

Ça marche pour moi

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
la source
3
l'ingénieur du firmware que nous avons en interne n'a pas mis à jour cela; obtenir Build.Manufacturer sur notre matériel est revenu "inconnu". L'empreinte digitale semble être une meilleure façon.
Quelqu'un Quelque part
3

Mettez un fichier dans le système de fichiers de l'émulateur; puisque le fichier n'existera pas sur le vrai appareil, celui-ci devrait être stable, fiable et facile à réparer lorsqu'il se casse.

Aaron Digulla
la source
3

J'ai rassemblé toutes les réponses à cette question et trouvé une fonction pour détecter si Android fonctionne 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).

CONvid19
la source
3

Quel que soit le code que vous utilisez pour effectuer la détection d'émulateur, je vous recommande fortement d'écrire des tests unitaires pour couvrir tous les Build.FINGERPRINT, Build.HARDWAREet les Build.MANUFACTURERvaleurs 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;
    }
}
Dan J
la source
2

Étant donné que le moteur d'émulation sous-jacent pour Genymotion est VirtualBox et que cela ne changera pas de sitôt, j'ai trouvé le code suivant le plus fiable:

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

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 totalement la réponse à la question mais dans la plupart des cas, vous voudrez peut-être faire la distinction entre les sessions de débogage / test et les sessions de vie de votre base d'utilisateurs.

Dans mon cas, j'ai défini google analytics sur dryRun () en mode débogage, donc cette approche fonctionne parfaitement pour moi.


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

dans le fichier gradle 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 build:

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.

micros
la source