当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何检测Android应用程序何时在模拟器中运行?》经验,为你挑选了20个好方法。

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



1> android deve..:

这个解决方案怎么样:

    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


这就是Facebook在React-Native中检测模拟器的方式
@Sid您是否在那里打印了各种Build类变量?似乎没什么特别的吗?您是否尝试过:https://github.com/framgia/android-emulator-detector?

2> Aleadam..:

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


"contains"而不是"startsWith"也适用于x86
请说明包含"generic"的指纹是模拟器还是设备.该信息是关键但未提供.
这在我运行CyanogenMod的设备上返回true,所以要小心.
[Android文档](https://developer.android.com/reference/android/os/Build.html#FINGERPRINT)表示您不应该尝试解释`FINGERPRINT`值.
模拟器 - 根据您之前的评论判断:)

3> Marcus..:

好的Android ID对我不起作用,我目前正在使用:

"google_sdk".equals( Build.PRODUCT );


阅读此内容的任何人都可能有兴趣知道此字符串似乎已更改为"sdk",而不是"google_sdk".
@Daniel:我使用2.3.3与谷歌API,它说'google_sdk'.对于使用Google API的AVD而言,它似乎是'google_sdk',对于普通的API,它是'sdk'.
包括更多案例:"google_sdk".equals(Build.PRODUCT)|| "sdk".equals(Build.PRODUCT)|| "sdk_x86".equals(Build.PRODUCT)|| "vbox86p" .equals(Build.PRODUCT)
英特尔模拟器返回"full_x86",因此我不会指望这种方法.
@GlennMaynard反向形式很丑陋,但很实用:Build.PRODUCT可以为null,而“ google_sdk”则不能,因此这种形式避免了潜在的null引用错误。

4> Vitali..:

基于其他答案的提示,这可能是最强大的方式:

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


对于Android 5.1 x86_64图像(可能还有其他更新的64位图像),这将是"ranchu"而不是"goldfish".
@holmes:错字,s/b"金鱼"
我会选择`isEmulator = Build.HARDWARE.contains("golfdish")`

5> 小智..:

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

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;

} 


更好的方法是`BuildConfig.DEBUG`。

6> J.J. Kim..:

这段代码适合我

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

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

由于Android模拟器总是将"Android"作为网络运营商回归,我使用上面的代码.


没有SIM卡的设备(如平板电脑)会返回什么?
@rds没有SIM卡的设备返回空字符串("")

7> Rockney..:

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



8> Sileria..:

以下两项都设置为"google_sdk":

Build.PRODUCT
Build.MODEL

所以它应该足以使用以下任一行.

"google_sdk".equals(Build.MODEL)

要么

"google_sdk".equals(Build.PRODUCT)



9> Patrick..:

我尝试了几种技术,但确定了稍微修改后的版本,检查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".



10> S.D...:

我只是寻找_sdk,_sdk_或者sdk_,甚至只是sdk部分Build.PRODUCT:

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


为什么不只是`contains("sdk")`?唯一的区别(除了更快)是`matches(".*_?sdk _?.*")`要求如果在sdk之前或之后有一个字符,它必须是下划线'_',这不是所有重要的检查.

11> 小智..:

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

但如果您只是需要检测您是否在开发环境中,则可以执行以下操作:

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

希望这有帮助....



12> AndroidCrop..:

使用此功能:

 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;

    }



13> Nils Pipenbr..:

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

它是模拟器特定的启动脚本,它不应该在非模拟器构建中存在.


这个文件在我的HTC One上,所以它不起作用;-)

14> Eyal..:

这是我的解决方案(仅当您在调试计算机上运行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("");



15> Louie Liu..:

从电池,仿真器:电源始终是AC充电器.温度始终为0.

并且您可以使用Build.HOST记录主机值,不同的仿真器具有不同的主机值.



16> Tim Kryger..:

另一个选择是查看ro.hardware属性并查看它是否设置为goldfish.不幸的是,似乎没有一种简单的方法可以从Java中做到这一点,但是使用property_get()从C中做到这一点很简单.


这似乎适用于NDK.包括并使用__system_property_get("ro.hardware",buf)然后检查buf是"goldfish".

17> Juri..:

以上建议的解决方案来检查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);
    }
} 



18> XXX..:

一种方法的所有答案

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


@ sud007在`/init.goldfish.rc中有很多设备,这会导致误报.例如,许多三星Galaxy系列设备.

19> ifeegoo..:

我找到了新的模拟器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。



20> Saeed..:

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

                    }
                });

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有