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


当前回答

您可以检查deviceId (IMEI)是否为“000000000000000”(15个零)

其他回答

不知道是否有更好的方法来检测emu,但模拟器将在根目录下有init.金鱼.rc文件。

它是特定于模拟器的启动脚本,在非模拟器构建中不应该出现。

来自模拟器《Battery》: 电源永远是交流充电器。 温度总是0。

您可以使用Build。HOST用来记录主机值,不同的模拟器有不同的主机值。

我只是寻找_sdk, _sdk_或sdk_,甚至只是sdk部分构建。产品:

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

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

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

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

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

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

这个解决方案怎么样(SystemProperties的类实现在这里可用):

val isProbablyRunningOnEmulator: Boolean by lazy {
    // Android SDK emulator
    return@lazy ((Build.MANUFACTURER == "Google" && Build.BRAND == "google" &&
            ((Build.FINGERPRINT.startsWith("google/sdk_gphone_")
                    && Build.FINGERPRINT.endsWith(":user/release-keys")
                    && Build.PRODUCT.startsWith("sdk_gphone_")
                    && Build.MODEL.startsWith("sdk_gphone_"))
                    //alternative
                    || (Build.FINGERPRINT.startsWith("google/sdk_gphone64_")
                    && (Build.FINGERPRINT.endsWith(":userdebug/dev-keys") || Build.FINGERPRINT.endsWith(":user/release-keys"))
                    && Build.PRODUCT.startsWith("sdk_gphone64_")
                    && Build.MODEL.startsWith("sdk_gphone64_"))))
            //
            || 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")
            //bluestacks
            || "QC_Reference_Phone" == Build.BOARD && !"Xiaomi".equals(Build.MANUFACTURER, ignoreCase = true)
            //bluestacks
            || Build.MANUFACTURER.contains("Genymotion")
            || Build.HOST.startsWith("Build")
            //MSI App Player
            || Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
            || Build.PRODUCT == "google_sdk"
            // another Android SDK emulator check
            || SystemProperties.getProp("ro.kernel.qemu") == "1")
}

请注意,一些模拟器伪造真实设备的精确规格,因此可能无法检测到它。我已经添加了我能添加的东西,但我不认为有100%的方法来检测它是否真的是一个模拟器。

这里有一个你可以在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"