Wie kann ich erkennen, wenn eine Android-Anwendung im Emulator ausgeführt wird?

313

Ich möchte, dass mein Code auf dem Emulator etwas anders ausgeführt wird als auf einem Gerät. ( Verwenden Sie beispielsweise 10.0.2.2 anstelle einer öffentlichen URL, um automatisch auf einem Entwicklungsserver ausgeführt zu werden.) Wie lässt sich am besten erkennen, wenn eine Android-Anwendung im Emulator ausgeführt wird?

Joe Ludwig
quelle
2
Könnte einen Blick darauf werfen android.os.Build.
Yanchenko
11
Überraschen Sie mich ... Google sollte eine Standardmethode dafür haben?
Pulver366
@kreker was ist das Problem, mit dem Sie in bestehenden Lösungen konfrontiert sind?
Khemraj
@ Khemraj Betrugsprobleme. Der böse Kerl kann einige Sensoren verspotten und einige Zeichenfolgen ändern, um so zu tun, als wäre er ein echtes Gerät
Kreker

Antworten:

159

Wie wäre es mit dieser Lösung:

    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

Beachten Sie, dass einige Emulatoren die genauen Spezifikationen realer Geräte vortäuschen, sodass sie möglicherweise nicht erkannt werden können.

Hier ein winziger Ausschnitt, den Sie in der APK erstellen können, um verschiedene Dinge darüber zu zeigen, sodass Sie Ihre eigenen Regeln hinzufügen können:

        textView.text = "FINGERPRINT:${Build.FINGERPRINT}\n" +
                "MODEL:${Build.MODEL}\n" +
                "MANUFACTURER:${Build.MANUFACTURER}\n" +
                "BRAND:${Build.BRAND}\n" +
                "DEVICE:${Build.DEVICE}\n" +
                "BOARD:${Build.BOARD}\n" +
                "HOST:${Build.HOST}\n" +
                "PRODUCT:${Build.PRODUCT}\n"
Android-Entwickler
quelle
9
Auf diese Weise erkennt Facebook Emulatoren in React-Native
Vaiden
Dies ist, worauf ich aktualisieren musste, nachdem ich die Antwort von @Aleadam für eine Weile verwendet hatte (es funktionierte nicht mehr für mich).
ckbhodge
@Sid Was soll dazu hinzugefügt werden?
Android-Entwickler
2
@Sid Haben Sie dort verschiedene Build-Klassenvariablen ausgedruckt? Nichts scheint etwas Besonderes zu sein? Haben Sie dies versucht: github.com/framgia/android-emulator-detector ?
Android-Entwickler
1
@DrDeo Sie können mit BuildConfig.DEBUG eine Überprüfung des aktuellen Builds hinzufügen oder einen eigenen Build mit Ihrer eigenen benutzerdefinierten Variablen erstellen. Möglicherweise können Sie auch Proguard verwenden, damit diese Funktion immer false oder etwas zurückgibt (Sie können beispielsweise Protokolle entfernen, wie hier gezeigt: medium.com/tixdo-labs/… , also ist das möglicherweise auch möglich)
Android-Entwickler
118

Eine häufige scheint zu sein Build.FINGERPRINT.contains("generic")

Aleadam
quelle
Dies funktioniert sogar mit dem Galaxy Tab Emulator. Die Top-Antwort hat nicht gefallen.
BufferStack
10
Bitte geben Sie an, ob ein Fingerabdruck mit "generisch" entweder ein Emulator oder das Gerät ist. Diese Informationen sind wichtig, werden aber nicht bereitgestellt.
James Cameron
2
Emulator - nach den Kommentaren vor Ihnen zu urteilen :)
Dori
7
Dies gibt auf meinen Geräten, auf denen CyanogenMod ausgeführt wird, true zurück.
Ardevd
8
In der Android-Dokumentation heißt es, Sie sollten nicht versuchen, den FINGERPRINTWert zu interpretieren .
Gnuf
64

Nun, die Android-ID funktioniert bei mir nicht. Ich verwende derzeit:

