Come posso rilevare quando un'applicazione Android è in esecuzione nell'emulatore?


313

Vorrei che il mio codice venisse eseguito in modo leggermente diverso quando si esegue l'emulatore rispetto a quando si esegue su un dispositivo. ( Ad esempio , utilizzando 10.0.2.2 invece di un URL pubblico per l'esecuzione automatica su un server di sviluppo.) Qual è il modo migliore per rilevare quando un'applicazione Android è in esecuzione nell'emulatore?


2
Potrebbe dare un'occhiata android.os.Build.
yanchenko,

11
Stupiscimi ... Google dovrebbe avere un modo standard per farlo?
powder366

@kreker qual è il problema, stai affrontando soluzioni esistenti?
Khemraj,

Problemi di frode @Khemraj. Il malvagio può deridere alcuni sensori e cambiare alcune stringhe per fingere un dispositivo reale
kreker,

Risposte:


159

Che ne dici di questa soluzione:

    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

Nota che alcuni emulatori fingono specifiche esatte di dispositivi reali, quindi potrebbe essere impossibile rilevarlo.

Ecco un piccolo frammento che puoi creare nell'APK per mostrare varie cose a riguardo, in modo da poter aggiungere le tue regole:

        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
Questo è il modo in cui Facebook rileva gli emulatori in React-Native
Vaiden,

Questo è ciò a cui ho dovuto aggiornare dopo aver usato la risposta di @Aleadam per un bel po '(ha smesso di funzionare per me).
ckbhodge,

@Sid Cosa dovrebbe essere aggiunto per questo?
sviluppatore Android

2
@Sid Hai stampato lì varie variabili della classe Build? Niente sembra speciale? Hai provato questo: github.com/framgia/android-emulator-detector ?
sviluppatore Android

1
@DrDeo Puoi aggiungere un controllo della build corrente usando BuildConfig.DEBUG o creare la tua build con la tua variabile personalizzata. Potresti anche essere in grado di utilizzare Proguard per rendere questa funzione sempre restituita false, o qualcosa del genere (puoi rimuovere i log, ad esempio, come mostrato qui: medium.com/tixdo-labs/… , quindi forse è anche possibile)
sviluppatore Android

118

Uno sems comune per essere Build.FINGERPRINT.contains("generic")


Funziona anche con l'emulatore Galaxy Tab. La risposta più apprezzata no.
BufferStack,

10
Indicare se un'impronta digitale contenente "generico" è un emulatore o il dispositivo. Tali informazioni sono fondamentali ma non fornite.
James Cameron,

2
Emulatore - a giudicare dai commenti prima dei tuoi :)
Dori

8
Questo è vero sui miei dispositivi con CyanogenMod, quindi attenzione.
Ardevd,

8
La documentazione di Android dice che non dovresti provare a interpretare il FINGERPRINTvalore.
gnuf,

64

Beh, l'ID Android non funziona per me, attualmente sto usando:

"google_sdk".equals( Build.PRODUCT );

35
Chiunque legga questo potrebbe essere interessato a sapere che questa stringa sembra essere cambiata in "sdk", anziché in "google_sdk".
Daniel Sloof,

15
@Daniel: utilizzo 2.3.3 con l'API di Google e dice "google_sdk". Sembra che sia "google_sdk" per AVD con l'API di Google e "sdk" per quelli normali.
Randy Sugianto "Yuku",

3
L'emulatore Intel restituisce "full_x86", quindi non vorrei contare su questo metodo.
user462982

3
@GlennMaynard Il modulo inverso è brutto, ma pratico: Build.PRODUCT potrebbe essere nullo mentre "google_sdk" non può, quindi questo modulo evita un potenziale errore di riferimento null.
Rupert Rawnsley,

4
Compresi più casi: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Build.PRODUCT) || "vbox86p" .equals (Build.PRODUCT)
Alberto Alonso Ruibal

31

Basato su suggerimenti di altre risposte, questo è probabilmente il modo più efficace:

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


Sì. A differenza di Build.PRODUCT, Build.HARDWARE (pesce rosso) è lo stesso per SDK e AOSP ufficiali. Prima dell'API 8, tuttavia, è necessario utilizzare reflection per accedere al campo HARDWARE.
David Chandler,

