Emülatörde bir Android uygulamasının çalıştığını nasıl tespit edebilirim?


313

Kod, bir aygıtta çalışırken emülatör üzerinde çalışırken biraz farklı çalıştırmak istiyorum. ( Örneğin , bir geliştirme sunucusuna otomatik olarak çalıştırmak için herkese açık bir URL yerine 10.0.2.2 kullanmak.) Emülatörde bir Android uygulaması çalışırken tespit etmenin en iyi yolu nedir?


2
Bir göz atabilir android.os.Build.
yanchenko

11
Beni şaşırtın ... Google'ın bunu yapmanın standart bir yolu olmalı mı?
powder366

@kreker sorun nedir, mevcut çözümlerle karşılaşıyorsunuz?
Khemraj

@Khemraj dolandırıcılık sorunları. Kötü adam gerçek cihazı taklit etmek için bazı sensörler alay ve bazı dizeleri değiştirmek
kreker

Yanıtlar:


159

Bu çözüme ne dersiniz:

    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

Bazı emülatörlerin gerçek cihazların tam özelliklerini taklit ettiğini unutmayın, bu yüzden onu tespit etmek imkansız olabilir.

İşte APK'da, bunun hakkında çeşitli şeyler göstermek için yapabileceğiniz küçük bir snippet, böylece kendi kurallarınızı ekleyebilirsiniz:

        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'de

@Aleadam'ın yanıtını bir süre kullandıktan sonra güncellemem gereken şey buydu (benim için çalışmayı durdurdu).
ckbhodge

@Sid Bunun için ne eklenmeli?
android geliştirici

2
@Sid Orada çeşitli Build sınıfı değişkenleri yazdırdınız mı? Özel bir şey yok mu? Bunu denediniz mi : github.com/framgia/android-emulator-detector ?
android geliştirici

1
@DrDeo BuildConfig.DEBUG kullanarak geçerli yapının bir kontrolünü ekleyebilir veya kendi özel değişkeninizle kendi yapınızı oluşturabilirsiniz. Proguard'ı bu işlevi her zaman yanlış döndürmek veya bir şey yapmak için de kullanabilirsiniz (günlükleri, örneğin burada gösterildiği gibi kaldırabilirsiniz: medium.com/tixdo-labs/… , belki de bu mümkündür)
android geliştirici

118

Yaygın olan biri Build.FINGERPRINT.contains("generic")


Bu Galaxy Tab Emulator ile bile çalışır. En beğenilen cevap vermedi.
BufferStack

10
Lütfen "jenerik" içeren bir parmak izinin taklitçi mi yoksa cihaz mı olduğunu belirtin. Bu bilgi anahtardır ancak sağlanmamıştır.
James Cameron

2
Emulator - sizinkinden önceki yorumlara bakılırsa :)
Dori

7
Bu CyanogenMod çalıştıran cihazlarda doğru döner bu yüzden dikkat edin.
ardevd

8
Android dokümantasyon Eğer yorumlamak çalışmamalıdır diyor FINGERPRINTdeğeri.
gnuf

64

Peki Android kimliği benim için çalışmıyor, şu anda kullanıyorum:

"google_sdk".equals( Build.PRODUCT );

35
Bunu okuyan herkes bu dizenin 'google_sdk' yerine 'sdk' olarak değiştiğini bilmek isteyebilir.
Daniel Sloof

15
@Daniel: Google API ile 2.3.3 kullanıyorum ve 'google_sdk' yazıyor. Google API ile AVD için 'google_sdk' ve normal olanlar için 'sdk' gibi görünüyor.
Randy Sugianto 'Yuku'

3
Intel öykünücüsü "full_x86" döndürür, bu yüzden bu yönteme güvenmem.
user462982

3
@GlennMaynard Ters form çirkin, ama pratiktir: "google_sdk" yapamazken Build.PRODUCT boş olabilir, bu nedenle bu form potansiyel bir boş referans hatasını önler.
Rupert Rawnsley

4
Daha fazla vaka dahil: "google_sdk" .equals (Build.PRODUCT) || "sdk" .equals (Build.PRODUCT) || "sdk_x86" .equals (Derleme.ÜRÜN) || "vbox86p" .equals (YAPIM ÜRÜNÜ)
Alberto Alonso Ruibal

31

Diğer cevapların ipuçlarına dayanarak, bu muhtemelen en sağlam yoldur:

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


Evet. Build.PRODUCT ürününün aksine, Build.HARDWARE (goldfish) resmi SDK ve AOSP için aynıdır. Bununla birlikte, API 8'den önce DONANIM alanına ulaşmak için yansıma kullanmanız gerekir.
David Chandler

