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

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


person Joe Ludwig    schedule 09.05.2010    source источник
comment
Можно взглянуть на android.os.Build.   -  person yanchenko    schedule 10.05.2010
comment
Удивите меня ... У Google должен быть стандартный способ сделать это?   -  person powder366    schedule 11.04.2014
comment
@kreker, в чем проблема, с которой вы сталкиваетесь в существующих решениях?   -  person Khemraj Sharma    schedule 01.10.2018
comment
@Khemraj проблемы с мошенничеством. Злой парень может издеваться над некоторыми датчиками и менять некоторые строки, чтобы притвориться настоящим устройством.   -  person kreker    schedule 02.10.2018


Ответы (39)


Как насчет этого решения (реализация класса SystemProperties доступна здесь):

private var sIsProbablyRunningOnEmulator: Boolean? = null

fun isProbablyRunningOnEmulator(): Boolean {
    var result = sIsProbablyRunningOnEmulator
    if (result != null)
        return result
    // Android SDK emulator
    result = (Build.FINGERPRINT.startsWith("google/sdk_gphone_")
            && Build.FINGERPRINT.endsWith(":user/release-keys")
            && Build.MANUFACTURER == "Google" && Build.PRODUCT.startsWith("sdk_gphone_") && Build.BRAND == "google"
            && Build.MODEL.startsWith("sdk_gphone_"))
            //
            || 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")
            //bluestacks
            || "QC_Reference_Phone" == Build.BOARD && !"Xiaomi".equals(Build.MANUFACTURER, ignoreCase = true) //bluestacks
            || Build.MANUFACTURER.contains("Genymotion")
            || Build.HOST=="Build2" //MSI App Player
            || Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
            || Build.PRODUCT == "google_sdk"
            // another Android SDK emulator check
            || SystemProperties.getProp("ro.kernel.qemu") == "1"
    sIsProbablyRunningOnEmulator = result
    return result
}

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

Вот крошечный фрагмент, который вы можете сделать в 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"
person android developer    schedule 01.02.2014
comment
Так Facebook обнаруживает эмуляторы в React-Native - person Vaiden; 27.01.2016
comment
Это то, что мне пришлось обновить после того, как довольно долго использовал ответ от @Aleadam (у меня он перестал работать). - person ckbhodge; 08.07.2016
comment
@Sid Что для этого нужно добавить? - person android developer; 13.08.2017
comment
Я не очень уверен, много оглядывался, но не смог найти ничего, что точно было бы правильным. Следующий код возвращает BlueStacks при запуске в эмуляторе blustack: android.opengl.GLES20.glGetString (android.opengl.GLES20.GL_RENDERER). Единственное, что мне нужно протестировать на реальных устройствах, чтобы убедиться, что нет ложных срабатываний. Короче говоря, все еще не уверен, ищу дополнительной помощи. - person Sid; 13.08.2017
comment
@Sid Вы распечатали там различные переменные класса сборки? Ничего особенного? Вы пробовали это: github.com/framgia/android-emulator-detector? - person android developer; 13.08.2017
comment
Что остановит меня, как злоумышленника, обмануть ваше приложение и вернуть 0x0 :) - person Dr Deo; 26.12.2017
comment
@DrDeo Вы можете добавить проверку текущей сборки с помощью BuildConfig.DEBUG или создать свою собственную сборку со своей собственной настраиваемой переменной. Вы также можете использовать Proguard, чтобы эта функция всегда возвращала false или что-то в этом роде (вы можете удалить журналы, например, как показано здесь: medium.com/tixdo-labs/, так что, возможно, это тоже возможно) - person android developer; 26.12.2017
comment
Невозможно обнаружить блики 4 - person san88; 06.05.2019
comment
@ san88 Во всяком случае, это не официальный способ. Это просто догадка, эмулятор это или нет. Технически, даже реальное устройство может обмануть эту функцию, отредактировав эти переменные (используя root или пользовательский ROM). Если вы хотите поддержать (и опять же, это только функция предположения) что-то новое, что эта функция не поддерживает, проверьте различные вещи в Build и решите, что лучше всего подходит для вашего случая. Я не могу просто протестировать все текущие приложения-эмуляторы на ПК и будущие и собрать их все. Это непрактично. Я только что получил некоторые из них. - person android developer; 07.05.2019
comment
@KishitaVariya См. Мой предыдущий комментарий по этому поводу. Кроме того, если эмулятор подделывает все, как вы можете проверить, эмулятор это или нет? Во всяком случае, я обновил ответ. Даже если это сработает для вас сегодня, это может не сработать в будущем. - person android developer; 20.11.2019
comment
Для Sony Xperia X (модель F5321) свойство Host возвращает BuildHost, поэтому это условие здесь не работает. - person digitalbreed; 27.03.2021
comment
@digitalbreed Хорошо, я обновил его, чтобы он больше подходил для плеера приложений MSI. Но всегда помните: это ненадежная вещь ... - person android developer; 28.03.2021
comment
Разве не нужно больше скобок вокруг операндов &&? - person Zahra Jamshidi; 09.04.2021
comment
@ZahraJamshidi Вы имеете в виду, что здесь с ними ошибка? - person android developer; 09.04.2021
comment
Я спрашиваю. В строке, в которой вы проверяете QC_Reference_Phone, есть оператор &&. Нужны ли скобки? - person Zahra Jamshidi; 09.04.2021
comment
Чтобы быть более конкретным, || b && c || d неоднозначно. вы имели в виду a || (b && c) || г? - person Zahra Jamshidi; 09.04.2021
comment
@ZahraJamshidi Это не двусмысленно. Есть порядок действий, как в математике. Если вы используете Android Studio, он даже даст вам возможность удалить лишние. Конечно, в сложных случаях их лучше разделить. В моем случае я решил разделить, используя новые строки, когда это возможно, и круглые скобки, когда нет. - person android developer; 09.04.2021
comment
Верно. Я думал о коротком замыкании оператора &&, но заметил, что && имеет более высокий приоритет, чем || Спасибо! - person Zahra Jamshidi; 09.04.2021
comment
@ZahraJamshidi Я думаю, что в каком-то курсе, который я читал в школе / университете, можно было рассматривать && как умножение и || как дополнение. Это помогло понять некоторые правила того, как заставить их выглядеть по-другому, очень похоже на то, как это работает в математике (но немного другие правила). - person android developer; 09.04.2021
comment
Эти методы больше не работают на большинстве эмуляторов, таких как Memu. - person Aman; 09.05.2021
comment
@Aman Я открыт для предложений, что здесь изменить. Как я уже сказал, это может постоянно меняться, никогда нельзя доверять на 100%. Это предположение, основанное на том, что я заметил. Может, для этого надо создать репозиторий на Github? - person android developer; 09.05.2021

