Jak mogę wykryć, kiedy aplikacja emulatora działa w emulatorze?


313

Chciałbym, aby mój kod działał nieco inaczej podczas uruchamiania na emulatorze niż podczas uruchamiania na urządzeniu. ( Na przykład użycie 10.0.2.2 zamiast publicznego adresu URL do automatycznego uruchomienia na serwerze programistycznym.) Jaki jest najlepszy sposób na wykrycie, kiedy aplikacja na Androida działa w emulatorze?


2
Może rzucić okiem android.os.Build.
janchenko

11
Zaskocz mnie ... Google powinien mieć standardowy sposób na zrobienie tego?
proszek366

@kreker, na czym polega problem, który napotykasz w istniejących rozwiązaniach?
Khemraj

@Khemraj problemy z oszustwami. Zły facet może szydzić kilka czujników i zmienić niektóre ciągi udawać prawdziwego urządzenia
kreker

Odpowiedzi:


159

A co z tym rozwiązaniem:

    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

Zwróć uwagę, że niektóre emulatory podają dokładne specyfikacje rzeczywistych urządzeń, więc ich wykrycie może być niemożliwe.

Oto mały fragment, który możesz zrobić w APK, aby pokazać różne rzeczy na jego temat, abyś mógł dodać własne reguły:

        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
W ten sposób Facebook wykrywa emulatory w React-Native
Vaiden

Właśnie to musiałem zaktualizować po dłuższym użyciu odpowiedzi z @Aleadam (przestało to dla mnie działać).
ckbhodge

@Sid Co należy do tego dodać?
programista Androida

2
@Sid Czy wydrukowałeś tam różne zmienne klasy kompilacji? Nic nie wydaje się wyjątkowe? Czy próbowałeś tego: github.com/framgia/android-emulator-detector ?
programista Androida

1
@DrDeo Możesz dodać kontrolę bieżącej kompilacji za pomocą BuildConfig.DEBUG lub utworzyć własną kompilację z własną zmienną niestandardową. Możesz także użyć programu Proguard, aby funkcja zawsze zwracała wartość false lub coś takiego (możesz usunąć dzienniki, na przykład, jak pokazano tutaj: medium.com/tixdo-labs/... , więc może to też możliwe)
programista Androida

118

Wydaje się, że jeden jest powszechny Build.FINGERPRINT.contains("generic")


Działa to nawet z emulatorem Galaxy Tab. Najpopularniejsza odpowiedź nie.
BufferStack

10
Podaj, czy odcisk palca zawierający „rodzajowy” jest emulatorem, czy urządzeniem. Ta informacja jest kluczowa, ale nie podana.
James Cameron,

2
Emulator - sądząc po komentarzach przed twoimi :)
Dori

7
To zwraca prawda na moich urządzeniach z CyanogenMod, więc uważaj.
ardevd

8
Dokumentacja Androida mówi, że nie powinieneś próbować interpretować tej FINGERPRINTwartości.
gnuf

64

No cóż, identyfikator Androida nie działa dla mnie, obecnie używam:

"google_sdk".equals( Build.PRODUCT );

35
Każdy, kto to czyta, może być zainteresowany, aby wiedzieć, że ten ciąg znaków zmienił się na „sdk”, a nie „google_sdk”.
Daniel Sloof,

15
@Daniel: Używam 2.3.3 z Google API i jest napisane „google_sdk”. Wydaje się, że jest to „google_sdk” dla AVD z Google API i „sdk” dla normalnych.
Randy Sugianto 'Yuku'

3
Emulator Intel zwraca „full_x86”, więc nie liczyłbym na tę metodę.
user462982,

3
@GlennMaynard Odwrotna forma jest brzydka, ale praktyczna: Build.PRODUCT może mieć wartość null, podczas gdy „google_sdk” nie może, dlatego ten formularz pozwala uniknąć potencjalnego błędu odniesienia null.
Rupert Rawnsley

4
W tym więcej przypadków: „google_sdk” .equals (Build.PRODUCT) || „sdk” .equals (Build.PRODUCT) || „sdk_x86” .equals (Build.PRODUCT) || „vbox86p” .equals (Build.PRODUCT)
Alberto Alonso Ruibal

31

W oparciu o wskazówki z innych odpowiedzi jest to prawdopodobnie najbardziej niezawodny sposób:

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


Tak. W przeciwieństwie do Build.PRODUCT, Build.HARDWARE (złota rybka) jest taki sam dla oficjalnego SDK i AOSP. Jednak przed API 8 musisz użyć refleksji, aby dostać się do pola SPRZĘT.
David Chandler,

