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

313

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

Джо Людвиг
источник
2
Могу взглянуть на android.os.Build.
Янченко
11
Удивите меня ... У Google должен быть стандартный способ сделать это?
powder366
@ kreker с чем сталкиваются в существующих решениях?
Хемрай
@ Khemraj проблемы мошенничества. Злой парень может издеваться над некоторыми датчиками и менять струны, притворяясь реальным устройством
kreker

Ответы:

159

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

    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

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

Вот небольшой фрагмент, который вы можете сделать в APK, чтобы показать различные вещи, чтобы вы могли добавить свои собственные правила:

        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"
разработчик Android
источник
9
Именно так Facebook обнаруживает эмуляторы в React-Native
Vaiden
Это то, что я должен был обновить после использования ответа от @Aleadam в течение некоторого времени (он перестал работать для меня).
ckbhodge
@Sid Что нужно добавить для этого?
Android-разработчик
2
@Sid Вы печатали там различные переменные класса Build? Ничего особенного не кажется? Вы пробовали это: github.com/framgia/android-emulator-detector ?
Android-разработчик
1
@DrDeo Вы можете добавить проверку текущей сборки с помощью BuildConfig.DEBUG или создать свою собственную сборку со своей собственной пользовательской переменной. Вы также можете использовать Proguard, чтобы эта функция всегда возвращала false или что-то еще (например, вы можете удалить журналы, как показано здесь: medium.com/tixdo-labs/… , так что, возможно, это тоже возможно)
разработчик Android
118

Один общий кажется Build.FINGERPRINT.contains("generic")

Aleadam
источник
Это работает даже с Galaxy Tab Emulator. Топ понравившегося ответа не сделал.
BufferStack
10
Пожалуйста, укажите, является ли отпечаток, содержащий «универсальный», эмулятором или устройством. Эта информация является ключевой, но не предоставляется.
Джеймс Кэмерон
2
Эмулятор - судя по комментариям перед вашими :)
Дори
8
Это возвращает true на моих устройствах под управлением CyanogenMod, так что будьте осторожны.
ardevd
8
Документация Android говорит, что вы не должны пытаться интерпретировать FINGERPRINTзначение.
gnuf
64

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

"google_sdk".equals( Build.PRODUCT );
Маркус
источник
35
Любому, кто читает это, может быть интересно узнать, что эта строка изменилась на «sdk», а не на «google_sdk».
Даниэль Слооф
15
@Daniel: я использую 2.3.3 с Google API, и он говорит "google_sdk". Похоже, это "google_sdk" для AVD с Google API и "sdk" для обычных.
Рэнди Сугианто «Юку»
3
Эмулятор Intel возвращает «full_x86», поэтому я бы не стал рассчитывать на этот метод.
user462982
3
@GlennMaynard Обратная форма уродлива, но практична: Build.PRODUCT может быть нулевым, тогда как «google_sdk» - нет, поэтому эта форма позволяет избежать потенциальной ошибки нулевой ссылки.
Руперт Роунсли
4
Включая больше случаев: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Альберто Алонсо Руибал
31

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

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

Виталий
источник
Да. В отличие от Build.PRODUCT, Build.HARDWARE (золотая рыбка) одинаков для официальных SDK и AOSP. До API 8, однако, вы должны использовать отражение, чтобы добраться до поля HARDWARE.
Дэвид Чендлер
4
Я бы пошел сisEmulator = Build.HARDWARE.contains("golfdish")
Холмс
7
@ Holmes: опечатка, S / B "Золотая рыбка"
Ной
7
Для образа Android 5.1 x86_64 (и, возможно, других более поздних 64-битных образов) это будет «ранчу» вместо «золотая рыбка».
варби
29

Google использует этот код в плагине информации об устройстве от Flutter, чтобы определить, является ли устройство эмулятором:

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
источник
20

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

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;

} 
Джефф С
источник
1
Спасибо за этот код. Я проверил, и это работает, хотя копирование длинного ключа отладки может быть болезненным, но это делается только один раз. Это единственное надежное решение, так как все остальные ответы сравнивают некоторую часть информационной строки сборки ОС со статической строкой, и это может и было изменено в версиях Android SDK, а также может быть подделано в пользовательских сборках Android.
ZoltanF
Я думаю, что это единственное надежное решение. Однако ключ отладки может измениться быстрее, чем мы хотим.
Rds
2
Лучший способ сделать это BuildConfig.DEBUG.
Mygod
13

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

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

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

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

Джей Джей Ким
источник
3
Что возвращает устройство без SIM-карты (например, планшета)?
Rds
Запуск эмулятора для Android 2.1. Этот код работал для меня, но после обновления Cordova до 2.7.0 переменная Context, похоже, не определена или что-то в этом роде. Вот ошибка, которую я получаю в ADT: «Контекст не может быть преобразован в переменную». Кроме того, согласно приведенному выше комментарию, это НЕ надежный метод (хотя на самом деле я сам его не подводил).
Руставоре
2
@rds Устройства, у которых нет SIM-карты, возвращает пустую строку ("")
JJ Kim
Нет ли способа получить это значение с помощью эмулятора? потому что я хотел бы заблокировать всех пользователей, если у них нет сим-карт.
с-
12

Я попробовал несколько методов, но остановился на немного пересмотренной версии проверки 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;
}

К вашему сведению - я обнаружил, что мой Kindle Fire имеет Build.BRAND = "generic", а на некоторых эмуляторах не было "Android" для оператора сети.

Патрик
источник
11

Для обоих следующих параметров установлено значение "google_sdk":

Build.PRODUCT
Build.MODEL

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

"google_sdk".equals(Build.MODEL)