"google_sdk".equals( Build.PRODUCT );
Marcus
quelle
35
Jeder, der dies liest, könnte interessiert sein zu wissen, dass sich diese Zeichenfolge anscheinend in "sdk" und nicht in "google_sdk" geändert hat.
Daniel Sloof
15
@ Daniel: Ich verwende 2.3.3 mit Google API und dort steht "google_sdk". Scheint, dass es "google_sdk" für AVD mit Google API und "sdk" für die normalen ist.
Randy Sugianto 'Yuku'
3
Der Intel-Emulator gibt "full_x86" zurück, sodass ich mich nicht auf diese Methode verlassen würde.
user462982
3
@GlennMaynard Die umgekehrte Form ist hässlich, aber praktisch: Build.PRODUCT kann null sein, während "google_sdk" dies nicht kann. Daher vermeidet diese Form einen möglichen Nullreferenzfehler.
Rupert Rawnsley
4
Einschließlich weiterer Fälle: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Alberto Alonso Ruibal
31

Basierend auf Hinweisen aus anderen Antworten ist dies wahrscheinlich der robusteste Weg:

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

Vitali
quelle
Ja. Im Gegensatz zu Build.PRODUCT ist Build.HARDWARE (Goldfisch) für das offizielle SDK und AOSP identisch. Vor API 8 müssen Sie jedoch Reflection verwenden, um zum Feld HARDWARE zu gelangen.
David Chandler
4
Ich würde mitisEmulator = Build.HARDWARE.contains("golfdish")
Holmes
7
@holmes: Tippfehler, s / b "Goldfisch"
Noah
7
Für das Android 5.1 x86_64-Bild (und wahrscheinlich andere neuere 64-Bit-Bilder) wäre das "Ranchu" anstelle von "Goldfisch".
Warbi
28

Google verwendet diesen Code im Geräte-Info-Plugin von Flutter, um festzustellen, ob das Gerät ein Emulator ist:

private boolean isEmulator() {
    return (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
        || Build.FINGERPRINT.startsWith("generic")
        || Build.FINGERPRINT.startsWith("unknown")
        || Build.HARDWARE.contains("goldfish")
        || Build.HARDWARE.contains("ranchu")
        || Build.MODEL.contains("google_sdk")
        || Build.MODEL.contains("Emulator")
        || Build.MODEL.contains("Android SDK built for x86")
        || Build.MANUFACTURER.contains("Genymotion")
        || Build.PRODUCT.contains("sdk_google")
        || Build.PRODUCT.contains("google_sdk")
        || Build.PRODUCT.contains("sdk")
        || Build.PRODUCT.contains("sdk_x86")
        || Build.PRODUCT.contains("vbox86p")
        || Build.PRODUCT.contains("emulator")
        || Build.PRODUCT.contains("simulator");
}
Rockney
quelle
20

Wie wäre es mit dem folgenden Code, um festzustellen, ob Ihre App mit dem Debug-Schlüssel signiert wurde? Es erkennt den Emulator nicht, aber es könnte für Ihren Zweck funktionieren?

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;

} 
Jeff S.
quelle
1
Vielen Dank für diesen Code. Ich habe überprüft und es funktioniert, Aldo Coping des langen Debug-Schlüssels kann schmerzhaft sein, aber es wird nur einmal durchgeführt. Dies ist die einzige zuverlässige Lösung, da alle anderen Antworten einen Teil der OS-Build-Info-Zeichenfolge mit einer statischen Zeichenfolge vergleichen. Diese kann und wurde gegenüber Android SDK-Versionen geändert und kann auch von benutzerdefinierten Android-Builds gefälscht werden.
ZoltanF
Ich denke, es ist die einzige zuverlässige Lösung. Der Debug-Schlüssel kann sich jedoch schneller ändern als gewünscht.
rds
2
Ein besserer Weg, dies zu tun, ist BuildConfig.DEBUG.
Mygod
13

Dieser Code funktioniert für mich

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

Falls dieses Gerät keine SIM-Karte hat, wird die leere Zeichenfolge erneut ausgeführt: ""

Da der Android-Emulator "Android" als Netzwerkbetreiber immer neu abstimmt, verwende ich den obigen Code.

