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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2799097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:26:16  来源:igfitidea点击:

How can I detect when an Android application is running in the emulator?

androidandroid-emulator

提问by Joe Ludwig

I would like to have my code run slightly differently when running on the emulator than when running on a device. (For example, using 10.0.2.2 instead of a public URL to run against a development server automatically.) What is the best way to detect when an Android application is running in the emulator?

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

回答by android developer

How about this solution:

这个解决方案怎么样:

    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

Note that some emulators fake exact specs of real devices, so it might be impossible to detect it.

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

Here a tiny snippet you can make in the APK to show various things about it, so you could add your own rules:

这里有一个小片段,您可以在 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"

回答by Aleadam

One common one sems to be Build.FINGERPRINT.contains("generic")

一种常见的似乎是 Build.FINGERPRINT.contains("generic")

回答by Marcus

Well Android id does not work for me, I'm currently using:

好吧,Android id 对我不起作用,我目前正在使用:

"google_sdk".equals( Build.PRODUCT );

回答by Vitali

Based on hints from other answers, this is probably the most robust way:

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

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

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

回答by Rockney

Google uses this code in the device-info pluginfrom Flutter to determine if the device is an emulator:

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

回答by Jeff S

How about something like the code below to tell if your app was signed with the debug key? it's not detecting the emulator but it might work for your purpose?

用下面的代码来判断你的应用程序是否使用调试密钥签名怎么样?它没有检测到模拟器,但它可能适用于您的目的?

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;

} 

回答by J.J. Kim

This code works for me

这段代码对我有用

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

In case that device does not have sim card, It retuns empty string:""

如果该设备没有 SIM 卡,则返回空字符串:""

Since Android emulator always retuns "Android" as network operator, I use above code.

由于 Android 模拟器总是将“Android”作为网络运营商,我使用上面的代码。

回答by Patrick

I tried several techniques, but settled on a slightly revised version of checking the Build.PRODUCT as below. This seems to vary quite a bit from emulator to emulator, that's why I have the 3 checks I currently have. I guess I could have just checked if product.contains("sdk") but thought the check below was a bit safer.

我尝试了几种技术,但最终确定了检查 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;
}

FYI - I found that my Kindle Fire had Build.BRAND = "generic", and some of the emulators didn't have "Android" for the network operator.

仅供参考 - 我发现我的 Kindle Fire 有 Build.BRAND = "generic",有些模拟器没有网络运营商的 "Android"。

回答by Sileria

Both the following are set to "google_sdk":

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

Build.PRODUCT
Build.MODEL

So it should be enough to use either one of the following lines.

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

"google_sdk".equals(Build.MODEL)

or

或者

"google_sdk".equals(Build.PRODUCT)

回答by S.D.

I just look for _sdk, _sdk_or sdk_, or even just sdkpart in Build.PRODUCT:

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

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