4
Ben giderdimisEmulator = Build.HARDWARE.contains("golfdish")
holmes

7
@holmes: yazım hatası, s / b "akvaryum balığı"
Noah

7
Android 5.1 x86_64 görüntüsü (ve muhtemelen daha yeni 64bit görüntüler) için bu "Japon balığı" yerine "ranchu" olur.
warbi

28

Google, bu kodu Flutter'ın cihaz bilgisi eklentisinde , cihazın bir taklitçi olup olmadığını belirlemek için kullanır:

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

Uygulamanızın hata ayıklama anahtarıyla imzalanıp imzalanmadığını söylemek için aşağıdaki kod gibi bir şeye ne dersiniz? öykünücüyü algılamıyor ancak amacınız için işe yarayabilir mi?

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
Bu kod için teşekkürler. Kontrol ettim ve çalışıyor, aldo uzun hata ayıklama anahtarıyla başa çıkmak acı verici olabilir, ancak sadece bir kez yapılır. Diğer tek cevaplar, işletim sistemi derleme bilgi dizesinin bir kısmını statik bir dizeyle karşılaştırdığından bu tek güvenilir çözümdür ve bu Android SDK sürümleri üzerinden değiştirilebilir ve değiştirilebilir ve ayrıca özel Android sürümleri tarafından dövülebilir.
ZoltanF

Bence bu tek güvenilir çözüm. Ancak hata ayıklama anahtarı istediğimizden daha hızlı değişebilir.
rds

2
Bunu yapmanın daha iyi bir yolu BuildConfig.DEBUG.
Mygod

13

Bu kod benim için çalışıyor

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

Cihazın sim kartı yoksa, boş dizeyi yeniden dener: ""

Android emülatörü her zaman "Android" i şebeke operatörü olarak yeniden ayarladığından yukarıdaki kodu kullanıyorum.


3
SIM kartı olmayan bir cihaz (tablet gibi) ne döndürür?
rds

Android 2.1 için emülatör çalışıyor. Bu kod benim için çalışıyordu, ancak Cordova'yı 2.7.0'a yükselttikten sonra, Context değişkeni tanımsız gibi görünüyor. ADT'de aldığım hata şöyle: "Bağlam bir değişkene çözümlenemiyor." Ayrıca, yukarıdaki yoruma göre, bu güvenilir bir yöntem DEĞİL (aslında kendim başarısız olmadı rağmen).
Rustavore

2
@rds SIM kartı olmayan cihazlar boş dize ("") döndürür
JJ Kim

Emülatörde bu değere sahip olmanın bir yolu yok mu? çünkü herhangi bir sim kartları yoksa tüm kullanıcıları engellemek istiyorum.
c-an

11

Her ikisi de "google_sdk" olarak ayarlanmıştır:

Build.PRODUCT
Build.MODEL

Bu nedenle, aşağıdaki satırlardan birini kullanmak yeterli olmalıdır.

"google_sdk".equals(Build.MODEL)

veya

"google_sdk".equals(Build.PRODUCT)

X86 öykünücüsünü Windows üzerinde çalıştırırken Build.Product kullanılır sdk_x86.
Edward Brey

PRODUCT ile kontrol etmek, farklı emülatörlerden çeşitli değerler döndürdüğü için iyi bir seçim değildir
Beeing Jk

11

Birkaç teknik denedim, ancak aşağıdaki gibi Build.PRODUCT'u kontrol etmek için biraz revize edilmiş bir versiyona yerleştim. Bu emülatörden emülatöre biraz değişiyor gibi görünüyor, bu yüzden şu anda sahip olduğum 3 kontrole sahibim. Sanırım sadece product.contains ("sdk") olup olmadığını kontrol etmiş olabilir ama aşağıdaki kontrol biraz daha güvenli olduğunu düşündüm.

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'ımın Build.BRAND = "generic" olduğunu ve emülatörlerin bazılarının şebeke operatörü için "Android" olmadığını buldum.


10

Sadece _sdk, _sdk_ya sdk_da hatta sadece bir sdkkısmına bakıyorum Build.PRODUCT:

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

3
Neden sadece contains("sdk")? Tek fark (daha hızlı olmaktan başka), matches(".*_?sdk_?.*")sdk'den önce veya sonra bir karakter varsa, kontrol etmek için o kadar da önemli olmayan bir alt çizgi '_' olması gerektiğini gerektirir.
Nulano

9

Emülatörde olup olmadığınızı söylemek için iyi bir yol bulamadım.

ancak yalnızca bir geliştirme ortamında bulunup bulunmadığınızı tespit etmeniz gerekiyorsa bunu yapabilirsiniz:

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

Umarım bu yardım ....


8

bu işlevi kullanın:

 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