JJ Kim
quelle
3
Was gibt ein Gerät ohne SIM-Karte (z. B. ein Tablet) zurück?
rds
Emulator für Android 2.1 ausführen. Dieser Code hat bei mir funktioniert, aber seit dem Upgrade von Cordova auf 2.7.0 scheint die Kontextvariable undefiniert zu sein oder so. Hier ist der Fehler, den ich in ADT erhalte: "Der Kontext kann nicht in eine Variable aufgelöst werden." Laut dem obigen Kommentar ist dies auch KEINE zuverlässige Methode (obwohl ich sie selbst nicht zum Scheitern gebracht habe).
Rustavore
2
@rds Geräte ohne SIM-Karte geben leere Zeichenfolge ("") zurück
JJ Kim
Gibt es keine Möglichkeit, diesen Wert mit dem Emulator zu haben? weil ich alle Benutzer blockieren möchte, wenn sie keine SIM-Karten haben.
c-an
11

Beide folgenden Elemente sind auf "google_sdk" festgelegt:

Build.PRODUCT
Build.MODEL

Es sollte also ausreichen, eine der folgenden Zeilen zu verwenden.

"google_sdk".equals(Build.MODEL)

oder

"google_sdk".equals(Build.PRODUCT)
Sileria
quelle
Wenn Sie den x86-Emulator unter Windows ausführen, ist Build.Product sdk_x86.
Edward Brey
Die Überprüfung mit PRODUCT ist keine gute Wahl, da verschiedene Werte von verschiedenen Emulatoren zurückgegeben werden
Beeing Jk
11

Ich habe verschiedene Techniken ausprobiert, mich jedoch für eine leicht überarbeitete Version der Überprüfung von Build.PRODUCT wie folgt entschieden. Dies scheint von Emulator zu Emulator ziemlich unterschiedlich zu sein, deshalb habe ich die 3 Schecks, die ich derzeit habe. Ich denke, ich hätte einfach überprüfen können, ob product.contains ("sdk") enthält, fand aber, dass die Überprüfung unten etwas sicherer war.

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

Zu Ihrer Information - Ich habe festgestellt, dass mein Kindle Fire Build.BRAND = "generic" hat und einige der Emulatoren kein "Android" für den Netzbetreiber hatten.

Patrick
quelle
10

Ich sehe nur _sdk, _sdk_oder sdk_, oder auch nur sdkteilweise in Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
SD
quelle
3
Warum nicht einfach contains("sdk")? Der einzige Unterschied (außer schneller zu sein) ist dermatches(".*_?sdk_?.*") , dass ein Zeichen vor oder nach sdk ein Unterstrich '_' sein muss, was nicht allzu wichtig ist, um es zu überprüfen.
Nulano
9

Ich habe nie einen guten Weg gefunden, um festzustellen, ob Sie im Emulator sind.

Wenn Sie jedoch nur feststellen müssen, ob Sie sich in einer Entwicklungsumgebung befinden, können Sie Folgendes tun:

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

Ich hoffe das hilft....

Ätherpuls
quelle
8

Verwenden Sie diese Funktion:

 public static final boolean isEmulator() {

    int rating = 0;

    if ((Build.PRODUCT.equals("sdk")) || (Build.PRODUCT.equals("google_sdk"))
            || (Build.PRODUCT.equals("sdk_x86")) || (Build.PRODUCT.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MANUFACTURER.equals("unknown")) || (Build.MANUFACTURER.equals("Genymotion"))) {
        rating++;
    }
    if ((Build.BRAND.equals("generic")) || (Build.BRAND.equals("generic_x86"))) {
        rating++;
    }
    if ((Build.DEVICE.equals("generic")) || (Build.DEVICE.equals("generic_x86")) || (Build.DEVICE.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MODEL.equals("sdk")) || (Build.MODEL.equals("google_sdk"))
            || (Build.MODEL.equals("Android SDK built for x86"))) {
        rating++;
    }
    if ((Build.HARDWARE.equals("goldfish")) || (Build.HARDWARE.equals("vbox86"))) {
        rating++;
    }
    if ((Build.FINGERPRINT.contains("generic/sdk/generic"))
            || (Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86"))
            || (Build.FINGERPRINT.contains("generic/google_sdk/generic"))
            || (Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))) {
        rating++;
    }

    return rating > 4;

    }
