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

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

171500 次浏览

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

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

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

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

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

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

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

另一种选择是查看ro。硬件属性,看看它是否设置为金鱼。不幸的是,在Java中似乎没有一个简单的方法来做到这一点,但在C中使用property_get ()是很简单的。

安卓id不适合我,我现在用的是:

"google_sdk".equals( Build.PRODUCT );

上面建议的检查ANDROID_ID的解决方案适用于我,直到我今天更新到最新的Android 2.2 SDK工具发布。

因此,我目前切换到以下解决方案,到目前为止,它的缺点是,你需要把PHONE_STATE读权限(<uses-permission android:name="android.permission.READ_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);
}
}

实际上,ANDROID_ID在2.2上总是等于9774年d56d682e549c(根据这个线程 +我自己的实验)。

所以,你可以这样检查:

String androidID = ...;
if(androidID == null || androidID.equals("9774D56D682E549C"))
do stuff;

虽然不是最漂亮的,但也很管用。

用下面的代码来判断你的应用是否使用了调试键?它没有检测模拟器,但它可能为您的目的工作?

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;


}

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

这对我很有用

public boolean isEmulator() {
return Build.MANUFACTURER.equals("unknown");
}

这个代码适用于我

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

如果该设备没有sim卡,它将返回空字符串:""

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

这是我的解决方案(它只适用于在调试机器上运行web服务器): 我已经创建了一个后台任务,当应用程序启动时启动。它寻找http://10.0.2.2,如果它存在,它将全局参数(IsDebug)更改为true。这是一种无声的方式来找出你在哪里运行
public class CheckDebugModeTask extends AsyncTask<String, Void, String> {
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("");

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

Build.PRODUCT
Build.MODEL

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

"google_sdk".equals(Build.MODEL)

"google_sdk".equals(Build.PRODUCT)

我从来没有找到一个很好的方法来判断你是否在模拟器中。

但如果你只是需要检测你是否在开发环境中,你可以这样做:

     if(Debug.isDebuggerConnected() ) {
// Things to do in debug environment...
}

希望对大家有所帮助....

Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

如果应用程序在模拟器上运行,这应该返回true。

我们应该注意的是不要检测所有的模拟器,因为只有几个不同的模拟器。这很容易检查。 我们必须确保实际的设备不会被检测为模拟器

我使用名为“Android设备信息共享”的应用程序来检查这一点。

在这个应用程序上,你可以看到许多设备的各种信息(可能是世界上大多数设备;如果您正在使用的设备不在列表中,它将自动添加)。

在模拟器的文件系统中放入一个文件;由于该文件不会存在于真正的设备上,这应该是稳定的,可靠的,容易修复当它崩溃。

我尝试了几种技术,但最终选择了稍微修改过的检查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"。

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

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

我只是寻找_sdk_sdk_sdk_,甚至只是Build.PRODUCT中的sdk部分:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
//-- emulator --
}else{
//-- other device --
}
if ("sdk".equals( Build.PRODUCT )) {
// Then you are running the app on the emulator.
Log.w("MyAPP", "\n\n  Emulator \n\n");
}

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

这个解决方案如何(SystemProperties的类实现可用在这里):

val isProbablyRunningOnEmulator: Boolean by lazy {
// Android SDK emulator
return@lazy ((Build.FINGERPRINT.startsWith("google/sdk_gphone_")
&& Build.FINGERPRINT.endsWith(":user/release-keys")
&& Build.MANUFACTURER == "Google" && Build.PRODUCT.startsWith("sdk_gphone_") && Build.BRAND == "google"
&& Build.MODEL.startsWith("sdk_gphone_"))
//
|| 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"
if (Build.BRAND.equalsIgnoreCase("generic")) {
// Is the emulator
}

所有BUILD引用都是BUILD。道具值,所以你必须考虑到如果你要把这个放到发布代码中,你可能会有一些根用户因为某种原因修改了他们的。实际上没有任何修改需要使用generic作为品牌,除非特别尝试模拟模拟器。

指纹是构建编译和内核编译签名。有一些构建使用通用的,通常直接来自谷歌。

在修改过的设备上,IMEI也有可能被归零,所以这是不可靠的,除非您完全阻止修改过的设备。

金鱼是所有其他设备扩展的基础android构建。每个Android设备都有一个init.金鱼.rc,除非被黑客攻击并出于未知原因删除。

由于Genymotion的底层模拟引擎是VirtualBox,这不会很快改变,我发现以下代码是最可靠的:

   public static boolean isGenymotion() {
return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}

使用这个函数:

 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;


}

我收集了关于这个问题的所有答案,并提出了一个函数来检测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日)