4
Andrei conisEmulator = Build.HARDWARE.contains("golfdish")
holmes il

7
@holmes: refuso, s / b "pesce rosso"
Noah

7
Per l'immagine Android 5.1 x86_64 (e probabilmente altre immagini a 64 bit più recenti) sarebbe "ranchu" anziché "pesce rosso".
warbi,

28

Google utilizza questo codice nel plug-in di informazioni sul dispositivo di Flutter per determinare se il dispositivo è un emulatore:

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

Che ne dici di qualcosa come il codice qui sotto per dire se la tua app è stata firmata con la chiave di debug? non sta rilevando l'emulatore ma potrebbe funzionare per il tuo scopo?

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
Grazie per questo codice Ho controllato e sta funzionando, aldo far fronte alla lunga chiave di debug può essere doloroso ma viene fatto solo una volta. Questa è l'unica soluzione affidabile , poiché tutte le altre risposte confrontano una parte della stringa di informazioni sulla build del sistema operativo con una stringa statica, e questo può ed è stato modificato sulle versioni di Android SDK e può anche essere forgiato da build Android personalizzate.
ZoltanF,

Penso che sia l'unica soluzione affidabile. Tuttavia, la chiave di debug può cambiare più rapidamente di quanto desideriamo.
martedì

2
Un modo migliore per farlo è BuildConfig.DEBUG.
Mygod,

13

Questo codice funziona per me

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

Nel caso in cui il dispositivo non abbia una scheda SIM, riavvia la stringa vuota: ""

Dal momento che l'emulatore Android riavvia sempre "Android" come operatore di rete, utilizzo il codice sopra.


3
Cosa restituisce un dispositivo senza una scheda SIM (come un tablet)?
martedì

Esecuzione dell'emulatore per Android 2.1. Questo codice funzionava per me, ma dall'aggiornamento di Cordova alla 2.7.0, la variabile di contesto sembra essere indefinita o qualcosa del genere. Ecco l'errore che sto riscontrando in ADT: "Il contesto non può essere risolto in una variabile". Inoltre, secondo il commento sopra, questo NON è un metodo affidabile (anche se non ho fallito).
Rustavore,

2
@rds I dispositivi che non dispongono di una scheda SIM restituiscono una stringa vuota ("")
JJ Kim

Non c'è modo di avere questo valore con l'emulatore? perché vorrei bloccare tutti gli utenti se non dispongono di schede SIM.
c-an

12

Ho provato diverse tecniche, ma ho optato per una versione leggermente rivista del controllo di Build.PRODUCT come di seguito. Questo sembra variare un po 'da emulatore a emulatore, ecco perché ho i 3 controlli che ho attualmente. Immagino che avrei potuto controllare se product.contains ("sdk") ma che il controllo di seguito fosse un po 'più sicuro.

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

Cordiali saluti - Ho scoperto che il mio Kindle Fire aveva Build.BRAND = "generico" e alcuni degli emulatori non avevano "Android" per l'operatore di rete.


11

Entrambi sono impostati su "google_sdk":

Build.PRODUCT
Build.MODEL

Quindi dovrebbe essere sufficiente utilizzare una delle seguenti righe.

"google_sdk".equals(Build.MODEL)

o

"google_sdk".equals(Build.PRODUCT)

Quando si esegue l'emulatore x86 su Windows, Build.Product è sdk_x86.
Edward Brey,

verificare con PRODUCT non è una buona scelta in quanto restituisce vari valori da diversi emulatori
Beeing Jk,

10

Cerco solo _sdk, _sdk_o sdk_, o anche solo sdkparte di Build.PRODUCT:

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

3
Perché non solo contains("sdk")? L'unica differenza (oltre ad essere più veloce) è che matches(".*_?sdk_?.*")se c'è un carattere prima o dopo SDK, deve essere un carattere di sottolineatura '_', che non è poi così importante da controllare.
Nulano,

9

Non ho mai trovato un buon modo per dire se sei nell'emulatore.

ma se devi solo rilevare se ti trovi in ​​un ambiente di sviluppo puoi farlo:

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

