如何从代码中找出我的 Android 应用程序是在模拟器还是真实设备上运行?

Posted

技术标签:

【中文标题】如何从代码中找出我的 Android 应用程序是在模拟器还是真实设备上运行?【英文标题】:How to find out from code if my Android app runs on emulator or real device? 【发布时间】:2011-10-15 09:48:08 【问题描述】:

我已经阅读了this *** thread,并尝试使用该答案中给出的代码来确定我是在模拟器还是在真实设备上运行我的代码:

import android.content.ContentResolver;
import android.provider.Settings.Secure;
...     
mTextView.setText(Secure.getString(getContentResolver(), Secure.ANDROID_ID));

在我的真实设备上它返回“2bccce3...”,但是在模拟器上它不返回空值,而是一个字符串“bd9f8...”

非常感谢如何从代码中找出模拟器或真实设备的想法

【问题讨论】:

【参考方案1】:

应该这样做:

boolean inEmulator = false;
String brand = Build.BRAND;
if (brand.compareTo("generic") == 0)

    inEmulator = true;

编辑:

boolean inEmulator = "generic".equals(Build.BRAND.toLowerCase());

【讨论】:

是的,我认为这比我发现的其他方法更可靠。不过,我很确定,没有人写下这对于模拟器来说永远都是正确的。 (我敢打赌,这对于所有设备都是错误的,尽管可能没有人能保证这一点。)顺便说一句,我认为你的代码作为单行代码会很清楚:boolean inEmulator = "generic".equals(Build.BRAND); 对其进行了编辑以使其更加清晰。谢谢你的建议。另外,我认为这应该适用于至少大多数设备,因为我在 1.5、1.6 和 2.1 的模拟器上对此进行了测试,并且它有效。 我也在 2.3.3 模拟器上对其进行了测试。我还在三星的 Galaxy Tab 和 Sony Erikson 的 ETK 模拟器上对其进行了测试,效果很好。但谁知道它是否会在未来发挥作用。 好吧,我不认为未来有任何理由改变价值。对于所有模拟器来说,保持该值相同似乎是合理的。如果有任何差异,只会使事情复杂化。 这将满足我的需求,尽管,正如@Ted 提到的“谁知道它是否会在未来发挥作用”。我需要知道我是否在真实设备上,以确保我不运行调试代码。我不认为硬件设备品牌被称为“通用”。如果将来模拟器改变了,我会简单地调整我的代码。对我来说很好。问题已回答。谢谢阿拉什【参考方案2】:

随着新的英特尔本机模拟器的出现,上述方法不再适用。现在我正在使用这段代码 sn-p,它适用于 Intel 和 ARM 仿真器:

if (Build.MODEL.contains("google_sdk") ||
    Build.MODEL.contains("Emulator") ||
    Build.MODEL.contains("Android SDK")) 
  RunsInEmulator = true;

【讨论】:

【参考方案3】:

有一个相当古老的thread on Android Developers group 建议检查设备上的传感器数量。这样的事情可能会奏效:

SensorManager manager = (SensorManager) getSystemService(SENSOR_SERVICE);
if (manager.getSensorList(Sensor.TYPE_ALL).isEmpty()) 
    // running on an emulator
 else 
    // running on a device

我没有试过这个,所以我不知道这个建议有多可靠。 (也许现在有些模拟器报告了一些传感器;也许有些设备报告没有传感器。[是否有 Android 牙刷?])但它不会比检查空 ANDROID_ID 更糟糕(从 2.2 起不起作用)。

附: Another thread 声称从 2.2 开始,模拟器的 ANDROID_ID 始终为“9774D56D682E549C”。但是,您显然得到了一些其他的十六进制字符串,所以我认为这也不正确。

附言我没有尝试过的其他建议是here。一个看起来特别好的(如果有效的话)是:

if (android.os.Build.MODEL.equals(“google_sdk”)) 
   // emulator
 else 
   //not emulator

【讨论】:

