Як я можу виявити, коли в емуляторі працює програма Android?


313

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


2
Ви можете подивитися android.os.Build.
Янченко

11
Дивуй мене ... У Google повинен бути стандартний спосіб зробити це?
порошок366

@kreker Що таке питання, з яким ви стикаєтесь у існуючих рішеннях?
Хемрайдж

@Hhemraj шахрайства. Злий хлопець може знущатися над датчиками та змінювати деякі струни, щоб зробити вигляд справжнього пристрою
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"

9
Ось так Facebook виявляє емулятори в React-Native
Vaiden

Це те, що мені довелося оновити після використання відповіді від @Aleadam протягом деякого часу (для мене це перестало працювати).
ckbhodge

@Sid Що слід додати до цього?
андроїд розробник

2
@Sid Ви надрукували там різні змінні класу Build? Нічого не здається особливим? Ви пробували це: github.com/framgia/android-emulator-detector ?
андроїд розробник

1
@DrDeo Ви можете додати перевірку поточної збірки за допомогою BuildConfig.DEBUG або створити власну збірку за допомогою власної власної змінної. Ви також можете використовувати Proguard для того, щоб ця функція завжди повертала помилкове або щось подібне (ви можете видалити журнали, наприклад, як показано тут: medium.com/tixdo-labs/… , тому, можливо, це теж можливо)
андроїд розробник

118

Одна загальна сім'я бути Build.FINGERPRINT.contains("generic")


Це працює навіть з емулятором Galaxy Tab. Відповідь у верхній частині сподобався не.
BufferStack

10
Будь ласка, вкажіть, чи відбиток пальців, що містить "generic", є емулятором чи пристроєм. Ця інформація є ключовою, але не надається.
Джеймс Кемерон

2
Емулятор - судячи з коментарів перед вашими :)
Дорі

7
Це повертається правдою на моїх пристроях, на яких працює CyanogenMod, так що будьте обережні.
ardevd

8
Документація на Android говорить, що не слід намагатися інтерпретувати FINGERPRINTзначення.
gnuf

64

Ну андроїд ідентифікатор для мене не працює, я зараз використовую:

"google_sdk".equals( Build.PRODUCT );

35
Кожному, хто читає це, може бути цікаво знати, що ця рядок, схоже, змінилася на 'sdk', а не на 'google_sdk'.
Даніель Слоуф

15
@Daniel: я використовую 2.3.3 з API Google, і він говорить "google_sdk". Здається, що це "google_sdk" для AVD з API Google і "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")
holmes

7
@holmes: typo, s / b "золота рибка"
Ной

7
Для зображення Android 5.1 x86_64 (і, мабуть, інших останніх 64-бітних зображень), яке було б "ранчу" замість "золотої рибки".
warbi

28

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

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
}

Якщо на пристрої немає сім-картки, він повертає порожній рядок: ""

Оскільки емулятор Android завжди встановлює "Android" як мережевий оператор, я використовую наведений вище код.


3
Що повертає пристрій без SIM-картки (наприклад, планшетний ПК)?
rds

Запуск емулятора для Android 2.1. Цей код працював для мене, але оскільки оновлення Кордови до 2.7.0, змінна Context виявляється невизначеною або щось таке. Ось помилка, яку я отримую в ADT: "Контекст неможливо вирішити до змінної." Крім того, згідно з коментарями вище, це НЕ є надійним методом (хоча я сам насправді не мав цього).
Руставоре

2
@rds Пристрої, на яких немає SIM-картки, повертають порожню рядок ("")
JJ Kim

Чи немає способу мати це значення за допомогою емулятора? тому що я хотів би заблокувати всіх користувачів, якщо у них немає сим-карт.
c-an

11

Обидва наведені нижче встановлені на "google_sdk":

Build.PRODUCT
Build.MODEL

Тож має бути достатньо використовувати будь-який з наступних рядків.

"google_sdk".equals(Build.MODEL)

або

"google_sdk".equals(Build.PRODUCT)

Під час запуску емулятора x86 у Windows, Build.Product є sdk_x86.
Едвард Брей

перевірка за допомогою PRODUCT не є вдалим вибором, оскільки вона повертає різні значення різних емуляторів
Beeing Jk

11

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


10

Я просто шукаю _sdk, _sdk_або sdk_, або навіть просто беру sdkучасть у Build.PRODUCT:

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

3
Чому б не просто contains("sdk")? Єдина відмінність (за винятком того, що це швидше) полягає в тому, matches(".*_?sdk_?.*")що, якщо є символ перед або після sdk, він повинен бути підкресленням '_', що не все так важливо, щоб перевірити.
Нулано

