Как определить, когда приложение Android работает в эмуляторе?

Я бы хотел, чтобы мой код запускался несколько иначе при работе на эмуляторе, чем при работе на устройстве. ( Например , используя 10.0.2.2 вместо общедоступного URL-адреса для автоматического запуска на сервере разработки.) Каков наилучший способ определить, когда приложение Android работает в эмуляторе?

Solutions Collecting From Web of "Как определить, когда приложение Android работает в эмуляторе?"

Один общий Build.FINGERPRINT.startsWith("generic") для Build.FINGERPRINT.startsWith("generic")

Ну Android id не работает для меня, я в настоящее время использую:

 "google_sdk".equals( Build.PRODUCT ); 

Как насчет этого решения:

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

Основываясь на подсказках из других ответов, это, вероятно, самый надежный способ:

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

Как насчет кода, приведенного ниже, чтобы узнать, подписано ли ваше приложение с помощью отладочного ключа? Он не обнаруживает эмулятор, но он может работать для вашей цели?

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

Этот код работает для меня

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

Если у устройства нет сим-карты, он перенастраивает пустую строку: ""

Поскольку эмулятор Android всегда перенастраивает «Android» в качестве оператора сети, я использую код выше.

Для обоих параметров установлено значение «google_sdk»:

 Build.PRODUCT Build.MODEL 

Поэтому должно быть достаточно использовать одну из следующих строк.

 "google_sdk".equals(Build.MODEL) 

или

 "google_sdk".equals(Build.PRODUCT) 

Я попробовал несколько методов, но остановился на слегка пересмотренной версии проверки Build.PRODUCT, как показано ниже. Похоже, что это немного отличается от эмулятора к эмулятору, поэтому у меня есть 3 чека, которые у меня есть. Думаю, я мог бы просто проверить, есть ли product.contains («sdk»), но подумал, что чек ниже был немного безопаснее.

 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 – я обнаружил, что у моего Kindle Fire есть Build.BRAND = «generic», и некоторые из эмуляторов не имеют «Android» для оператора сети.

Я просто ищу _sdk , _sdk_ или sdk_ или даже просто часть sdk в Build.PRODUCT :

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

Я никогда не нашел хороший способ сказать, находитесь ли вы в эмуляторе.

Но если вам просто нужно определить, если вы находитесь в среде разработки, вы можете это сделать:

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

Надеюсь, эта помощь ….

Используйте эту функцию:

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

Не знаю, есть ли лучшие способы обнаружения эму, но у эмулятора будет файл init.goldfish.rc в корневой директории.

Это специальный сценарий запуска эмулятора, и его не должно быть на сборке без эмулятора.

Вот мое решение (оно работает только при запуске веб-сервера на машине отладки): я создал фоновое задание, которое начинается с момента запуска приложения. Он ищет http://10.0.2.2, и если он существует, он изменяет глобальный параметр (IsDebug) на true. Это бесшумный способ узнать, где вы работаете.

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

От основной деятельности onCreate:

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

Другой вариант – посмотреть на свойство ro.hardware и посмотреть, установлен ли его набор на золотую рыбу. К сожалению, похоже, что нет простого способа сделать это с Java, но его тривиально с C, используя свойство_get () .

Вышеупомянутое предлагаемое решение для проверки ANDROID_ID работало для меня, пока я не обновил сегодня до последних инструментов SDK, выпущенных с Android 2.2.

Поэтому в настоящее время я перешел на следующее решение, которое работает до сих пор с недостатком, однако вам нужно установить разрешение на чтение PHONE_STATE ( <uses-permission android:name="android.permission.READ_PHONE_STATE"/> use <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); } } 

Ну, если вы хотите быть хардкором об этом и не использовать какой-либо отпечаток пальца, который можно легко изменить, я видел, как концепции в этом блоге действительно закодированы и работают.

Вы можете проверить IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

Если я вспомню на эмуляторе это возвращение 0. однако, нет никакой документации, я могу найти, что гарантирует это. Хотя эмулятор может не всегда возвращать 0, кажется довольно безопасным, что зарегистрированный телефон не вернет 0. Что произойдет на нетелефонном устройстве Android, либо без установленной SIM-карты, или на том, что в настоящее время не зарегистрировано на сеть?

Похоже, что это будет плохая идея, чтобы зависеть от этого.

Это также означает, что вам нужно будет попросить разрешения на чтение состояния телефона, что плохо, если вы еще не требуете его для чего-то другого.

Если не так, то всегда где-то перевертывается, прежде чем вы, наконец, сгенерируете подписанное приложение.

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

Это должно возвращать true, если приложение работает на эмуляторе.

Мы должны быть осторожны, не обнаруживая всех эмуляторов, потому что есть только несколько разных эмуляторов. Это легко проверить. Мы должны убедиться, что фактические устройства не обнаружены в качестве эмулятора.