Emu'yu algılamanın daha iyi yolları olup olmadığını bilmiyorum, ancak öykünücünün dosyayı init.goldfish.rckök dizinde bulacaksınız.

Bu emülatöre özgü bir başlangıç-komut dosyasıdır ve emülatör olmayan bir yapıda bulunmamalıdır.


Android sisteminin başlatılması sırasında Linux çekirdeği önce "init" işlemini çağırır. init "/init.rc" ve "init.device.rc" dosyalarını okur. "init.device.rc" aygıta özgüdür, sanal aygıtta bu dosyaya "init.goldfish.rc" denir.
NET3

7

İşte benim çözüm (sadece hata ayıklama makinenizde bir web sunucusu çalıştırırsanız çalışır): Uygulama başladığında başlayan bir arka plan görevi oluşturdum. Bu arar http://10.0.2.2 ve varsa doğru küresel bir parametre (IsDebug) değiştirir. Nerede koştuğunuzu öğrenmenin sessiz bir yoludur.

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

Create'deki ana etkinlikten:

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

7

Pil'den emülatör: Güç kaynağı her zaman AC Şarj Cihazıdır. Sıcaklık her zaman 0'dır.

Ve Build.HOSTana bilgisayar değerini kaydetmek için kullanabilirsiniz , farklı emülatör farklı ana bilgisayar değerine sahiptir.


Güç kaynağını ve sıcaklığı nasıl elde edersiniz?
android geliştirici

5

Başka bir seçenek, ro.hardware özelliğine bakmak ve Japon balığı olup olmadığını görmek olacaktır. Ne yazık ki bunu Java'dan yapmanın kolay bir yolu yok, ancak property_get () kullanarak C'den önemsiz .


4
Bu NDK'den çalışıyor gibi görünüyor. <Sys / system_properties.h> dosyasını ekleyin ve __system_property_get ("ro.hardware", buf) kullanın, sonra buflerin "goldfish" olup olmadığını kontrol edin.
NuSkooler

5

Yukarıda ANDROID_ID, Android 2.2 ile piyasaya sürülen en yeni SDK araçlarına güncelleyene kadar benim için çalışmayı kontrol etmek için önerilen çözüm .

Bu nedenle şu anda dezavantajla çalışan şu çözüme geçtim, ancak PHONE_STATE okuma iznini ( <uses-permission android:name="android.permission.READ_PHONE_STATE"/>) koymanız gerekiyor

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

Tüm cevaplar tek bir yöntemde

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

Güzel bir. init.goldfish.rcsadece emülatörlerde bulunur; Ayrıca, Yapı ayrıntılarına ek olarak ileriye dönük iyi bir kontroldür.
sud007