我已经尝试过 P.P.S. 中给出的那个。在 3.0 模拟器(使用 Google 地图 API)和设备 Nexus One、摩托罗拉 defy 和三星 Galaxy S 上。它按预期工作。这应该符合我的目的,即使将来模拟器的模型会发生变化,我也会适应。只有一件事最不会发生:如果应用程序是真实设备,则假设它可以在模拟器上运行。然而,真正的设备模型不太可能被命名为“google_sdk”。所以这解决了我的问题。非常感谢特德 传感器检查对我不起作用。 Emulator 的传感器列表并没有空出来,而是像一个设备一样工作。【参考方案4】:

我认为最好的答案是确定您真正关心了解的原因 - 然后检查您认为需要您的应用程序行为不同于设备上的模拟器的任何特定特征 .

【讨论】:

我需要在模拟器模式下运行调试代码。 所以我需要的是能够明确告诉我我在真实设备上的东西,以确保执行“真实代码”。如果将来对模拟器的检查失败,这不是什么大问题,我可以轻松适应。 @Ted 在 P.P.S 中对他的回答进行了试用,这对我的目的有用,请参阅我对他的回答的评论 我建议你将调试与模拟器/设备分开,因为有时你会发现你需要在真实设备上运行调试代码,因为它会暴露出模拟器没有的问题。 【参考方案5】:

这个解决方案怎么样:

  public static boolean isRunningOnEmulator()
    
    boolean result=//
        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");
    if(result)
      return true;
    result|=Build.BRAND.startsWith("generic")&&Build.DEVICE.startsWith("generic");
    if(result)
      return true;
    result|="google_sdk".equals(Build.PRODUCT);
    return result;
    

编辑:似乎我已经在这里回答了这个问题:

https://***.com/a/21505193/878126

【讨论】:

【参考方案6】:

如this post 中所述,IMEI 和 IMSI 在模拟器上进行了编码:

2325      "+CIMI", OPERATOR_HOME_MCCMNC "000000000", NULL ,   /* request internation subscriber identification number */
2326      "+CGSN", "000000000000000", NULL ,   /* request model version */

您可以使用

轻松获得价值
adb shell dumpsys iphonesubinfo

因此,使用 TelephonyManager.getDeviceId() 检查设备的 IMEI 应该足以确定您使用的是模拟器还是真实设备。为了绝对确定,您可以将其与检查各种其他帖子所述的型号名称。

public static boolean isRunningOnEmulator(final Context inContext) 

    final TelephonyManager theTelephonyManager = (TelephonyManager)inContext.getSystemService(Context.TELEPHONY_SERVICE);
    final boolean hasEmulatorImei = theTelephonyManager.getDeviceId().equals("000000000000000");
    final boolean hasEmulatorModelName = Build.MODEL.contains("google_sdk")
            || Build.MODEL.contains("Emulator")
            || Build.MODEL.contains("Android SDK");

    return hasEmulatorImei || hasEmulatorModelName;

这种方法的缺点是您需要一个上下文来访问此信息并为每次检查实例化一个 TelephonyManager。

【讨论】:

【参考方案7】:

这是标准的 google flutter 模拟器检查:

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

【讨论】:

【参考方案8】:

以下是正确检测到我的模拟器

if (Build.BRAND.equalsIgnoreCase("generic")) 
              //"YES, I am an emulator"
        else 
              //"NO, I am NOT an emulator"
       

【讨论】:

【参考方案9】:

在撰写本文时,除了尝试检查传感器外,此线程中的任何内容都不适用于 Bluestacks 4 模拟器。所以我用这个gist检查了电池温度。它应该返回0.0,这意味着它没有电池温度(因此它是一个模拟器)。

public float getCpuTemp() 
    Process process;
    try 
        process = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone0/temp");
        process.waitFor();
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = reader.readLine();
        float temp = Float.parseFloat(line) / 1000.0f;
        return temp;
     catch (Exception e) 
        e.printStackTrace();
        return 0.0f;
    

【讨论】:

我还应该注意,这包括所有模拟器。对于 Bluestacks 4,您可以创建一个函数来检测 sdcard 中的 windows 文件夹。

以上是关于如何从代码中找出我的 Android 应用程序是在模拟器还是真实设备上运行?的主要内容,如果未能解决你的问题,请参考以下文章