Я использовал приложение под названием « Информация об Android-устройстве », чтобы проверить это.

В этом приложении вы можете увидеть различные виды информации многих устройств (возможно, большинство устройств в мире, если используемое вами устройство отсутствует в списке, оно будет добавляться автоматически).

Фактически, ANDROID_ID на 2.2 всегда равен 9774D56D682E549C (согласно этой теме + мои собственные эксперименты).

Итак, вы можете проверить что-то вроде этого:

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

Не самый красивый, но он выполняет эту работу.

Это работает для меня

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

Поместите файл в файловую систему эмулятора; Так как файл не будет существовать на реальном устройстве, он должен быть стабильным, надежным и легко фиксироваться при его разрыве.

Из аккумулятора эмулятор: источником питания всегда является зарядное устройство переменного тока. Температура всегда равна 0.

И вы можете использовать Build.HOST для записи значения хоста, у другого эмулятора есть другое значение хоста.

Все ответы одним способом

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

Все ссылки на BUILD – это значения build.prop, поэтому вы должны учитывать, что если вы собираетесь поместить это в код выпуска, у вас могут быть некоторые пользователи с root, которые по какой-то причине изменили их. Практически никаких модификаций, которые требуют использования универсального бренда, если специально не пытаются имитировать эмулятор.

Fingerprint – это компиляция сборки и компиляция ядра. Существуют сборки, которые используют общие, обычно напрямую полученные от Google.

На устройстве, которое было изменено, IMEI также имеет возможность обнуления, поэтому это ненадежно, если вы вообще не блокируете модифицированные устройства.

Goldfish – это базовая сборка Android, из которой все другие устройства расширены. КАЖДЫЙ Android-устройство имеет init.goldfish.rc, если его не взломали и не удалили по неизвестным причинам.

Я собрал все ответы на этот вопрос и придумал функцию, чтобы определить, работает ли Android на vm / emulator:

 public boolean isvm(){ StringBuilder deviceInfo = new StringBuilder(); deviceInfo.append("Build.PRODUCT " +Build.PRODUCT +"\n"); deviceInfo.append("Build.FINGERPRINT " +Build.FINGERPRINT+"\n"); deviceInfo.append("Build.MANUFACTURER " +Build.MANUFACTURER+"\n"); deviceInfo.append("Build.MODEL " +Build.MODEL+"\n"); deviceInfo.append("Build.BRAND " +Build.BRAND+"\n"); deviceInfo.append("Build.DEVICE " +Build.DEVICE+"\n"); String info = deviceInfo.toString(); Log.i("LOB", info); Boolean isvm = false; if( "google_sdk".equals(Build.PRODUCT) || "sdk_google_phone_x86".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT) || "sdk_x86".equals(Build.PRODUCT) || "vbox86p".equals(Build.PRODUCT) || Build.FINGERPRINT.contains("generic") || Build.MANUFACTURER.contains("Genymotion") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") ){ isvm = true; } if(Build.BRAND.contains("generic")&&Build.DEVICE.contains("generic")){ isvm = true; } return isvm; } 

Испытано на эмуляторе, Genymotion и Bluestacks (1 октября 2015 г.).

Какой бы код вы ни использовали для обнаружения эмулятора, я настоятельно рекомендую писать модульные тесты, чтобы покрыть все значения Build.FINGERPRINT , Build.HARDWARE и Build.MANUFACTURER которые вы в зависимости от. Вот несколько примеров тестов:

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

… и вот наш код (отладочные журналы и комментарии удалены для краткости):

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

Проверяя ответы, ни один из них не работал при использовании эмуляторов LeapDroid, Droid4x или Andy,

Что работает для всех случаев:

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

Я нашел новый эмулятор Build.HARDWARE = "ranchu" .

Ссылка: https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU

А также я нашел официальный способ Android проверить, есть ли эмулятор или нет. Я считаю, что это хорошая ссылка для нас.

Начиная с Android API уровня 23 [Android 6.0]

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

У нас есть ScreenShapeHelper.IS_EMULATOR чтобы проверить, есть ли эмулятор.

Поскольку Android API уровня 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"); } 

У нас есть Build.IS_EMULATOR чтобы проверить, есть ли эмулятор.

То, как должностное лицо проверяет, не является ли эмулятор не новым, а также, возможно, недостаточно, ответы, упомянутые выше, также упоминаются.

Но это может показаться нам, что чиновник предоставит официальному лицу возможность проверить, есть ли эмулятор или нет.

Используя вышеупомянутые способы, мы также можем использовать два способа проверить, есть ли эмулятор.

Как получить доступ к пакету com.android.internal и @hide

И ждать официального открытого SDK.

Поскольку основной эмуляционный движок для Genymotion – VirtualBox, и это не изменится в ближайшее время, я нашел следующий код самым надежным:

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