4
Poszedłbym zisEmulator = Build.HARDWARE.contains("golfdish")
holmes

7
@holmes: literówka, s / b „złota rybka”
Noah

7
W przypadku obrazu Androida 5.1 x86_64 (i prawdopodobnie innych nowszych obrazów 64-bitowych) byłoby to „ranchu” zamiast „złota rybka”.
warbi

28

Google używa tego kodu we wtyczce Flutter do informacji o urządzeniu, aby ustalić, czy urządzenie jest emulatorem:

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

Co powiesz na poniższy kod, aby stwierdzić, czy Twoja aplikacja została podpisana za pomocą klucza debugowania? nie wykrywa emulatora, ale może działać w twoim przypadku?

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
Dziękuję za ten kod. Sprawdziłem i działa, aldo kopiowanie długiego klucza debugowania może być bolesne, ale dzieje się to tylko raz. Jest to jedyne niezawodne rozwiązanie, ponieważ wszystkie inne odpowiedzi porównują pewną część ciągu informacyjnego kompilacji systemu operacyjnego ze statycznym ciągiem, i można to zmienić w wersjach zestawu SDK systemu Android, a także można je sfałszować w niestandardowych kompilacjach systemu Android.
ZoltanF

Myślę, że to jedyne niezawodne rozwiązanie. Jednak klucz debugowania może się zmienić szybciej niż chcemy.
rds

2
Lepszym sposobem na to jest BuildConfig.DEBUG.
Mygod

13

Ten kod działa dla mnie

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

W przypadku, gdy urządzenie nie ma karty SIM, resetuje pusty ciąg znaków: „”

Ponieważ emulator Androida zawsze ponownie „Android” jako operator sieci, używam powyższego kodu.


3
Co zwraca urządzenie bez karty SIM (takie jak tablet)?
rds

Uruchamianie emulatora dla Androida 2.1. Ten kod działał dla mnie, ale od czasu uaktualnienia Cordova do wersji 2.7.0 zmienna Context wydaje się być niezdefiniowana lub coś w tym rodzaju. Oto błąd, który otrzymuję w ADT: „Kontekstu nie można rozwiązać na zmienną”. Ponadto, zgodnie z powyższym komentarzem, NIE jest to niezawodna metoda (chociaż sam tak naprawdę nie zawiodłem).
Rustavore

2
@rds Urządzenia, które nie mają karty SIM, zwracają pusty ciąg znaków („”)
JJ Kim

Czy nie ma możliwości uzyskania tej wartości za pomocą emulatora? ponieważ chciałbym zablokować wszystkich użytkowników, jeśli nie mają żadnych kart SIM.
c-an

11

Oba następujące są ustawione na „google_sdk”:

Build.PRODUCT
Build.MODEL

Dlatego powinno wystarczyć użycie jednej z poniższych linii.

"google_sdk".equals(Build.MODEL)

lub

"google_sdk".equals(Build.PRODUCT)

Podczas uruchamiania emulatora x86 w systemie Windows Build.Product to sdk_x86.
Edward Brey

sprawdzanie za pomocą PRODUCT nie jest dobrym wyborem, ponieważ zwraca różne wartości z różnych emulatorów
Beeing Jk

11

Wypróbowałem kilka technik, ale zdecydowałem się na nieco zmienioną wersję sprawdzania Build.PRODUCT, jak poniżej. Wydaje się, że różni się to nieco w zależności od emulatora, dlatego mam 3 testy, które obecnie mam. Wydaje mi się, że mogłem właśnie sprawdzić, czy product.contains („sdk”), ale uznałem, że poniższe sprawdzenie jest nieco bezpieczniejsze.

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

Do Twojej wiadomości - odkryłem, że mój Kindle Fire miał Build.BRAND = „rodzajowy”, a niektóre emulatory nie miały „Androida” dla operatora sieci.


10

I wystarczy spojrzeć na _sdk, _sdk_lub sdk_, lub nawet tylko sdkczęść w Build.PRODUCT:

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

3
Dlaczego nie tylko contains("sdk")? Jedyna różnica (poza tym, że jest szybsza) polega na tym, matches(".*_?sdk_?.*")że jeśli przed lub po sdk znajduje się znak, musi to być znak podkreślenia „_”, który nie jest aż tak ważny do sprawdzenia.
Nulano

9

Nigdy nie znalazłem dobrego sposobu na sprawdzenie, czy jesteś w emulatorze.

ale jeśli potrzebujesz tylko detecetować, jeśli jesteś w środowisku programistycznym, możesz to zrobić:

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