AndroidCrop
quelle
7

Ich weiß nicht, ob es bessere Möglichkeiten gibt, die Emu zu erkennen, aber der Emulator hat die Datei init.goldfish.rcim Stammverzeichnis.

Es ist das emulatorspezifische Startskript und sollte bei einem Nicht-Emulator-Build nicht vorhanden sein.

Nils Pipenbrinck
quelle
Während des Starts des Android-Systems ruft der Linux-Kernel zuerst den Prozess "init" auf. init liest die Dateien "/init.rc" und "init.device.rc". "init.device.rc" ist gerätespezifisch. Auf dem virtuellen Gerät heißt diese Datei "init.goldfish.rc".
NET3
7

Hier ist meine Lösung (funktioniert nur, wenn Sie einen Webserver auf Ihrem Debug-Computer ausführen): Ich habe eine Hintergrundaufgabe erstellt, die beim Start der Anwendung gestartet wird. Es sucht nach http://10.0.2.2 und wenn es existiert, ändert es einen globalen Parameter (IsDebug) in true. Es ist ein stiller Weg, um herauszufinden, wo Sie laufen.

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

von der Hauptaktivität onCreate:

CheckDebugModeTask checkDebugMode = new CheckDebugModeTask();
checkDebugMode.execute("");
Eyal
quelle
7

Von der Batterie, dem Emulator: Die Stromquelle ist immer ein Wechselstromladegerät. Die Temperatur ist immer 0.

Und Sie können verwenden Build.HOST, um Host-Wert aufzuzeichnen, unterschiedliche Emulatoren haben unterschiedliche Host-Werte.

Louie Liu
quelle
Wie erhalten Sie die Stromquelle und die Temperatur?
Android-Entwickler
5

Eine andere Möglichkeit wäre, sich die Eigenschaft ro.hardware anzusehen und zu prüfen, ob sie auf Goldfisch eingestellt ist. Leider scheint es keinen einfachen Weg zu geben, dies von Java aus zu tun, aber es ist trivial von C mit property_get () .

Tim Kryger
quelle
4
Dies scheint vom NDK aus zu funktionieren. Fügen Sie <sys / system_properties.h> ein und verwenden Sie __system_property_get ("ro.hardware", buf). Überprüfen Sie dann, ob buf "goldfish" ist.
NuSkooler
5

Die oben vorgeschlagene Lösung zur Überprüfung auf die ANDROID_ID sie für mich funktioniert hat, bis ich heute auf die neuesten SDK-Tools aktualisiert habe, die mit Android 2.2 veröffentlicht wurden.

Daher habe ich derzeit auf die folgende Lösung umgestellt, die bisher mit dem Nachteil funktioniert, dass Sie jedoch die Leseberechtigung PHONE_STATE ( <uses-permission android:name="android.permission.READ_PHONE_STATE"/>) eingeben müssen.

private void checkForDebugMode() {
    ISDEBUGMODE = false; //(Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID) == null);

    TelephonyManager man = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
    if(man != null){
        String devId = man.getDeviceSoftwareVersion();
        ISDEBUGMODE = (devId == null);
    }
} 
Juri
quelle
5

Alle Antworten in einer Methode