Spero che questo aiuto ....


8

usa questa funzione:

 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

Non so se ci sono modi migliori per rilevare l'emu, ma l'emulatore avrà il file init.goldfish.rcnella directory principale.

È lo script di avvio specifico dell'emulatore e non dovrebbe essere presente in una build non emulatore.


Durante l'avvio del sistema Android il kernel Linux prima chiama il processo "init". init legge i file "/init.rc" e "init.device.rc". "init.device.rc" è specifico del dispositivo, sul dispositivo virtuale questo file si chiama "init.goldfish.rc".
NET3,

7

Ecco la mia soluzione (funziona solo se si esegue un server Web sul proprio computer di debug): Ho creato un'attività in background che si avvia all'avvio dell'applicazione. Sembra per http://10.0.2.2 e se esiste cambia un parametro globale (IsDebug) su true. È un modo silenzioso per scoprire dove stai correndo.

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

dall'attività principale suCreate:

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

7

Dalla batteria, l'emulatore: la fonte di alimentazione è sempre il caricabatterie CA. La temperatura è sempre 0.

E puoi usare Build.HOSTper registrare il valore dell'host, l'emulatore diverso ha un valore dell'host diverso.


Come si ottiene la fonte di alimentazione e la temperatura?
sviluppatore Android

6

Ho trovato il nuovo emulatore Build.HARDWARE = "ranchu".

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

E ho anche trovato il modo ufficiale Android per verificare se l'emulatore o no. Penso che sia un buon riferimento per noi.

Dall'API Android Livello 23 [Android 6.0]

package com.android.internal.util;

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

Dobbiamo ScreenShapeHelper.IS_EMULATORverificare se l'emulatore.

Dal livello API 24 di Android [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");

}

Dobbiamo Build.IS_EMULATORverificare se l'emulatore.

Il modo in cui il funzionario controlla se l'emulatore non è nuovo e forse non è abbastanza, anche le risposte sopra menzionate.

Ma questo forse ci mostra che il funzionario fornirà la via ufficiale per verificare se l'emulatore o no.

Come usando tutti i modi sopra menzionati, in questo momento possiamo anche usare i due modi per verificare se l'emulatore.

Come accedere al com.android.internalpacchetto e@hide

e attendi l'SDK ufficiale aperto.


5

Un'altra opzione sarebbe quella di guardare la proprietà ro.hardware e vedere se è impostato su goldfish. Sfortunatamente non sembra esserci un modo semplice per farlo da Java, ma è banale da C usando property_get () .


4
Questo sembra funzionare dall'NDK. Includi <sys / system_properties.h> e usa __system_property_get ("ro.hardware", buf) quindi controlla che buf sia "pesce rosso".
NuSkooler il

5

La soluzione sopra suggerita per verificare il ANDROID_IDfunzionamento per me fino a quando non ho aggiornato oggi agli ultimi strumenti SDK rilasciati con Android 2.2.

Pertanto, al momento sono passato alla seguente soluzione che funziona finora con lo svantaggio, tuttavia è necessario inserire l'autorizzazione di lettura 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

Tutte le risposte in un unico metodo

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

Ben fatto. init.goldfish.rcesiste solo negli emulatori; è anche un buon controllo in futuro oltre ai dettagli di costruzione.
sud007,