или

"google_sdk".equals(Build.PRODUCT)
Sileria
источник
При запуске эмулятора x86 в Windows, Build.Product есть sdk_x86.
Эдвард Брей
проверка с помощью PRODUCT не является хорошим выбором, так как она возвращает различные значения из разных эмуляторов
Beeing Jk
10

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

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
SD
источник
3
Почему не просто contains("sdk")? Единственное отличие (кроме быстрого) состоит в том, matches(".*_?sdk_?.*")что если перед символом sdk или после него есть символ, он должен быть подчеркиванием '_', что не так уж важно проверять.
Нулано
9

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

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

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

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

Etherpulse
источник
8

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

 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
источник
7

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

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

Нильс Пипенбринк
источник
Во время запуска системы Android ядро ​​Linux сначала вызывает процесс «init». init читает файлы "/init.rc" и "init.device.rc". «init.device.rc» относится к конкретному устройству, на виртуальном устройстве этот файл называется «init.goldfish.rc».
NET3
7

Вот мое решение (оно работает только в том случае, если вы запускаете веб-сервер на своем компьютере для отладки): я создал фоновую задачу, которая запускается при запуске приложения. Он ищет 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;
}
}

из основной деятельности по созданию:

CheckDebugModeTask checkDebugMode = new CheckDebugModeTask();
checkDebugMode.execute("");
Эяль
источник
7

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

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

Луи Лю
источник
Как вы получаете источник питания и температуру?
разработчик Android
6

Я нашел новый эмулятор 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.

ifeegoo
источник
5

Другой вариант - посмотреть на свойство ro.hardware и посмотреть, установлено ли для него значение goldfish. К сожалению, кажется, что нет простого способа сделать это из Java, но это тривиально из C с помощью property_get () .

Тим Кригер
источник
4
Похоже, это работает от NDK. Включите <sys / system_properties.h> и используйте __system_property_get («ro.hardware», buf), затем проверьте, что buf - «золотая рыбка».
NuSkooler
5

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

Поэтому в настоящее время я переключился на следующее решение, которое до сих пор работает с недостатком, однако вам необходимо установить разрешение на чтение 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
источник
5

Все ответы в одном методе

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
источник
Хороший. init.goldfish.rcсуществует только в эмуляторах; кроме того, это хорошая проверка в дополнение к деталям сборки.
sud007
2
@ sud007 Существует множество устройств с `/init.goldfish.rc, и это приведет к ложным срабатываниям. Например, многие устройства серии Samsung Galaxy.
laalto
@laalto ты был действительно прав. Я узнал об этом позже и извиняюсь, что забыл обновить его здесь.
sud007
Тест-ключи генерирует ложные срабатывания для меня.
Ави Паршан
На каких устройствах они генерируют ложные срабатывания?
Аман Верма
5

Моя рекомендация:

попробуй это с github.

Легко обнаружить эмулятор Android

  • Проверено на реальных устройствах в Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Эмулятор Android
  • Энди 46.2.207.0
  • MEmu play
  • Nox App Player
  • Koplayer
  • .....

Как использовать с примером:

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

                    }
                });
Saeed
источник
4

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

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

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

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

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

Джефф
источник
5
IMEI также может вернуться 0на планшет Android или на телефон без SIM-карты.
Пол Ламмерцма
Мы можем редактировать IMEI на эмуляторе. так что это может не служить цели. Также, начиная с API 29, мы не можем получить доступ к IMEI.
Анант
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

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

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

Я использовал приложение под названием « Android Device Info Share », чтобы проверить это.

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

кандзи
источник
На моем Genymotion, работающем на Mac Build.DEVICE = vbox86p
lxknvlk
4

Проверяя ответы, ни один из них не работал при использовании эмуляторов 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;
}
леон карабчесвкий
источник
1
^ airpair.com/android/posts/… ..
Юша Алеауб
Andy_46.16_48 возвращает «andy» для Build.HARDWARE
Дуг Восс
Привести ложный положительный результат для устройств Samsung серии J. Для определения эмулятора использовалось следующее: github.com/gingo/android-emulator-detector
bluetoothfx
3

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

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

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

Не самая красивая, но она делает свою работу.

Эрик Эйкеленбоом
источник
8
Я был бы осторожен с этим из-за этой ужасной ошибки: code.google.com/p/android/issues/detail?id=10603
Брэндон О'Рурк
3

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

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
источник
3
инженер по прошивке, который у нас есть, не обновил это; Получение Build.Manufacturer на нашем оборудовании вернуло «неизвестно». Отпечаток пальца кажется лучшим способом.
Кто-то где-то
3

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

Аарон Дигулла
источник
3

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

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

CONvid19
источник
3

Какой код вы используете , чтобы сделать обнаружение эмулятора, я настоятельно рекомендую писать юнит - тесты , чтобы охватить все 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;
    }
}
Дэн Дж
источник
2

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

   public static boolean isGenymotion() {
        return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
Нати Дикштейн
источник
2

Другой вариант - проверить, находитесь ли вы в режиме отладки или производственном режиме:

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

просто и надежно.

Не совсем ответ на вопрос, но в большинстве случаев вы можете захотеть провести различие между сеансами отладки / тестирования и сеансами жизни вашей пользовательской базы.

В моем случае я установил для Google Analytics значение DryRun () в режиме отладки, поэтому этот подход работает для меня совершенно нормально.


Для более продвинутых пользователей есть еще один вариант. Варианты сборки Gradle:

в файле Gradle вашего приложения добавьте новый вариант:

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

В вашем коде проверьте тип сборки:

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

Теперь у вас есть возможность создать 3 разных типа вашего приложения.

Майкс
источник