From Battery,模拟器: 电源永远是交流充电器。 温度总是0

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

无论你用什么代码来做模拟器检测,我强烈建议你编写单元测试来覆盖你所依赖的所有Build.FINGERPRINTBuild.HARDWAREBuild.MANUFACTURER值。下面是一些测试示例:

@Test
public void testIsEmulatorGenymotion() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator(
"generic/vbox86p/vbox86p:4.1.1/JRO03S/eng.buildbot.20150217.102902:userdebug/test-keys",
"vbox86", "Genymotion")).isTrue();


assertThat(
DeviceUtils.isRunningOnEmulator(
"generic/vbox86p/vbox86p:5.1/LMY47D/buildbot06092001:userdebug/test-keys", "vbox86",
"Genymotion")).isTrue();
}


@Test
public void testIsEmulatorDefaultAndroidEmulator() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator(
"generic_x86/sdk_google_phone_x86/generic_x86:5.0.2/LSY66H/1960483:eng/test-keys", "goldfish",
"unknown")).isTrue();


assertThat(
DeviceUtils.isRunningOnEmulator(
"Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/2469028:userdebug/test-keys",
"ranchu", "unknown")).isTrue();
}


@Test
public void testIsEmulatorRealNexus5() throws Exception {
assertThat(
DeviceUtils.isRunningOnEmulator("google/hammerhead/hammerhead:6.0.1/MMB29K/2419427:user/release-keys",
"hammerhead", "LGE")).isFalse();
}

...下面是我们的代码(为了简洁起见,删除了调试日志和注释):

public static boolean isRunningOnEmulator() {
if (sIsRunningEmulator == null) {
sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER);
}


return sIsRunningEmulator;
}


static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
|| manufacturer.equals("unknown");


if (isEmulatorFingerprint && isEmulatorManufacturer) {
return true;
} else {
return false;
}
}

所有答案都在一个方法中

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

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

另一个选择是检查你是在调试模式还是生产模式:

if (BuildConfig.DEBUG) { Log.i(TAG, "I am in debug mode"); }

简单可靠。

这并不是问题的全部答案,但在大多数情况下,您可能想要区分用户群的调试/测试会话和生命会话。

在我的情况下,我在调试模式下将谷歌分析设置为dryRun(),因此这种方法完全适合我。


对于更高级的用户,还有另一种选择。Gradle构建变量:

在你的应用程序的gradle文件中添加一个新的变体:

buildTypes {
release {
// some already existing commands
}
debug {
// some already existing commands
}
// the following is new
test {
}
}

在你的代码中检查构建类型:

if ("test".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Test build type"); }
else if ("debug".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Debug build type"); }

现在你有机会构建3种不同类型的应用程序。

我找到了新的模拟器Build.HARDWARE = "ranchu"

参考:https://groups.google.com/forum/ !主题/ android-emulator-dev / dltBnUW_HzU

而且我还找到了Android官方的方法来检查是否是模拟器。我认为这对我们是很好的参考。

Android API Level 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。

这对我来说是有效的,而不是startsWith: Build.FINGERPRINT.contains("generic")

欲了解更多信息,请查看此链接:https://gist.github.com/espinchi/168abf054425893d86d1

我的建议:

尝试从github

易于检测android模拟器

  • 在设备场中的真实设备上检查(https://aws.amazon.com/device-farm/)
  • BlueStacks
  • Genymotion
  • Android模拟器
  • 安迪46.2.207.0
  • 菜单玩
  • 诺克斯应用播放器
  • Koplayer
  • .....

如何与示例一起使用:

EmulatorDetector.with(this)
.setCheckTelephony(true)
.addPackageName("com.bluestacks")
.setDebug(true)
.detect(new EmulatorDetector.OnEmulatorDetectorListener() {
@Override
public void onResult(boolean isEmulator) {
if(isEmulator){
// Do your work
}
else{
// Not emulator and do your work
}
}
});

谷歌在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("sdk_gphone64_arm64")
|| Build.PRODUCT.contains("vbox86p")
|| Build.PRODUCT.contains("emulator")
|| Build.PRODUCT.contains("simulator");
}

试试github上的这个链接。

https://github.com/mofneko/EmulatorDetector

这个模块帮助你检测模拟器到你的Android项目支持的Unity。

基本的检查

  • BlueStacks
  • Genymotion
  • Android模拟器
  • 诺克斯应用播放器
  • Koplayer
  • .....

检查设备是否安装了这些包是一个好主意:

    mListPackageName.add("com.google.android.launcher.layouts.genymotion");
mListPackageName.add("com.bluestacks");
mListPackageName.add("com.vphone.launcher");
mListPackageName.add("com.bignox.app");

我只是把它放在一个数组列表中…

然后简单地检查包管理器,直到找到一个。

private static boolean isEmulByPackage(Context context) {
final PackageManager pm = context.getPackageManager();
for (final String pkgName : mListPackageName) {
return isPackageInstalled(pkgName, pm);
}
return false;
}


private static boolean isPackageInstalled(final String packageName, final PackageManager packageManager) {
try {
packageManager.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}

请注意,VM很可能有一些方法来欺骗应用程序,在这种情况下,可能有必要查看一些虚拟设备中不存在的物理传感器。

这是Firebase Crashlytics处理它的方式:

private static final String GOLDFISH = "goldfish";
private static final String RANCHU = "ranchu";
private static final String SDK = "sdk";
    

public static boolean isEmulator() {
return Build.PRODUCT.contains(SDK)
|| Build.HARDWARE.contains(GOLDFISH)
|| Build.HARDWARE.contains(RANCHU);
}

最常用的方法是从品牌、名称……等。但是这个方法是静态的,并且适用于模拟器的有限版本。如果有1000多家虚拟机制造商呢?那么你必须写一段代码来匹配1000多个虚拟机?

但这是浪费时间。甚至在一段时间后,会有新的vm启动,你的脚本也会被浪费。

根据我的测试,我知道了 getRadioVersion()在虚拟机上返回空, 返回真实android设备上的版本号
public Boolean IsVM()
{
return android.os.Build.getRadioVersion().length() == 0;
}
//return true if VM
//return false if real

虽然有用,但我没有官方解释。

代码: http://github.com/Back-X/anti-vm/blob/main/android/anti-vm.b4a

发布: http://github.com/Back-X/anti-vm/releases/download/1/anti-vm.apk

这个方法对我有用

    public static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
boolean isHardware = hardware.toLowerCase().contains("intel") || hardware.toLowerCase().contains("vbox");
boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
|| manufacturer.equals("unknown");


if (isHardware || isEmulatorFingerprint && isEmulatorManufacturer) {
return true;
} else {
return false;
}
}

试试这个方法。

在谷歌和Genymotion模拟器上测试。

public Boolean IsVM() {
String radioVersion = android.os.Build.getRadioVersion();
return radioVersion == null || radioVersion.isEmpty() || radioVersion.equals("1.0.0.0");
}

在Android Studio [Run >编辑配置…>启动标志)

在启动标志中添加以下内容…

--ei running_emulator 1

然后在你的onCreate活动中

Bundle extras = getIntent().getExtras();
if (extras.getInt("running_emulator", 0) == 1) {
//Running in the emulator!... Make USE DEV ENV!!
}

简单!