如何检测模拟器中正在运行Android应用程序的时间?


313

我希望在模拟器上运行的代码与在设备上运行的代码略有不同。(例如,使用10.0.2.2代替公共URL自动针对开发服务器运行。)检测Android应用程序何时在模拟器中运行的最佳方法是什么?


2
可以看看android.os.Build
扬琴科

11
令我惊讶... Google应该有标准的方法吗?
powder366 2014年

@kreker,您在现有解决方案中面临的问题是什么?
Khemraj '18年

@Khemraj欺诈问题。邪恶的家伙可以嘲笑一些传感器并更改一些字符串以假装真实设备
kreker

Answers:


158

该解决方案如何:

    fun isProbablyAnEmulator() = Build.FINGERPRINT.startsWith("generic")
            || Build.FINGERPRINT.startsWith("unknown")
            || Build.MODEL.contains("google_sdk")
            || Build.MODEL.contains("Emulator")
            || Build.MODEL.contains("Android SDK built for x86")
            || Build.BOARD == "QC_Reference_Phone" //bluestacks
            || Build.MANUFACTURER.contains("Genymotion")
            || Build.HOST.startsWith("Build") //MSI App Player
            || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
            || "google_sdk" == Build.PRODUCT

请注意,某些仿真器会伪造真实设备的确切规格,因此可能无法检测到。

您可以在APK中制作一个小片段来显示有关它的各种内容,因此可以添加自己的规则:

        textView.text = "FINGERPRINT:${Build.FINGERPRINT}\n" +
                "MODEL:${Build.MODEL}\n" +
                "MANUFACTURER:${Build.MANUFACTURER}\n" +
                "BRAND:${Build.BRAND}\n" +
                "DEVICE:${Build.DEVICE}\n" +
                "BOARD:${Build.BOARD}\n" +
                "HOST:${Build.HOST}\n" +
                "PRODUCT:${Build.PRODUCT}\n"

9
这就是Facebook在React-Native中检测模拟器的方式
Vaiden

这是我使用@Aleadam的答案相当一段时间后必须更新的内容(它已停止为我工作)。
ckbhodge '16

@Sid应该添加什么?
Android开发人员

2
@Sid您是否在那里打印了各种Build类变量?似乎没什么特别的吗?您是否尝试过:github.com/framgia/android-emulator-detector
Android开发人员

1
@DrDeo您可以使用BuildConfig.DEBUG添加对当前版本的检查,或使用自己的自定义变量创建自己的版本。您也许还可以使用Proguard使此函数始终返回false或其他内容(例如,您可以删除日志,如下所示:medium.com/tixdo-labs/…,所以也许也可以)
android developer

118

一种常见的一种说法是 Build.FINGERPRINT.contains("generic")


即使在Galaxy Tab模拟器中也可以使用。最喜欢的答案没有。
BufferStack 2012年

10
请说明包含“通用”指纹的指纹是模拟器还是设备。该信息是关键,但未提供。
James Cameron

2
仿真器-根据您面前的评论判断:)
Dori

7
请在运行CyanogenMod的设备上返回true。
ardevd 2015年

8
Android文档说,你不应该试图解释FINGERPRINT值。
gnuf 2015年

64

Android id不适用于我,我目前正在使用:

"google_sdk".equals( Build.PRODUCT );

35
任何阅读此内容的人都可能想知道此字符串似乎已更改为“ sdk”,而不是“ google_sdk”。
Daniel Sloof

15
@Daniel:我在Google API中使用2.3.3,并说“ google_sdk”。对于使用Google API的AVD,似乎是“ google_sdk”,对于普通的,似乎是“ sdk”。
Randy Sugianto'Yuku'2011-4-25

3
英特尔仿真器返回“ full_x86”,因此我不会指望此方法。
user462982

3
@GlennMaynard反向形式很丑陋,但很实用:Build.PRODUCT可以为null,而“ google_sdk”则不能,因此这种形式避免了潜在的null引用错误。
鲁珀特·罗恩斯利

4
包括更多情况:“ google_sdk” .equals(Build.PRODUCT)|| “ sdk” .equals(Build.PRODUCT)|| “ sdk_x86” .equals(Build.PRODUCT)|| “ vbox86p” .equals(Build.PRODUCT)
Alberto Alonso Ruibal 2014年

31

根据其他答案的提示,这可能是最可靠的方法:

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


是。与Build.PRODUCT不同,对于官方SDK和AOSP,Build.HARDWARE(金鱼)是相同的。在API 8之前,您必须使用反射来获得HARDWARE字段。
David Chandler 2013年