2
@ sud007 Orada `/init.goldfish.rc ile birçok cihaz var ve bu yanlış pozitiflere yol açacak. Örneğin, birçok Samsung Galaxy serisi cihaz.
laalto

@ laalto gerçekten haklıydın. Bunu daha sonra öğrendim ve burada güncellemeyi unuttuğum özür dilerim.
sud007

test anahtarları benim için yanlış pozitifler üretiyor.
Avi Parshan

Hangi cihazlarda yanlış pozitif üretiyorlar?
Aman Verma

5

Yeni emülatörü buldum Build.HARDWARE = "ranchu".

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

Ayrıca, emülatör olup olmadığını kontrol etmek için Android resmi yolunu buldum.

Android API Seviye 23'ten beri [Android 6.0]

package com.android.internal.util;

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

ScreenShapeHelper.IS_EMULATOREmülatör olup olmadığını kontrol etmeliyiz .

Android API Seviye 24'ten beri [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_EMULATOREmülatör olup olmadığını kontrol etmeliyiz .

Yetkilinin emülatörün yeni olup olmadığını ve aynı zamanda yeterli olmadığını kontrol etme şekli, yukarıdaki cevaplardan da bahsetti.

Ancak bu bize yetkilinin emülatörün emülatör olup olmadığını kontrol etmesini sağlayacağını gösterebilir.

Yukarıda belirtilen tüm yolları kullanırken, şu anda emülatör olup olmadığını kontrol etmek için iki yolu da kullanabiliriz.

com.android.internalPakete nasıl erişilir ve@hide

ve resmi açık SDK'yı bekleyin.


5

Benim tavsiyem:

bunu github'dan deneyin .

Kolayca algılanabilen android emülatörü

  • Device Farm'daki gerçek cihazlarda kontrol edildi ( https://aws.amazon.com/device-farm/ )
  • BlueStacks
  • Genymotion
  • Android Emülatörü
  • Andy 46.2.207.0
  • MEmu oyun
  • Nox Uygulama Oynatıcı
  • Koplayer
  • .....

Örnek ile nasıl kullanılır:

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 adresini kontrol edebilirsiniz.

öykünücü bu dönüş 0 hatırlıyorum. Ancak, bunu garanti bulabileceğiniz hiçbir belge yoktur. emülatör her zaman 0 döndürmeyebilse de, kayıtlı bir telefonun 0'ı döndürmemesi oldukça güvenli görünmektedir. ağ?

buna bağlı olmak kötü bir fikir gibi görünüyor.

ayrıca telefon durumunu okumak için izin istemeniz gerektiği anlamına gelir, bu da başka bir şey için zaten gerekli değilse kötüdür.

değilse, nihayet imzalı uygulamanızı oluşturmadan önce her zaman biraz bir yere çevirme vardır.


5
IMEI'nin muhtemelen 0bir Android tablete veya SIM kartı olmayan bir telefona dönmesi muhtemeldir .
Paul Lammertsma

Emülatörde IMEI'yi düzenleyebiliriz. dolayısıyla bu amaca hizmet etmeyebilir. Ayrıca, API 29'dan başlayarak IMEI'ye erişemiyoruz.
Ananth

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

Uygulama bir öykünücü üzerinde çalışıyorsa, bu durum doğru dönmelidir.

Dikkat etmemiz gereken şey, tüm emülatörleri tespit etmemek çünkü sadece birkaç farklı emülatör var. Kontrol etmek kolaydır. Gerçek cihazların taklitçi olarak algılanmadığından emin olmalıyız.

Bunu kontrol etmek için " Android Cihaz Bilgisi Paylaşımı " adlı uygulamayı kullandım .

Bu uygulamada, birçok cihazın çeşitli bilgilerini görebilirsiniz (muhtemelen dünyadaki çoğu cihaz; Kullandığınız cihaz listede yoksa, otomatik olarak eklenecektir).


Bir Mac üzerinde çalışan Genymotion'umda Build.DEVICE = vbox86p
lxknvlk


3

Bu benim için çalışıyor

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

3
şirket içi yazılım üreticimiz bunu güncellemedi; Donanımımız üzerinde Build.Manufacturer almak "bilinmeyen" döndü. Parmak izi daha iyi bir yol gibi görünüyor.
Birisi

3

Emülatörün dosya sistemine bir dosya koyun; dosya gerçek cihazda bulunmayacağından, sağlam, güvenilir ve kırıldığında düzeltmesi kolay olmalıdır.


3

Bu sorudaki tüm cevapları topladım ve Android'in bir vm / emülatörde çalışıp çalışmadığını tespit etme işleviyle geldim:

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

Emulator, Genymotion ve Bluestacks üzerinde test edildi (1 Ekim 2015).


3

Cevapları kontrol ederek, hiçbiri LeapDroid, Droid4x veya Andy emülatörlerini kullanırken işe yaramadı,

Tüm durumlar için işe yarayan şey şudur:

 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 Build.HARDWARE için "andy" döndürüyor
Doug Voss

Samsung J serisi cihazlar için yanlış pozitif yol açar. Emülatörü tespit etmek için aşağıdaki şekilde kullanılır: github.com/gingo/android-emulator-detector
bluetoothfx

2

Genymotion için temeldeki emülasyon motoru VirtualBox olduğundan ve yakında herhangi bir zamanda değişmeyeceği için aşağıdaki kodu en güvenilir buldum:

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

2

Eğer emülatör algılama yapmak için kullandıkları Hangi kod, ben çok yazma birimi tümünü kapsayacak şekilde testler öneriyoruz Build.FINGERPRINT, Build.HARDWAREve Build.MANUFACTURERsen bağlı olduğu değerleri. İşte bazı örnek testler:

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

... ve işte kodumuz (hata ayıklama günlükleri ve yorumları kısaca kaldırıldı):

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

Başka bir seçenek, hata ayıklama modunda mı yoksa üretim modunda mı olduğunuzu kontrol etmektir:

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

basit ve güvenilir.

Sorunun cevabı tamamen değil, çoğu durumda hata ayıklama / test oturumları ile kullanıcı tabanınızın yaşam oturumları arasında ayrım yapmak isteyebilirsiniz.

Benim durumumda, hata ayıklama modunda google analytics'i dryRun () olarak ayarladım, bu yüzden bu yaklaşım benim için tamamen iyi çalışıyor.


Daha ileri düzey kullanıcılar için başka bir seçenek daha vardır. kepçe yapı varyantları:

uygulamanızın gradle dosyasına yeni bir varyant ekleyin:

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

Kodunuzda derleme türünü kontrol edin:

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

Artık uygulamanızın 3 farklı türünü oluşturma şansınız var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.