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


当前回答

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

如果我在模拟器上调用这个返回0。然而,我找不到任何文件可以保证这一点。虽然模拟器可能不总是返回0,但注册的电话不返回0似乎是相当安全的。在非手机的安卓设备上,或者没有安装SIM卡,或者没有在网络上注册的设备上,会发生什么呢?

似乎这是个坏主意,依赖于它。

这也意味着你需要获得读取手机状态的许可,如果你不需要它来做其他事情,这是很糟糕的。

如果不是这样,那么在你最终生成签名应用之前,总是会有一些翻转。

其他回答

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

isEmulator = "金鱼".equals(Build.HARDWARE)

检查答案,当使用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;
}

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

如果我在模拟器上调用这个返回0。然而,我找不到任何文件可以保证这一点。虽然模拟器可能不总是返回0,但注册的电话不返回0似乎是相当安全的。在非手机的安卓设备上,或者没有安装SIM卡,或者没有在网络上注册的设备上,会发生什么呢?

似乎这是个坏主意,依赖于它。

这也意味着你需要获得读取手机状态的许可,如果你不需要它来做其他事情,这是很糟糕的。

如果不是这样,那么在你最终生成签名应用之前,总是会有一些翻转。

我收集了关于这个问题的所有答案,并提出了一个函数来检测Android是否运行在虚拟机/模拟器上:

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日)

我尝试了几种技术,但最终选择了稍微修改过的检查Build的版本。产品如下。这似乎变化很大,从模拟器到模拟器,这就是为什么我有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"。