Mam nadzieję, że to pomoże....


8

użyj tej funkcji:

 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

Nie wiem, czy są lepsze sposoby na wykrycie emu, ale emulator będzie miał plik init.goldfish.rc w katalogu głównym.

Jest to skrypt startowy specyficzny dla emulatora i nie powinien on być dostępny w wersji innej niż emulator.


Podczas uruchamiania systemu Android jądro Linuksa najpierw nazywa proces „init”. init czyta pliki „/init.rc” i „init.device.rc”. „init.device.rc” jest specyficzny dla urządzenia, na urządzeniu wirtualnym plik ten nosi nazwę „init.goldfish.rc”.
NET3

7

Oto moje rozwiązanie (działa tylko wtedy, gdy na serwerze debugowania działa serwer WWW): Utworzyłem zadanie w tle, które uruchamia się po uruchomieniu aplikacji. Wygląda na http://10.0.2.2 a jeśli istnieje to zmienia parametr globalny (IsDebug) true. Jest to cichy sposób, aby dowiedzieć się, gdzie biegniesz.

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

z głównej działalności na Utwórz:

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

7

Z baterii emulator: źródłem zasilania jest zawsze ładowarka sieciowa. Temperatura wynosi zawsze 0.

I możesz użyć Build.HOSTdo rejestrowania wartości hosta, inny emulator ma inną wartość hosta.


Jak uzyskać źródło zasilania i temperaturę?
programista Androida

5

Inną opcją byłoby przyjrzenie się właściwości ro.hardware i sprawdzenie, czy jest ustawiona na złotą rybkę. Niestety wydaje się, że nie ma łatwego sposobu na zrobienie tego z Javy, ale jest to trywialne z C przy użyciu property_get () .


4
Wydaje się, że działa z NDK. Dołącz <sys / system_properties.h> i użyj __system_property_get („ro.hardware”, buf), a następnie sprawdź, czy buf to „złota rybka”.
NuSkooler

5

Powyższe sugerowane rozwiązanie do sprawdzenia ANDROID_ID działało dla mnie, dopóki nie zaktualizowałem dzisiaj do najnowszych narzędzi SDK wydanych z Androidem 2.2.

Dlatego obecnie przełączyłem się na następujące rozwiązanie, które działa do tej pory z tą wadą, że musisz jednak ustawić uprawnienie odczytu 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

Wszystkie odpowiedzi w jednej metodzie

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

Niezłe. init.goldfish.rcistnieje tylko w emulatorach; jest to dodatkowo dobry sprawdzian w przyszłości, oprócz szczegółów kompilacji.
sud007