Один общий может быть Build.FINGERPRINT.contains("generic")

person Aleadam    schedule 03.05.2011
comment
Это работает даже с эмулятором Galaxy Tab. Самый популярный ответ - нет. - person BufferStack; 30.06.2012
comment
Используя образ Intel для API 10, я получаю Android / full_x86 / generic_x86: 2.3.7 / GINGERBREAD / eng.juntian.20111231.141301: eng / test-keys для этого ... - person user462982; 28.07.2012
comment
Укажите, является ли отпечаток пальца, содержащий универсальный, эмулятором или устройством. Эта информация является ключевой, но не предоставляется. - person James Cameron; 20.06.2013
comment
Эмулятор - судя по комментариям перед вашим :) - person Dori; 31.03.2014
comment
Это вернет истину на моих устройствах с CyanogenMod, так что будьте осторожны. - person ardevd; 12.04.2015
comment
Есть ли какое-нибудь решение, которое также работает с устройствами CyanogenMod? - person Saiteja Parsi; 22.11.2015
comment
В документации Android говорится, что вам не следует пытаться интерпретировать FINGERPRINT значение. - person gnuf; 14.12.2015

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

"google_sdk".equals( Build.PRODUCT );
person Marcus    schedule 15.05.2010
comment
Любой, кто читает это, может быть заинтересован узнать, что эта строка, похоже, изменилась на 'sdk', а не на 'google_sdk'. - person Daniel Sloof; 06.06.2010
comment
@Daniel: я использую 2.3.3 с Google API, и там написано google_sdk. Кажется, что это google_sdk для AVD с Google API и sdk для обычных. - person Randy Sugianto 'Yuku'; 25.04.2011
comment
Это надежный способ решить эту проблему. Наши серверы используют идентификатор устройства, и мы хотим любой ценой предотвратить использование приложения на эмуляторах, поскольку идентификатор устройства можно легко подделать, но я хочу убедиться, что мы не исключаем какие-либо устройства в случае их наличия. которые используют google_sdk или sdk - person Tolga E; 15.01.2012
comment
Эмулятор Intel возвращает full_x86, поэтому я бы не стал рассчитывать на этот метод. - person user462982; 28.07.2012
comment
ITYM Build.PRODUCT.equals (google_sdk). Писать в обратном направлении - значит отличаться только ради этого. @TolgaE: Конечно, нет никакого способа, поскольку все, что вы можете запросить, чтобы увидеть, находитесь ли вы в эмуляторе, эмулятор может лгать. - person Glenn Maynard; 02.07.2013
comment
@GlennMaynard Обратная форма уродлива, но практична: Build.PRODUCT может быть нулевым, тогда как google_sdk не может, поэтому эта форма позволяет избежать потенциальной ошибки нулевой ссылки. - person Rupert Rawnsley; 27.07.2013
comment
Мой эмулятор [intel] использует sdk_x86. - person gdw2; 02.10.2013
comment
sdk_x86 для моего эмулятора. Больше не действует. - person holmes; 02.10.2013
comment
Genymotion использует vbox86p. Решение FINGERPRINT, приведенное ниже, кажется более надежным. - person gdw2; 03.10.2013
comment
Включая другие случаи: google_sdk.equals (Build.PRODUCT) || sdk.equals (Build.PRODUCT) || sdk_x86.equals (Build.PRODUCT) || vbox86p.equals (Build.PRODUCT) - person Alberto Alonso Ruibal; 07.03.2014
comment
My Build.MODEL - это Android SDK, созданный для x86, а Build.PRODUCT - это google_sdk_x86. Я думаю, это случайное недостоверное. - person MERT DOĞAN; 07.02.2018
comment
Я предлагаю для любой переменной Build получить строку типа String product = "" + Build.PRODUCT;, потому что она может быть нулевой, но contains все равно можно использовать, а не equals. Дополнительно используйте toLowercase для сравнения без учета регистра. - person Manuel; 20.05.2019

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");
}
person Rockney    schedule 26.03.2019
comment
Вот ссылка непосредственно на рассматриваемый код: github.com/flutter/plugins/blob/master/packages/device_info/ - person Raman; 14.11.2020
comment
Вот как это делает библиотека crashlytics firebase: public static boolean isEmulator(Context context) { String androidId = Secure.getString(context.getContentResolver(), "android_id"); return "sdk".equals(Build.PRODUCT) || "google_sdk".equals(Build.PRODUCT) || androidId == null; } - person Pepijn; 24.02.2021
comment
Эти методы больше не работают на большинстве эмуляторов, таких как Memu. - person Aman; 09.05.2021

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

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