static boolean checkEmulator()
{
    try
    {
        String buildDetails = (Build.FINGERPRINT + Build.DEVICE + Build.MODEL + Build.BRAND + Build.PRODUCT + Build.MANUFACTURER + Build.HARDWARE).toLowerCase();

        if (buildDetails.contains("generic") 
        ||  buildDetails.contains("unknown") 
        ||  buildDetails.contains("emulator") 
        ||  buildDetails.contains("sdk") 
        ||  buildDetails.contains("genymotion") 
        ||  buildDetails.contains("x86") // this includes vbox86
        ||  buildDetails.contains("goldfish")
        ||  buildDetails.contains("test-keys"))
            return true;
    }   
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        TelephonyManager    tm  = (TelephonyManager) App.context.getSystemService(Context.TELEPHONY_SERVICE);
        String              non = tm.getNetworkOperatorName().toLowerCase();
        if (non.equals("android"))
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        if (new File ("/init.goldfish.rc").exists())
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    return false;
}
XXX
quelle
Schön. init.goldfish.rcexistiert nur in Emulatoren; Zusätzlich zu den Build-Details ist dies eine gute Überprüfung für die Zukunft.
Sud007
2
@ sud007 Es gibt viele Geräte mit `/init.goldfish.rc und dies führt zu Fehlalarmen. Zum Beispiel viele Geräte der Samsung Galaxy-Serie.
Laalto
@laalto du warst eigentlich richtig. Ich habe das später herausgefunden und entschuldige mich, dass ich vergessen habe, es hier zu aktualisieren.
Sud007
Testschlüssel haben für mich falsch positive Ergebnisse generiert.
Avi Parshan
Auf welchen Geräten erzeugen sie falsch positive Ergebnisse?
Aman Verma
5

Ich habe den neuen Emulator gefunden Build.HARDWARE = "ranchu".

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

Und ich habe auch den offiziellen Weg für Android gefunden, um zu überprüfen, ob Emulator oder nicht. Ich denke, es ist eine gute Referenz für uns.

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

Wir müssen ScreenShapeHelper.IS_EMULATORprüfen, ob Emulator.

Seit Android API Level 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");

}

Wir müssen Build.IS_EMULATORprüfen, ob Emulator.

Die Art und Weise, wie der Beamte prüft, ob der Emulator nicht neu ist, und vielleicht auch nicht genug, sind die oben genannten Antworten ebenfalls erwähnt.

Aber dies zeigt uns vielleicht, dass der Beamte die Möglichkeit bietet, zu prüfen, ob der Emulator oder nicht.

Da wir die oben genannten Methoden verwenden, können wir jetzt auch die beiden Methoden verwenden, um zu überprüfen, ob der Emulator vorhanden ist.

So greifen Sie auf das com.android.internalPaket zu und@hide

und warten Sie auf das offizielle offene SDK.

ifeegoo
quelle
5

Meine Empfehlung:

versuchen Sie dies von Github.

Einfach zu erkennender Android Emulator

  • Auf realen Geräten in der Gerätefarm überprüft ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Android Emulator
  • Andy 46.2.207.0
  • MEmu spielen
  • Nox App Player
  • Koplayer
  • ..... .....

Verwendung mit einem Beispiel:

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

                    }
                });
Saeed
quelle
4

Sie können die IMEI-Nummer http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29 überprüfen

Wenn ich mich auf dem Emulator an diese Rückgabe 0 erinnere, gibt es jedoch keine Dokumentation, die dies garantiert. Obwohl der Emulator möglicherweise nicht immer 0 zurückgibt, scheint es ziemlich sicher zu sein, dass ein registriertes Telefon nicht 0 zurückgibt. Was würde auf einem Android-Gerät ohne Telefon oder einem Gerät ohne installierte SIM-Karte oder einem Gerät geschehen, das derzeit nicht auf dem Android-Gerät registriert ist Netzwerk?

Das scheint eine schlechte Idee zu sein, sich darauf zu verlassen.

Dies bedeutet auch, dass Sie um Erlaubnis bitten müssen, um den Telefonstatus zu lesen. Dies ist schlecht, wenn Sie ihn nicht bereits für etwas anderes benötigen.

Wenn nicht, wird immer irgendwo etwas umgedreht, bevor Sie schließlich Ihre signierte App generieren.

Jeff
quelle
5
IMEI wird wahrscheinlich auch 0auf einem Android-Tablet oder einem Telefon ohne SIM-Karte zurückkehren.
Paul Lammertsma
Wir können IMEI auf dem Emulator bearbeiten. Dies kann also nicht den Zweck erfüllen. Ab API 29 können wir auch nicht auf IMEI zugreifen.
Ananth
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

Dies sollte true zurückgeben, wenn die App auf einem Emulator ausgeführt wird.

Wir sollten vorsichtig sein, wenn nicht alle Emulatoren erkannt werden, da es nur mehrere verschiedene Emulatoren gibt. Es ist leicht zu überprüfen. Wir müssen sicherstellen, dass tatsächliche Geräte nicht als Emulator erkannt werden.

Ich habe die App " Android Device Info Share " verwendet, um dies zu überprüfen.

In dieser App können Sie verschiedene Arten von Informationen zu vielen Geräten anzeigen (wahrscheinlich die meisten Geräte auf der Welt; wenn das von Ihnen verwendete Gerät in der Liste fehlt, wird es automatisch hinzugefügt).

Kanji
quelle
Auf meinem Genymotion läuft auf einem Mac Build.DEVICE = vbox86p
lxknvlk
3

Tatsächlich entspricht ANDROID_ID auf 2.2 immer 9774D56D682E549C (gemäß diesem Thread + meinen eigenen Experimenten).

Sie könnten also so etwas überprüfen:

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

Nicht das schönste, aber es macht den Job.

Eric Eijkelenboom
quelle
8
Ich würde wegen dieses schrecklichen Fehlers vorsichtig sein
Brandon O'Rourke
3

Das funktioniert bei mir

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
quelle
3
Der Firmware-Ingenieur, den wir intern haben, hat dies nicht aktualisiert. Build.Manufacturer auf unsere Hardware zu bekommen, gab "unbekannt" zurück. Der Fingerabdruck scheint ein besserer Weg zu sein.
Jemand irgendwo
3

Legen Sie eine Datei im Dateisystem des Emulators ab. Da die Datei auf dem realen Gerät nicht vorhanden ist, sollte sie stabil, zuverlässig und leicht zu reparieren sein, wenn sie beschädigt wird.

Aaron Digulla
quelle
3

Ich habe alle Antworten auf diese Frage gesammelt und eine Funktion entwickelt, mit der festgestellt werden kann, ob Android auf einem VM / Emulator ausgeführt wird:

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

Getestet auf Emulator, Genymotion und Bluestacks (1. Oktober 2015).

CONvid19
quelle
3

Bei der Verwendung der LeapDroid-, Droid4x- oder Andy-Emulatoren funktionierte keiner von ihnen.

Was in allen Fällen funktioniert, ist Folgendes:

 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;
}
leon karabchesvky
quelle
1
^ airpair.com/android/posts/…
Yousha Aleayoub
Andy_46.16_48 gibt "andy" für Build.HARDWARE
Doug Voss
Blei falsch positiv für Geräte der Samsung J-Serie. Wird verwendet, um Emulator zu erkennen: github.com/gingo/android-emulator-detector
bluetoothfx
2

Da die zugrunde liegende Emulations-Engine für Genymotion VirtualBox ist und sich dies in Kürze nicht ändern wird, fand ich den folgenden Code am zuverlässigsten:

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

Unabhängig davon, welchen Code Sie für die Emulatorerkennung verwenden, würde ich dringend empfehlen, Komponententests zu schreiben, um alle und Werte abzudecken Build.FINGERPRINT, von denen Sie abhängig sind. Hier einige Beispieltests:Build.HARDWAREBuild.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();
}

... und hier ist unser Code (Debug-Protokolle und Kommentare wurden aus Gründen der Übersichtlichkeit entfernt):

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;
    }
}
Dan J.
quelle
2

Eine andere Möglichkeit besteht darin, zu überprüfen, ob Sie sich im Debug- oder Produktionsmodus befinden:

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

einfach und zuverlässig.

Nicht ganz die Antwort auf die Frage, aber in den meisten Fällen möchten Sie möglicherweise zwischen Debugging- / Testsitzungen und Lebenssitzungen Ihrer Benutzerbasis unterscheiden.

In meinem Fall habe ich Google Analytics im Debug-Modus auf dryRun () gesetzt, sodass dieser Ansatz für mich völlig in Ordnung ist.


Für fortgeschrittene Benutzer gibt es eine andere Option. Gradle Build-Varianten:

Fügen Sie in der Gradle-Datei Ihrer App eine neue Variante hinzu:

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

Überprüfen Sie in Ihrem Code den Build-Typ:

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

Jetzt haben Sie die Möglichkeit, 3 verschiedene Arten Ihrer App zu erstellen.

Mikrofone
quelle