2
@ sud007 Istnieje wiele urządzeń z `/init.goldfish.rc, co doprowadzi do fałszywych trafień. Na przykład wiele urządzeń z serii Samsung Galaxy.
laalto

@laalto, faktycznie miałeś rację. Dowiedziałem się o tym później i przepraszam, że zapomniałem go zaktualizować tutaj.
sud007

klucze testowe generują dla mnie fałszywe alarmy.
Avi Parshan,

Na jakich urządzeniach generują fałszywe alarmy?
Aman Verma

5

Znalazłem nowy emulator Build.HARDWARE = "ranchu".

Odniesienie: https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU

Znalazłem też oficjalny sposób Androida, aby sprawdzić, czy emulator, czy nie. Myślę, że jest to dla nas dobre odniesienie.

Od Androida API Level 23 [Android 6.0]

package com.android.internal.util;

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

Musimy ScreenShapeHelper.IS_EMULATORsprawdzić, czy emulator.

Od Androida API Poziom 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");

}

Mamy Build.IS_EMULATORsprawdzić, czy emulator.

Sposób, w jaki urzędnik sprawdza, czy emulator nie jest nowy, a także może niewystarczający, wspomniane powyżej również odpowiedzi.

Ale może to nam pokazać, że urzędnik zapewni sposób urzędnikowi, aby sprawdzić, czy emulator, czy nie.

Korzystając z wyżej wymienionych wszystkich sposobów, teraz możemy również skorzystać z dwóch sposobów sprawdzenia, czy emulator.

Jak uzyskać dostęp do com.android.internalpakietu i@hide

i poczekaj na oficjalny otwarty zestaw SDK.


5

Moja rekomendacja:

spróbuj tego z github.

Łatwy do wykrycia emulator Androida

  • Sprawdzone na prawdziwych urządzeniach w Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Emulator Androida
  • Andy 46.2.207.0
  • Zagraj w MEmu
  • Nox App Player
  • Koplayer
  • .....

Jak używać z przykładem:

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

                    }
                });

4

możesz sprawdzić numer IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

jeśli przywołam na emulatorze ten zwrot 0. jednak nie ma dokumentacji, która by to zapewniła. chociaż emulator nie zawsze zwraca 0, wydaje się całkiem bezpieczne, że zarejestrowany telefon nie zwróci 0. co by się stało na urządzeniu z Androidem innym niż telefon, lub bez zainstalowanej karty SIM lub niezarejestrowanym na sieć?

wydaje się, że to zły pomysł, polegać na tym.

oznacza to również, że musisz poprosić o pozwolenie na odczytanie stanu telefonu, co jest złe, jeśli nie potrzebujesz go już do czegoś innego.

jeśli nie, to zawsze coś gdzieś przerzucasz, zanim w końcu wygenerujesz podpisaną aplikację.


5
IMEI prawdopodobnie powróci również 0na tablecie z Androidem lub telefonie bez karty SIM.
Paul Lammertsma,

Możemy edytować IMEI na emulatorze. więc może to nie służyć celowi. Począwszy od interfejsu API 29 nie możemy uzyskać dostępu do IMEI.
Ananth

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

Powinno to zwrócić wartość true, jeśli aplikacja działa na emulatorze.

Na co powinniśmy uważać, nie wykrywamy wszystkich emulatorów, ponieważ istnieje tylko kilka różnych emulatorów. Łatwo to sprawdzić. Musimy upewnić się, że rzeczywiste urządzenia nie zostaną wykryte jako emulator.

Korzystałem z aplikacji o nazwie „ Udostępnianie informacji o urządzeniu z Androidem ”, aby to sprawdzić.

W tej aplikacji możesz zobaczyć różnego rodzaju informacje o wielu urządzeniach (prawdopodobnie o większości urządzeń na świecie; jeśli urządzenia, którego używasz, brakuje na liście, zostanie ono dodane automatycznie).


Na moim Genymotion działającym na komputerze Mac Build.DEVICE = vbox86p
lxknvlk


3

To działa dla mnie

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

3
inżynier oprogramowania wewnętrznego, którego posiadamy, nie zaktualizował tego; uzyskanie Build.Man Manufacturer na naszym sprzęcie zwróciło „nieznane” Odcisk palca wydaje się lepszym sposobem.
Ktoś gdzieś

3

Umieść plik w systemie plików emulatora; ponieważ plik nie będzie istniał na prawdziwym urządzeniu, powinien być stabilny, niezawodny i łatwy do naprawienia, gdy się zepsuje.


3

Zebrałem wszystkie odpowiedzi na to pytanie i opracowałem funkcję pozwalającą wykryć, czy Android działa na emulatorze vm / emulatorze:

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

Testowane na emulatorach, genymotion i Bluestacks (1 października 2015).


3

Sprawdzając odpowiedzi, żadna z nich nie działała podczas korzystania z emulatorów LeapDroid, Droid4x lub Andy,

Dla wszystkich przypadków działa to:

 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 zwraca „andy” dla Build.HARDWARE
Doug Voss

Ołów fałszywie dodatni dla urządzeń Samsung serii J. Używany do wykrycia emulatora: github.com/gingo/android-emulator-detector
bluetoothfx

2

Ponieważ podstawowym mechanizmem emulacji Genymotion jest VirtualBox, który nie zmieni się w najbliższym czasie, uznałem następujący kod za najbardziej niezawodny:

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

2

Niezależnie od tego kodu użyć, aby zrobić wykrywanie emulatora, bardzo polecam pisanie testów jednostkowych na pokrycie wszystkich Build.FINGERPRINT, Build.HARDWAREi Build.MANUFACTURERwartości, które zależą. Oto kilka przykładowych testów:

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

... a oto nasz kod (dzienniki debugowania i komentarze zostały usunięte dla zwięzłości):

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

Inną opcją jest sprawdzenie, czy jesteś w trybie debugowania czy w trybie produkcyjnym:

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

prosty i niezawodny.

Nie do końca odpowiedź na pytanie, ale w większości przypadków możesz rozróżnić sesje debugowania / testowania od sesji życiowych bazy użytkowników.

W moim przypadku ustawiłem Google Analytics na dryRun () w trybie debugowania, więc to podejście działa dla mnie całkowicie dobrze.


Dla bardziej zaawansowanych użytkowników jest inna opcja. warianty budowy stopni:

w pliku oceny aplikacji dodaj nowy wariant:

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

W kodzie sprawdź typ kompilacji:

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

Teraz masz możliwość zbudowania 3 różnych typów aplikacji.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.