person Vitali    schedule 11.12.2012
comment
да. В отличие от Build.PRODUCT, Build.HARDWARE (золотая рыбка) одинаков для официального SDK и AOSP. Однако до API 8 вы должны использовать отражение, чтобы получить доступ к полю HARDWARE. - person David Chandler; 26.04.2013
comment
Я бы пошел с isEmulator = Build.HARDWARE.contains("golfdish") - person holmes; 02.10.2013
comment
@holmes: опечатка, золотая рыбка s / b - person Noah; 14.11.2013
comment
Для образа Android 5.1 x86_64 (и, возможно, других более поздних 64-битных образов) это будет ранчо, а не золотая рыбка. - person warbi; 02.09.2016

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

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;

} 
person Jeff S    schedule 01.12.2010
comment
Спасибо за этот код. Я проверил, и он работает, хотя копирование длинного ключа отладки может быть болезненным, но это делается только один раз. Это единственное надежное решение, поскольку все другие ответы сравнивают некоторую часть строки информации о сборке ОС со статической строкой, и это может и было изменено в версиях Android SDK, а также может быть подделано с помощью пользовательского Сборки Android. - person ZoltanF; 19.08.2011
comment
Думаю, это единственно надежное решение. Однако ключ отладки может измениться быстрее, чем мы хотим. - person rds; 26.08.2012
comment
Лучше сделать это BuildConfig.DEBUG. - person Mygod; 15.05.2017

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

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

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

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

person J.J. Kim    schedule 05.07.2011
comment
Что возвращает устройство без сим-карты (например, планшет)? - person rds; 26.08.2012
comment
Запуск эмулятора Android 2.1. Этот код работал у меня, но после обновления Cordova до 2.7.0 переменная Context кажется неопределенной или что-то в этом роде. Вот ошибка, которую я получаю в ADT: контекст не может быть преобразован в переменную. Кроме того, согласно приведенному выше комментарию, это НЕ надежный метод (хотя у меня на самом деле он не выходил из строя). - person Rustavore; 17.05.2013
comment
@rds Devices, у которых нет SIM-карты, возвращает пустую строку () - person J.J. Kim; 12.06.2013
comment
Нет возможности получить это значение с помощью эмулятора? потому что я бы хотел заблокировать всех пользователей, если у них нет сим-карт. - person c-an; 12.11.2019
comment
к сведению, nox не возвращает Android в качестве оператора сети - person John Foong; 14.05.2021

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