2
@ sud007 Ci sono molti dispositivi là fuori con `/init.goldfish.rc e questo porterà a falsi positivi. Ad esempio, molti dispositivi della serie Samsung Galaxy.
laalto,

@laalto in realtà avevi ragione. L'ho scoperto più tardi e mi scuso per aver dimenticato di aggiornarlo qui.
sud007

test-keys ha generato falsi positivi per me.
Avi Parshan,

Su quali dispositivi stanno generando falsi positivi?
Aman Verma,

5

La mia raccomandazione:

prova questo da Github.

Emulatore Android facile da rilevare

  • Controllato su dispositivi reali in Device Farm ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Emulatore Android
  • Andy 46.2.207.0
  • Gioca
  • Nox App Player
  • Koplayer
  • .....

Come usare con un esempio:

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

                    }
                });

4

puoi controllare l'IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

se ricordo sull'emulatore questo ritorno 0. tuttavia, non c'è documentazione che posso trovare che lo garantisca. anche se l'emulatore potrebbe non restituire sempre 0, sembra abbastanza sicuro che un telefono registrato non restituisca 0. cosa succederebbe su un dispositivo Android non telefonico o uno senza una scheda SIM installata o uno che non è attualmente registrato sul Rete?

sembra che sarebbe una cattiva idea, dipendere da quello.

significa anche che dovresti chiedere l'autorizzazione per leggere lo stato del telefono, il che è male se non lo richiedi già per qualcos'altro.

in caso contrario, c'è sempre un po 'di sfogliare da qualche parte prima di generare finalmente l'app firmata.


5
È probabile che l'IMEI ritorni anche 0su un tablet Android o su un telefono senza scheda SIM.
Paul Lammertsma,

Possiamo modificare l'IMEI sull'emulatore. quindi questo potrebbe non servire allo scopo. Inoltre, a partire dall'API 29 non possiamo accedere all'IMEI.
Ananth

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

Ciò dovrebbe restituire true se l'app è in esecuzione su un emulatore.

Ciò di cui dovremmo fare attenzione non è rilevare tutti gli emulatori perché ci sono solo diversi emulatori diversi. È facile da controllare Dobbiamo assicurarci che i dispositivi effettivi non vengano rilevati come emulatore.

Ho usato l'app chiamata " Condividi informazioni dispositivo Android " per controllare questo.

Su questa app, puoi vedere vari tipi di informazioni di molti dispositivi (probabilmente la maggior parte dei dispositivi nel mondo; se il dispositivo che stai utilizzando non è presente nell'elenco, verrà aggiunto automaticamente).


Sul mio Genymotion in esecuzione su un Mac Build.DEVICE = vbox86p
lxknvlk

4

Controllando le risposte, nessuno di loro ha funzionato quando si utilizzavano emulatori LeapDroid, Droid4x o Andy,

Ciò che funziona per tutti i casi è il seguente:

 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 restituisce "andy" per Build.HARDWARE
Doug Voss

Piombo falso positivo per dispositivi Samsung serie J. Usato per rilevare l'emulatore: github.com/gingo/android-emulator-detector
bluetoothfx


3

Questo funziona per me

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

3
l'ingegnere del firmware che abbiamo in casa non lo ha aggiornato; ottenere Build.Manufacturer sul nostro hardware restituito "sconosciuto". L'impronta digitale sembra un modo migliore.
Qualcuno da qualche parte

3

Inserisci un file nel file system dell'emulatore; poiché il file non esiste sul dispositivo reale, questo dovrebbe essere stabile, affidabile e facile da correggere quando si rompe.


3

Ho raccolto tutte le risposte su questa domanda e ho trovato la funzione per rilevare se Android è in esecuzione su un VM / emulatore:

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

Testato su emulatore, Genymotion e Bluestacks (1 ottobre 2015).


3

Qualunque sia il codice che si utilizza per fare il rilevamento emulatore, io consiglierei vivamente scrittura di unit test per coprire tutta la Build.FINGERPRINT, Build.HARDWAREe Build.MANUFACTURERvalori che si sta a seconda. Ecco alcuni test di esempio:

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

... ed ecco il nostro codice (log di debug e commenti rimossi per concisione):

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

Dato che il motore di emulazione sottostante per Genymotion è VirtualBox e che non cambierà presto, ho trovato il seguente codice il più affidabile:

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

2

Un'altra opzione è verificare se ci si trova in modalità debug o produzione:

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

semplice e affidabile.

Non completamente la risposta alla domanda, ma nella maggior parte dei casi potresti voler distinguere tra sessioni di debug / test e sessioni di vita della tua base di utenti.

Nel mio caso ho impostato google analytics su dryRun () in modalità debug, quindi questo approccio funziona perfettamente per me.


Per gli utenti più esperti c'è un'altra opzione. varianti di costruzione gradle:

nel file di valutazione della tua app aggiungi una nuova variante:

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

Nel tuo codice controlla il tipo di build:

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

Ora hai l'opportunità di creare 3 diversi tipi di app.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.