4
我会去isEmulator = Build.HARDWARE.contains("golfdish")
holmes

7
@holmes:错字,S / b“金鱼”
诺亚

7
对于Android 5.1 x86_64映像(可能还有其他较新的64位映像),它将是“ ranchu”而不是“ goldfish”。
warbi'9

28

Google使用Flutter 的device-info插件中的以下代码来确定设备是否为模拟器:

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

20

类似于下面的代码(告诉您的应用是否已使用调试键签名)怎么样?它没有检测到仿真器,但可能对您有用吗?

public void onCreate Bundle b ) {
   super.onCreate(savedInstanceState);
   if ( signedWithDebugKey(this,this.getClass()) ) {
     blah blah blah
   }

  blah 
    blah 
      blah

}

static final String DEBUGKEY = 
      "get the debug key from logcat after calling the function below once from the emulator";    


public static boolean signedWithDebugKey(Context context, Class<?> cls) 
{
    boolean result = false;
    try {
        ComponentName comp = new ComponentName(context, cls);
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(),PackageManager.GET_SIGNATURES);
        Signature sigs[] = pinfo.signatures;
        for ( int i = 0; i < sigs.length;i++)
        Log.d(TAG,sigs[i].toCharsString());
        if (DEBUGKEY.equals(sigs[0].toCharsString())) {
            result = true;
            Log.d(TAG,"package has been signed with the debug key");
        } else {
            Log.d(TAG,"package signed with a key other than the debug key");
        }

    } catch (android.content.pm.PackageManager.NameNotFoundException e) {
        return false;
    }

    return result;

} 

1
感谢您提供此代码。我已经检查过并且它正在工作,阿尔多应对长调试键可能很痛苦,但是只能完成一次。这是唯一可靠的解决方案,因为所有其他答案都将OS构建信息字符串的某些部分与静态字符串进行了比较,并且可以(并且已经在Android SDK版本上进行了更改),也可以通过自定义Android构建来伪造。
ZoltanF 2011年

我认为这是唯一可靠的解决方案。但是,调试键的更改速度可能比我们想要的快。
rds 2012年

2
更好的方法是BuildConfig.DEBUG
Mygod '17

13

该代码对我有用

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

如果该设备没有SIM卡,它将重新调整空字符串:“”

由于Android模拟器总是将“ Android”重新调谐为网络运营商,因此我使用上面的代码。


3
没有SIM卡的设备(例如平板电脑)会返回什么?
rds 2012年

运行适用于Android 2.1的模拟器。这段代码对我有用,但是由于将Cordova升级到2.7.0,因此Context变量似乎是未定义的。这是我在ADT中遇到的错误:“上下文无法解析为变量。” 另外,根据上面的评论,这不是一种可靠的方法(尽管我自己并未使它失败)。
Rustavore

2
@rds没有SIM卡的设备返回空字符串(“”)
JJ Kim

模拟器无法获得此值吗?因为我想阻止所有没有SIM卡的用户。
c-

11

以下两项都设置为“ google_sdk”:

Build.PRODUCT
Build.MODEL

因此,使用以下任一行就足够了。

"google_sdk".equals(Build.MODEL)

要么

"google_sdk".equals(Build.PRODUCT)

在Windows上运行x86模拟器时,Build.Product为sdk_x86
爱德华·布雷

使用PRODUCT进行检查不是一个好选择,因为它会从不同的仿真器返回各种值
Beeing Jk

11

我尝试了几种技术,但选择了对Build.PRODUCT进行稍微修改的版本,如下所示。各个仿真器之间的差异似乎相差很大,这就是为什么我要拥有当前拥有的3张支票的原因。我想我可以检查一下product.contains(“ sdk”),但认为以下检查更安全。

public static boolean isAndroidEmulator() {
    String model = Build.MODEL;
    Log.d(TAG, "model=" + model);
    String product = Build.PRODUCT;
    Log.d(TAG, "product=" + product);
    boolean isEmulator = false;
    if (product != null) {
        isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
    }
    Log.d(TAG, "isEmulator=" + isEmulator);
    return isEmulator;
}

仅供参考-我发现我的Kindle Fire拥有Build.BRAND =“ generic”,并且某些仿真器没有网络运营商的“ Android”。


10

我只是寻找_sdk_sdk_sdk_,甚至只是sdk参与其中Build.PRODUCT

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

3
为什么不只是contains("sdk")呢?唯一的区别(不是更快)是matches(".*_?sdk_?.*")要求在sdk之前或之后有一个字符,它必须是下划线'_',这并不是很重要的检查。
Nulano 2015年