person Patrick    schedule 29.11.2012

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

Build.PRODUCT
Build.MODEL

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

"google_sdk".equals(Build.MODEL)

or

"google_sdk".equals(Build.PRODUCT)
person Sileria    schedule 12.09.2011
comment
При запуске эмулятора x86 в Windows Build.Product - sdk_x86. - person Edward Brey; 15.10.2013
comment
проверка с помощью ПРОДУКТА - не лучший выбор, так как она возвращает разные значения из разных эмуляторов. - person Beeing Jk; 12.04.2018

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

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
person S.D.    schedule 23.05.2013
comment
Почему не просто contains("sdk")? Единственное отличие (кроме скорости) состоит в том, что matches(".*_?sdk_?.*") требует, чтобы если до или после sdk есть символ, он должен быть подчеркиванием '_', что не так важно для проверки. - person Nulano; 28.01.2015

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

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

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

Надеюсь на эту помощь ....

person Etherpulse    schedule 14.05.2012

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

 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;

    }
person AndroidCrop    schedule 19.09.2015

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

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

person Nils Pipenbrinck    schedule 09.05.2010
comment
Во время запуска системы Android ядро ​​Linux сначала вызывает процесс init. init читает файлы /init.rc и init.device.rc. init.device.rc зависит от устройства, на виртуальном устройстве этот файл называется init.goldfish.rc. - person NET3; 09.02.2018
comment
Я прочитал здесь другой комментарий stackoverflow: stackoverflow.com/questions/2799097/, что этот файл присутствует на многих реальных устройствах, многих Samsung. Я также вижу это в наших журналах с некоторых устройств Samsung. - person gjgjgj; 01.09.2020

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

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

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

person Louie Liu    schedule 06.11.2015
comment
Как получить источник питания и температуру? - person android developer; 20.11.2019

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

person Tim Kryger    schedule 09.05.2010
comment
Похоже, это работает от NDK. Включите ‹sys / system_properties.h› и используйте __system_property_get (ro.hardware, buf), затем проверьте, что buf - это золотая рыбка. - person NuSkooler; 26.01.2011

Нашел новый эмулятор 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, чтобы проверить, работает ли эмулятор.

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

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

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

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

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

person ifeegoo    schedule 13.05.2017

