我希望我的代码在模拟器上运行时的运行方式与在设备上运行时的运行方式略有不同.(例如,使用10.0.2.2而不是公共URL自动针对开发服务器运行.)检测Android应用程序何时在模拟器中运行的最佳方法是什么?
这个解决方案怎么样:
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
一个常见的sems是 Build.FINGERPRINT.contains("generic")
好的Android ID对我不起作用,我目前正在使用:
"google_sdk".equals( Build.PRODUCT );
基于其他答案的提示,这可能是最强大的方式:
isEmulator = "goldfish".equals(Build.HARDWARE)
下面的代码如何判断您的应用程序是否使用调试密钥签名?它没有检测到模拟器,但它可能适用于您的目的?
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; }
这段代码适合我
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String networkOperator = tm.getNetworkOperatorName(); if("Android".equals(networkOperator)) { // Emulator } else { // Device }
如果该设备没有SIM卡,它会返回空字符串:""
由于Android模拟器总是将"Android"作为网络运营商回归,我使用上面的代码.
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"); }
以下两项都设置为"google_sdk":
Build.PRODUCT Build.MODEL
所以它应该足以使用以下任一行.
"google_sdk".equals(Build.MODEL)
要么
"google_sdk".equals(Build.PRODUCT)
我尝试了几种技术,但确定了稍微修改后的版本,检查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".
我只是寻找_sdk
,_sdk_
或者sdk_
,甚至只是sdk
部分Build.PRODUCT
:
if(Build.PRODUCT.matches(".*_?sdk_?.*")){ //-- emulator -- }else{ //-- other device -- }
我从来没有找到一个很好的方法来判断你是否在模拟器中.
但如果您只是需要检测您是否在开发环境中,则可以执行以下操作:
if(Debug.isDebuggerConnected() ) { // Things to do in debug environment... }
希望这有帮助....
使用此功能:
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; }
不知道是否有更好的方法来检测emu,但模拟器将文件init.goldfish.rc
放在根目录中.
它是模拟器特定的启动脚本,它不应该在非模拟器构建中存在.
这是我的解决方案(仅当您在调试计算机上运行Web服务器时才有效):我创建了一个后台任务,该任务在应用程序启动时启动.它查找http://10.0.2.2,如果它存在,则将全局参数(IsDebug)更改为true.这是一种无声的方式来找出你在哪里跑步.
public class CheckDebugModeTask extends AsyncTask{ 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("");
从电池,仿真器:电源始终是AC充电器.温度始终为0.
并且您可以使用Build.HOST
记录主机值,不同的仿真器具有不同的主机值.
另一个选择是查看ro.hardware属性并查看它是否设置为goldfish.不幸的是,似乎没有一种简单的方法可以从Java中做到这一点,但是使用property_get()从C中做到这一点很简单.
以上建议的解决方案来检查ANDROID_ID
我的工作情况,直到我今天更新到Android 2.2发布的最新SDK工具.
因此,我目前切换到以下解决方案,到目前为止工作的缺点是,你需要把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); } }
一种方法的所有答案
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; }
我找到了新的模拟器Build.HARDWARE = "ranchu"
。
参考:https : //groups.google.com/forum/#!topic/android-emulator- dev/ dltBnUW_HzU
我也找到了Android官方方法来检查是否模拟器,我认为这对我们来说是很好的参考。
从Android API级别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。
My recommendation:
try this from github.
Easy to detect android emulator
Checked on real devices in Device Farm (https://aws.amazon.com/device-farm/)
BlueStacks
Genymotion
Android Emulator
Andy 46.2.207.0
MEmu play
Nox App Player
Koplayer
.....
How to use with an Example:
EmulatorDetector.with(this) .setCheckTelephony(true) .addPackageName("com.bluestacks") .setDebug(true) .detect(new EmulatorDetector.OnEmulatorDetectorListener() { @Override public void onResult(boolean isEmulator) { } });