9

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

але якщо вам просто потрібно виявити, якщо ви перебуваєте в середовищі розробки, ви можете це зробити:

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

Сподіваюся, що це допоможе ....


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;

    }

7

Не знаю, чи є кращі способи виявити ему, але емулятор матиме файл init.goldfish.rc у root-каталозі.

Це специфічний для запуску скрипт для емулятора, і він не повинен бути там у складі неемулятора.


Під час запуску системи 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;
}
}

від основної діяльності onCreate:

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

7

Емулятор: від джерела живлення завжди є зарядний пристрій змінного струму. Температура завжди 0.

І ви можете використовувати Build.HOSTдля запису значення хоста, різний емулятор має різне значення хосту.


Як ви отримуєте джерело живлення та температуру?
андроїд розробник

5

Іншим варіантом було б подивитися властивість ro.hardware і побачити, чи встановлено його золоту рибку. На жаль, здається, що це не простий спосіб зробити це з 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);
    }
} 

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

Хороший. init.goldfish.rcіснує лише в емуляторах; це також хороша перевірка вперед, крім деталей збірки.
sud007

2
@ sud007 Існує багато пристроїв із `/init.goldfish.rc, і це призведе до помилкових позитивних результатів. Наприклад, багато пристроїв серії Samsung Galaxy.
laalto

@laalto ти насправді мав рацію. Пізніше я це виявив і вибачте, що забув оновити його тут.
sud007

тест-ключі генерують помилкові позитиви для мене.
Аві Паршан

На яких пристроях вони генерують помилкові позитиви?
Аман Верма

5

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


5

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

спробуйте це з github.

Легко виявити емулятор Android

  • Перевірено на реальних пристроях у Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Генімоція
  • Android-емулятор
  • Енді 46.2.207.0
  • MEmu грати
  • Програвач Nox App
  • Коплаєр
  • .....

Як використовувати приклад:

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

                    }
                });

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

Це має повернути істину, якщо додаток працює на емуляторі.

Що ми повинні бути обережні, це не виявити всіх емуляторів, оскільки є лише кілька різних емуляторів. Це легко перевірити. Ми повинні переконатися, що фактичні пристрої не виявляються як емулятор.

Я перевірив це за допомогою програми під назвою " Поділитися інформацією про пристрої Android ".

У цьому додатку ви можете бачити різного роду інформацію про багато пристроїв (можливо, більшість пристроїв у світі; якщо пристрій, який ви використовуєте, відсутній у списку, він буде доданий автоматично).


На моєму Genymotion, що працює на Mac Build.DEVICE = vbox86p
lxknvlk

3

Насправді ANDROID_ID на 2.2 завжди дорівнює 9774D56D682E549C (відповідно до цієї теми + мої власні експерименти).

Отже, ви можете перевірити щось подібне:

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

Не найкрасивіший, але це робить свою роботу.


8
Я буду з цим обережним через цю жахливу помилку: code.google.com/p/android/isissue/detail?id=10603
Брендон О'Рурк

3

Це працює для мене

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

3
інженер мікропрограмного забезпечення, який у нас є, не оновив це; отримання Build.Manufacturer на нашому апаратному забезпеченні повернулося "невідомо". Відбиток пальців здається кращим способом.
Хтось десь

3

Помістіть файл у файлову систему емулятора; оскільки файл не буде існувати на реальному пристрої, він повинен бути стабільним, надійним та легким для виправлення при поломці.


3

Я зібрав усі відповіді на це питання і придумав функцію виявлення, чи Android працює на vm / емуляторі:

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


3

Перевіряючи відповіді, жоден з них не працював під час використання емуляторів LeapDroid, Droid4x чи Енді,

Що працює у всіх випадках:

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


Andy_46.16_48 повертає "andy" для Build.HARDWARE
Doug Voss

Помилковий позитивний пристрій серії Samsung J. Застосовується наступне для виявлення емулятора: github.com/gingo/android-emulator-detector
bluetoothfx

2

Оскільки основним двигуном емуляції для Genymotion є VirtualBox, і це скоро не зміниться, я знайшов наступний код найбільш надійним:

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

2

Які символи ви використовуєте , щоб зробити виявлення емулятора, я настійно рекомендую писати юніт - тести , щоб охопити всі 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

Інший варіант - перевірити, чи перебуваєте ви в режимі налагодження чи режимі виробництва:

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 різних типи вашої програми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.