Выше предложенное решение для проверки 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);
    }
} 
person Juri    schedule 27.05.2010

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

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;
}
person XXX    schedule 14.05.2016
comment
Хороший. init.goldfish.rc существует только в эмуляторах; это также хорошая проверка в будущем в дополнение к деталям сборки. - person sud007; 25.05.2016
comment
@ sud007 Существует много устройств с `/init.goldfish.rc ', и это приводит к ложным срабатываниям. Например, многие устройства серии Samsung Galaxy. - person laalto; 05.01.2018
comment
@laalto, ты был прав. Я узнал об этом позже и извиняюсь, что забыл обновить его здесь. - person sud007; 31.01.2018
comment
test-keys генерировал для меня ложные срабатывания. - person Avi Parshan; 15.11.2018
comment
На каких устройствах они генерируют ложные срабатывания? - person Aman Verma; 22.12.2018


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

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

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

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

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

person kanji    schedule 04.09.2012
comment
На моем Genymotion, запущенном на Mac, Build.DEVICE = vbox86p - person lxknvlk; 16.02.2016

Проверяю ответы, ни один из них не работал при использовании эмуляторов 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;
}
person leon karabchesvky    schedule 06.09.2016
comment
^ airpair.com/android/posts/ - person Yousha Aleayoub; 09.09.2016
comment
Andy_46.16_48 возвращает Andy для Build.HARDWARE - person Doug Voss; 10.02.2017
comment
Провести ложное срабатывание для устройств Samsung серии J. Для обнаружения эмулятора используется следующее: github.com/gingo/android-emulator-detector - person bluetoothfx; 10.07.2018

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

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

похоже, что это было бы плохой идеей, полагаться на это.

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

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

person Jeff    schedule 09.05.2010
comment
IMEI, скорее всего, вернет 0 на планшете Android или на телефоне без SIM-карты. - person Paul Lammertsma; 11.03.2011
comment
Мы можем редактировать IMEI на эмуляторе. так что это может не служить цели. Также, начиная с API 29, мы не можем получить доступ к IMEI. - person Ananth; 16.10.2019

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

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

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

Не самый красивый, но работает.

person Eric Eijkelenboom    schedule 25.11.2010
comment
Я был бы осторожен с этим из-за этой ужасной ошибки: code.google .com / p / android / issues / detail? id = 10603. - person Brandon O'Rourke; 23.02.2011

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

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
person Ribomation    schedule 03.07.2011
comment
наш штатный инженер по прошивке не обновлял это; получение Build.Manufacturer на нашем оборудовании неизвестно. Отпечаток пальца кажется лучшим способом. - person Someone Somewhere; 15.11.2011

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

person Aaron Digulla    schedule 04.09.2012

Я собрал все ответы на этот вопрос и придумал функцию, чтобы определить, работает ли 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 г.).

person Pedro Lobito    schedule 01.10.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;
    }
}
person Dan J    schedule 12.02.2016

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

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 разных типа вашего приложения.

person mikes    schedule 23.02.2017

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

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

if (Build.BRAND.equalsIgnoreCase("generic")) {
    // Is the emulator
}

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

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

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

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

person Abandoned Cart    schedule 22.02.2014

Это сработало для меня вместо startsWith: Build.FINGERPRINT.contains("generic")

Для получения дополнительной информации перейдите по этой ссылке: https://gist.github.com/espinchi/168abf054425893d86d1

person imsrgadich    schedule 18.07.2017

попробуйте эту ссылку с github.

https://github.com/mofneko/EmulatorDetector

Этот модуль поможет вам эмулировать обнаружение вашего Android-проекта, поддерживающего Unity.

Базовая проверка

  • BlueStacks
  • Genymotion
  • Эмулятор Android
  • Nox App Player
  • Koplayer
  • .....
person Saeid Parvizi    schedule 06.03.2020

Рекомендуется проверить, установлены ли на устройстве следующие пакеты:

    mListPackageName.add("com.google.android.launcher.layouts.genymotion");
    mListPackageName.add("com.bluestacks");
    mListPackageName.add("com.vphone.launcher");
    mListPackageName.add("com.bignox.app");

А затем просто сверяйтесь с менеджером пакетов, пока он не найдет его.

private static boolean isEmulByPackage(Context context) {
        final PackageManager pm = context.getPackageManager();
        for (final String pkgName : mListPackageName) {
            return isPackageInstalled(pkgName, pm);
        }
        return false;
    }

private static boolean isPackageInstalled(final String packageName, final PackageManager packageManager) {
    try {
        packageManager.getPackageInfo(packageName, 0);
        return true;
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
}
person Avi Parshan    schedule 14.06.2020

Вот как Firebase Crashlytics подходит к этому:

  public static boolean isEmulator(Context context) {
      final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
      return Build.PRODUCT.contains(SDK)
          || Build.HARDWARE.contains(GOLDFISH)
          || Build.HARDWARE.contains(RANCHU)
          || androidId == null;
  }
person G00fY    schedule 26.03.2021

Чаще всего используется метод сопоставления значений бренда, названия ... и т. Д. Но этот метод является статическим и предназначен для ограниченных версий эмуляторов. Что, если существует более 1000 производителей виртуальных машин? тогда вам нужно будет написать код для сопоставления 1000+ виртуальных машин?

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

Итак, основываясь на моих тестах, я узнал, что getRadioVersion() возвращает пустое значение на виртуальной машине и возвращает номер версии на реальном устройстве Android.

public Boolean IsVM() 
{
    return android.os.Build.getRadioVersion().length() == 0;
} 
//return true if VM
//return false if real

Хотя это работает, но у меня нет официального объяснения этому.

Код: http://github.com/Back-X/anti-vm/blob/main/android/anti-vm.b4a

Выпуск: http://github.com/Back-X/anti-vm/releases/download/1/anti-vm.apk

person Gray Programmerz    schedule 05.04.2021

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

    public static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
    boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
    boolean isHardware = hardware.toLowerCase().contains("intel") || hardware.toLowerCase().contains("vbox");
    boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
            || manufacturer.equals("unknown");

    if (isHardware || isEmulatorFingerprint && isEmulatorManufacturer) {
        return true;
    } else {
        return false;
    }
}
person Javid Sattar    schedule 19.05.2021

Попробуйте воспользоваться этим методом.

Проверено на эмуляторах Google и Genymotion.

public Boolean IsVM() {
    String radioVersion = android.os.Build.getRadioVersion();
    return radioVersion == null || radioVersion.isEmpty() || radioVersion.equals("1.0.0.0");
}
person Yusuph wickama    schedule 03.06.2021

Вы можете проверить, является ли deviceId (IMEI) «000000000000000» (15 нулей)

person SparK    schedule 23.09.2013
comment
Обнаружение должно выполняться без дополнительных разрешений. - person ENSATE; 24.03.2019
comment
Вы больше не можете получить IMEI, начиная с API 29 - person Ananth; 16.10.2019