Je voudrais que mon code fonctionne légèrement différemment lors de l’exécution sur l’émulateur plutôt que sur un périphérique. ( 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 qu’une application Android s’exécute dans l’émulateur?
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); }
Un seul Build.FINGERPRINT.contains("generic")
commun à Build.FINGERPRINT.contains("generic")
Eh bien, l’identifiant Android ne fonctionne pas pour moi, j’utilise actuellement:
"google_sdk".equals( Build.PRODUCT );
Basé sur des indices d’autres réponses, c’est probablement la manière la plus robuste:
isEmulator = "goldfish".equals(Build.HARDWARE)
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 vous?
public void onCreate Bundle b ) { super.onCreate(savedInstanceState); if ( signedWithDebugKey(this,this.getClass()) ) { blah blah blah } blah blah blah } static final Ssortingng 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; }
Ce code fonctionne pour moi
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); Ssortingng networkOperator = tm.getNetworkOperatorName(); if("Android".equals(networkOperator)) { // Emulator } else { // Device }
Au cas où ce périphérique n’aurait pas de carte SIM, il relance la chaîne vide: “”
Étant donné que l’émulateur Android reprend toujours “Android” en tant qu’opérateur de réseau, j’utilise le code ci-dessus.
Les deux 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)
J’ai essayé plusieurs techniques, mais j’ai choisi une version légèrement révisée de la vérification de Build.PRODUCT comme ci-dessous. Cela semble varier un peu de l’émulateur à l’émulateur, c’est pourquoi j’ai les 3 chèques que j’ai actuellement. Je suppose que je pourrais juste vérifier si product.contains (“sdk”) mais pensait que le contrôle ci-dessous était un peu plus sûr.
public static boolean isAndroidEmulator() { Ssortingng model = Build.MODEL; Log.d(TAG, "model=" + model); Ssortingng 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 trouvé que mon Kindle Fire avait Build.BRAND = “générique”, et certains des émulateurs n’avaient pas “Android” pour l’opérateur du réseau.
Je cherche simplement _sdk
, _sdk_
ou sdk_
, ou même juste sdk
partie Build.PRODUCT
dans Build.PRODUCT
:
if(Build.PRODUCT.matches(".*_?sdk_?.*")){ //-- emulator -- }else{ //-- other device -- }
Je n’ai jamais trouvé un bon moyen de savoir si vous êtes dans l’émulateur.
mais si vous avez juste besoin de les 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 ….
Je ne sais pas s’il existe de meilleurs moyens de détecter l’émeu, 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 y en avoir sur une version non émulateur.
Voici ma solution (cela fonctionne uniquement 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 lorsque l’application démarre. 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 { public static boolean IsDebug = false; public CheckDebugModeTask() { } @Override protected Ssortingng doInBackground(Ssortingng... params) { try { HttpParams httpParameters = new BasicHttpParams(); int timeoutConnection = 1000; HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); int timeoutSocket = 2000; HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); Ssortingng 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 (Ssortingng result) { if (result == "Debug") { CheckDebugModeTask.IsDebug = true; } }
de l’activité principale surCréer:
CheckDebugModeTask checkDebugMode = new CheckDebugModeTask(); checkDebugMode.execute("");
Eh bien, si vous voulez être hardcore à ce sujet et ne pas utiliser d’empreintes digitales facilement modifiables, j’ai vu les concepts de cet article de blog coder et fonctionner.
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; }
Une autre option serait de regarder la propriété ro.hardware et voir si elle est définie sur goldfish. Malheureusement, il ne semble pas y avoir de moyen facile de faire cela à partir de Java, mais c’est sortingvial à partir de C en utilisant property_get () .
La solution suggérée ci-dessus pour vérifier le ANDROID_ID
fonctionné pour moi jusqu’à ce que je ANDROID_ID
à 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 que vous devez mettre la permission de lecture PHONE_STATE (
)
private void checkForDebugMode() { ISDEBUGMODE = false; //(Secure.getSsortingng(getApplicationContext().getContentResolver(), Secure.ANDROID_ID) == null); TelephonyManager man = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE); if(man != null){ Ssortingng devId = man.getDeviceSoftwareVersion(); ISDEBUGMODE = (devId == null); } }
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, il renvoie 0. Cependant, il n’y a pas de documentation que je puisse trouver qui le garantisse. Bien que l’émulateur ne retourne pas toujours 0, il semble assez sûr qu’un téléphone enregistré ne renvoie pas 0. Que se passe-t-il sur un appareil Android autre qu’un téléphone ou une carte SIM installée ou non enregistrée sur le téléphone? réseau?
semble être une mauvaise idée, 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 avant de générer votre application signée.
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
Cela devrait retourner true si l’application s’exécute sur un émulateur.
Ce que nous devrions faire attention, c’est de ne pas détecter tous les émulateurs car il n’y a que plusieurs émulateurs différents. Il est facile de vérifier. Nous devons nous assurer que les périphériques 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 le périphérique que vous utilisez est absent de la liste, il sera automatiquement ajouté).
De la batterie, l’émulateur: La source d’alimentation est toujours le chargeur secteur. La température est toujours 0.
Et vous pouvez utiliser Build.HOST
pour enregistrer la valeur de l’hôte, différents émulateur a une valeur d’hôte différente.
Toutes les réponses dans une méthode
static boolean checkEmulator() { try { Ssortingng 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); Ssortingng 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; }
J’ai trouvé le nouvel émulateur Build.HARDWARE = "ranchu"
.
Référence: https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU
Et aussi j’ai trouvé le moyen officiel Android pour vérifier si l’émulateur 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 = getSsortingng("ro.kernel.qemu").equals("1"); }
Nous avons Build.IS_EMULATOR
pour vérifier si l’émulateur.
La manière dont le fonctionnaire vérifie si l’émulateur n’est pas nouveau et peut-être pas assez, les réponses ci-dessus ont également été mentionnées.
Mais cela nous montre peut-être que le fonctionnaire fournira le moyen officiel de vérifier si l’émulateur ou non.
En utilisant toutes les manières mentionnées ci-dessus, nous pouvons maintenant utiliser les deux méthodes pour vérifier si l’émulateur.
Comment accéder au package com.android.internal
et @hide
et attendez le SDK ouvert officiel.
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:
Ssortingng androidID = ...; if(androidID == null || androidID.equals("9774D56D682E549C")) do stuff;
Pas le plus joli, mais ça fait le boulot.
Cela fonctionne pour moi
public boolean isEmulator() { return Build.MANUFACTURER.equals("unknown"); }
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, il devrait être stable, fiable et facile à réparer en cas de panne.
J’ai rassemblé toutes les réponses sur cette question et j’ai mis au point une fonction pour détecter si Android fonctionne sur un vm / émulateur:
public boolean isvm(){ SsortingngBuilder deviceInfo = new SsortingngBuilder(); 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"); Ssortingng info = deviceInfo.toSsortingng(); 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).
if ("sdk".equals( Build.PRODUCT )) { // Then you are running the app on the emulator. Log.w("MyAPP", "\n\n Emulator \n\n"); }
if (Build.BRAND.equalsIgnoreCase("generic")) { // Is the emulator }
Toutes les références à BUILD sont des valeurs de build.prop, vous devez donc considérer que si vous voulez le mettre dans un code de version, il se peut que certains utilisateurs avec root aient modifié les leurs pour quelque raison que ce soit. Il n’y a pratiquement aucune modification nécessitant l’utilisation de génériques en tant que marque, sauf si vous essayez spécifiquement d’émuler l’émulateur.
L’empreinte digitale est la compilation de compilation et la signature de compilation du kernel. Il existe des versions génériques, généralement directement issues de Google.
Sur un périphérique qui a été modifié, l’IMEI peut également être mis à zéro, ce qui n’est pas fiable, sauf si vous bloquez complètement les périphériques modifiés.
Goldfish est la version Android de base à partir de laquelle tous les autres périphériques sont étendus. CHAQUE appareil Android a un init.goldfish.rc à moins que piraté et supprimé pour des raisons inconnues.
Comme le moteur d’émulation sous-jacent de 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"); }
Quel que soit le code que vous utilisez pour la détection de l’émulateur, je vous recommande fortement d’écrire des tests unitaires pour couvrir toutes les Build.FINGERPRINT
, Build.HARDWARE
et Build.MANUFACTURER
dont vous Build.MANUFACTURER
. 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 des raisons de concision):
public static boolean isRunningOnEmulator() { if (sIsRunningEmulator == null) { sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER); } return sIsRunningEmulator; } static boolean isRunningOnEmulator(Ssortingng fingerprint, Ssortingng hardware, Ssortingng manufacturer) { boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys"); boolean isEmulatorManufacturer = manufacturer.equals("Genymotion") || manufacturer.equals("unknown"); if (isEmulatorFingerprint && isEmulatorManufacturer) { return true; } else { return false; } }
En vérifiant les réponses, aucune n’a fonctionné lors de l’utilisation d’émulateurs LeapDroid, Droid4x ou Andy,
Ce qui fonctionne dans tous les cas est le suivant:
private static Ssortingng getSystemProperty(Ssortingng name) throws Exception { Class systemPropertyClazz = Class.forName("android.os.SystemProperties"); return (Ssortingng) systemPropertyClazz.getMethod("get", new Class[]{Ssortingng.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; }