9

我从来没有找到一种好的方法来判断您是否在模拟器中。

但是如果您只是在开发环境中需要检测,则可以执行以下操作:

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

希望能有所帮助。


8

使用此功能:

 public static final boolean isEmulator() {

    int rating = 0;

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

    return rating > 4;

    }

7

不知道是否有更好的方法来检测emu,但是模拟器将拥有该文件 init.goldfish.rc放在根目录中。

这是特定于模拟器的启动脚本,不应在非模拟器构建中存在。


在Android系统启动期间,Linux内核首先将进程称为“ init”。init读取文件“ /init.rc”和“ init.device.rc”。“ init.device.rc”是特定于设备的,在虚拟设备上,此文件称为“ init.goldfish.rc”。
NET3

7

这是我的解决方案(仅当您在调试计算机上运行Web服务器时,该方法才有效):我创建了一个后台任务,该任务在应用程序启动时启动。它查找http://10.0.2.2,如果存在,它将一个全局参数(IsDebug)更改为true。这是找出您在哪里跑步的一种无声方式。

public class CheckDebugModeTask extends AsyncTask<String, Void, String> {
public static boolean IsDebug = false;

public CheckDebugModeTask()
{

}

@Override
protected String doInBackground(String... params) {     
  try {
    HttpParams httpParameters = new BasicHttpParams();
    int timeoutConnection = 1000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    int timeoutSocket = 2000;
    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

    String url2 = "http://10.0.2.2";        
          HttpGet httpGet = new HttpGet(url2);
    DefaultHttpClient client = new DefaultHttpClient(httpParameters);

    HttpResponse response2 = client.execute(httpGet);
    if (response2 == null || response2.getEntity() == null || response2.getEntity().getContent() == null)
    return "";

    return "Debug";

} catch (Exception e) {
    return "";
}
}

@Override
protected void onPostExecute (String result)
{       
if (result == "Debug")
{
    CheckDebugModeTask.IsDebug = true;
}
}

从onCreate的主要活动中:

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

7

通过电池,仿真器:电源始终是交流充电器。温度始终为0。

并且您可以Build.HOST用来记录主机值,不同的仿真器具有不同的主机值。


您如何获得电源和温度?
Android开发人员

5

另一个选择是查看ro.hardware属性,并查看其是否设置为goldfish。不幸的是,似乎没有一种简单的方法可以从Java做到这一点,但是使用property_get()从C做到这一点却微不足道。


4
这似乎在NDK中起作用。包括<sys / system_properties.h>并使用__system_property_get(“ ro.hardware”,buf),然后检查buf是否为“金鱼”。
NuSkooler

5

以上建议的解决方案可以ANDROID_ID为我检查是否有效,直到我今天更新为随Android 2.2一起发布的最新SDK工具。

因此,我目前切换到以下解决方案,该解决方案目前为止仍具有缺点,但是您需要设置PHONE_STATE读取权限(<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

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

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

5

所有答案合而为一

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

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

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

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

    return false;
}

好一个。init.goldfish.rc仅存在于模拟器中;除了构建细节外,它还是一个不错的检查。
sud007 '16

2
@ sud007有很多带有`/init.goldfish.rc的设备,这将导致误报。例如,许多三星Galaxy系列设备。
laalto

@laalto您实际上是正确的。后来我发现了这一点,很抱歉我在这里忘记对其进行更新。
sud007 '18

测试键一直在为我产生误报。
阿维·帕山

他们在哪些设备上产生误报?
阿曼·维尔玛

5

我找到了新的模拟器 Build.HARDWARE = "ranchu"

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

我也找到了Android官方方法来检查是否模拟器,我认为这对我们来说是很好的参考。

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

我们必须ScreenShapeHelper.IS_EMULATOR检查模拟器。

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

}

我们必须Build.IS_EMULATOR检查模拟器。

上面提到的答案还包括官方检查模拟器是否新颖的方法,也许还不够。

但这也许向我们表明,官员将提供官员检查模拟器的方式。

正如上面提到的所有方法一样,现在我们还可以使用两种方法来检查是否为模拟器。

如何访问com.android.internal包和@hide

然后等待官方开放的SDK。


5

我的建议:

试试这个从GitHub。

易于检测的Android模拟器

如何搭配范例使用:

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

                    }
                });

4

您可以检查IMEI#, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

如果我记得在模拟器上返回0。但是,没有文档可以保证这一点。尽管仿真器可能不会始终返回0,但注册的电话不会返回0似乎非常安全。在非电话的android设备上,未安装SIM卡的设备或当前未在SIM卡上注册的设备上会发生的情况。网络?

依靠它似乎是一个坏主意。

这也意味着您需要请求读取手机状态的许可,如果您还不需要其他条件的话,那就不好了。

如果不是那样,那么在最终生成签名的应用程序之前,总会有一些麻烦。


5
IMEI也可能会0在Android平板电脑或没有SIM卡的手机上返回。
Paul Lammertsma 2011年

我们可以在模拟器上编辑IMEI。因此这可能无法达到目的。另外,从API 29开始,我们将无法访问IMEI。
Ananth

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

如果应用程序在模拟器上运行,则应返回true。

我们应该注意的是不要检测所有仿真器,因为只有几个不同的仿真器。很容易检查。我们必须确保没有将实际设备检测为仿真器。

我使用了名为“ Android设备信息共享 ”对此进行了检查。

在此应用程序上,您可以看到许多设备的各种信息(可能是世界上大多数设备;如果列表中缺少您正在使用的设备,则会自动添加该信息)。


在Mac上运行的Genymotion上,Build.DEVICE = vbox86p
lxknvlk


3

这对我有用

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

3
我们内部的固件工程师没有对此进行更新;在我们的硬件上获取Build.Manufacturer返回“未知”。指纹似乎是一种更好的方法。
某处某人


3

我已经收集了有关此问题的所有答案,并提出了功能来检测Android是否在vm / emulator上运行:

public boolean isvm(){


        StringBuilder deviceInfo = new StringBuilder();
        deviceInfo.append("Build.PRODUCT " +Build.PRODUCT +"\n");
        deviceInfo.append("Build.FINGERPRINT " +Build.FINGERPRINT+"\n");
        deviceInfo.append("Build.MANUFACTURER " +Build.MANUFACTURER+"\n");
        deviceInfo.append("Build.MODEL " +Build.MODEL+"\n");
        deviceInfo.append("Build.BRAND " +Build.BRAND+"\n");
        deviceInfo.append("Build.DEVICE " +Build.DEVICE+"\n");
        String info = deviceInfo.toString();


        Log.i("LOB", info);


        Boolean isvm = false;
        if(
                "google_sdk".equals(Build.PRODUCT) ||
                "sdk_google_phone_x86".equals(Build.PRODUCT) ||
                "sdk".equals(Build.PRODUCT) ||
                "sdk_x86".equals(Build.PRODUCT) ||
                "vbox86p".equals(Build.PRODUCT) ||
                Build.FINGERPRINT.contains("generic") ||
                Build.MANUFACTURER.contains("Genymotion") ||
                Build.MODEL.contains("Emulator") ||
                Build.MODEL.contains("Android SDK built for x86")
                ){
            isvm =  true;
        }


        if(Build.BRAND.contains("generic")&&Build.DEVICE.contains("generic")){
            isvm =  true;
        }

        return isvm;
    }

在模拟器,Genymotion和Bluestacks上进行了测试(2015年10月1日)。


3

检查答案,在使用LeapDroid,Droid4x或Andy仿真器时,它们都无效,

适用于所有情况的内容如下:

 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返回“ andy”
Doug Voss,

三星J系列设备的误报率较高。以下用于检测模拟器:github.com/gingo/android-emulator-detector
bluetoothfx

2

由于Genymotion的基础仿真引擎是VirtualBox,并且不会很快改变,因此我发现以下代码最可靠:

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

2

无论使用哪种代码来执行模拟器检测,我会强烈建议编写单元测试,以覆盖所有的Build.FINGERPRINTBuild.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();
}

...这是我们的代码(为简洁起见,删除了调试日志和注释):

public static boolean isRunningOnEmulator() {
    if (sIsRunningEmulator == null) {
        sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER);
    }

    return sIsRunningEmulator;
}

static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
    boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
    boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
            || manufacturer.equals("unknown");

    if (isEmulatorFingerprint && isEmulatorManufacturer) {
        return true;
    } else {
        return false;
    }
}

2

另一个选择是检查您是处于调试模式还是生产模式:

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

简单可靠。

并非完全是问题的答案,但是在大多数情况下,您可能希望区分调试/测试会话和用户群的生命周期。

就我而言,我在调试模式下将Google Analytics(分析)设置为dryRun(),因此这种方法对我来说完全可以使用。


对于更高级的用户,还有另一种选择。gradle构建变体:

在应用程序的gradle文件中添加新的变体:

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

在您的代码中检查构建类型:

if ("test".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Test build type"); }
 else if ("debug".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Debug build type"); }

现在,您有机会构建3种不同类型的应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.