에뮬레이터에서 Android 애플리케이션이 실행 중인지 어떻게 알 수 있습니까?


313

에뮬레이터에서 실행할 때 장치에서 실행할 때와 코드가 약간 다르게 실행되도록하고 싶습니다. ( 예를 들어 , 공개 URL 대신 10.0.2.2를 사용하여 개발 서버에 대해 자동으로 실행합니다.) 에뮬레이터에서 Android 애플리케이션이 실행될 때 감지하는 가장 좋은 방법은 무엇입니까?


2
를 볼 수 있습니다 android.os.Build.
yanchenko

11
놀라워요 ... Google에 표준 방법이 있어야합니까?
powder366

@ kreker 문제가 무엇입니까, 기존 솔루션에서 직면하고 있습니까?
Khemraj

@Khemraj 사기 문제. 일부 센서를 조롱하고 일부 문자열을 변경할 수 있습니다 악한 사람은 실제 장치 척
kreker

답변:


159

이 솔루션은 어떻습니까?

    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

일부 에뮬레이터는 실제 장치의 정확한 사양을 위조하므로 감지하지 못할 수도 있습니다.

여기에 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"

9
Facebook이 React-Native에서 에뮬레이터를 감지하는 방식입니다
Vaiden

이것은 @Aleadam의 답변을 꽤 오랫동안 사용한 후에 업데이트해야했습니다 (제게 작동하지 않았습니다).
ckbhodge

@Sid 무엇을 추가해야합니까?
안드로이드 개발자

2
@Sid 다양한 Build 클래스 변수를 인쇄 했습니까? 특별한 것 같지 않습니까? 이것을 시도 했습니까? github.com/framgia/android-emulator-detector ?
안드로이드 개발자

1
@DrDeo BuildConfig.DEBUG를 사용하여 현재 빌드 확인을 추가하거나 고유 한 사용자 정의 변수를 사용하여 고유 한 빌드를 작성할 수 있습니다. Proguard를 사용하여이 함수가 항상 false 또는 무언가를 반환하도록 할 수도 있습니다 (예 : medium.com/tixdo-labs/… 있음)
Android 개발자

118

하나의 일반적인 하나 Build.FINGERPRINT.contains("generic")


Galaxy Tab Emulator에서도 작동합니다. 가장 좋아하는 답변은 그렇지 않았습니다.
BufferStack

10
"일반"을 포함하는 지문이 에뮬레이터인지 또는 장치인지 설명하십시오. 이 정보는 핵심이지만 제공되지는 않습니다.
James Cameron

2
에뮬레이터-귀하의 의견에 따라 판단 :)
Dori

7
이것은 CyanogenMod를 실행하는 장치에서 true를 반환하므로주의하십시오.
ardevd

8
안드로이드 문서는 당신이 해석하려고하지해야한다고 말했습니다 FINGERPRINT값입니다.
gnuf

64

글쎄, 안드로이드 ID가 나를 위해 작동하지 않습니다, 나는 현재 사용하고 있습니다 :

"google_sdk".equals( Build.PRODUCT );

35
이 글을 읽는 사람은이 문자열이 'google_sdk'가 아닌 'sdk'로 변경된 것 같습니다.
Daniel Sloof 2016

15
@Daniel : Google API에서 2.3.3을 사용하며 'google_sdk'라고 말합니다. Google API를 사용하는 AVD의 경우 'google_sdk'이고 일반적인 경우 'sdk'인 것 같습니다.
랜디 Sugianto '유쿠'

3
인텔 에뮬레이터는 "full_x86"을 반환하므로이 방법을 고려하지 않습니다.
user462982

3
@GlennMaynard 그 반대의 형식은 추악하지만 실용적입니다. Build.PRODUCT는 null 일 수 있지만 "google_sdk"는 할 수 없으므로이 형식은 잠재적 인 null 참조 오류를 피합니다.
Rupert Rawnsley

4
더 많은 경우를 포함 : "google_sdk".equals (Build.PRODUCT) || "sdk".equals (Build.PRODUCT) || "sdk_x86".equals (Build.PRODUCT) || "vbox86p".equals (Build.PRODUCT)
Alberto Alonso Ruibal

31

다른 답변의 힌트를 바탕으로 아마도 가장 강력한 방법 일 것입니다.

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


예. Build.PRODUCT와 달리 Build.HARDWARE (금붕어)는 공식 SDK 및 AOSP에서 동일합니다. 그러나 API 8 이전에는 하드웨어 필드에 도달하려면 리플렉션을 사용해야합니다.
David Chandler

4
나는 함께 갈 것이다isEmulator = Build.HARDWARE.contains("golfdish")
holmes

7
@holmes : 오타, s / b "금붕어"
Noah

7
Android 5.1 x86_64 이미지 (및 아마도 다른 최신 64 비트 이미지)의 경우 "금붕어"대신 "ranchu"입니다.
warbi

28

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

20

아래 코드와 같이 앱이 디버그 키로 서명되었는지 여부는 어떻습니까? 에뮬레이터를 감지하지 못하지만 목적에 따라 작동 할 수 있습니까?

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;

} 

1
이 코드에 감사드립니다. 나는 확인했고 그것이 작동하고있다, 긴 디버그 키를 대처하는 aldo는 고통 스러울 수 있지만 한 번만 수행된다. 이것은 다른 모든 답변이 OS 빌드 정보 문자열의 일부를 정적 문자열과 비교하므로 Android SDK 버전에 따라 변경 될 수 있으며 사용자 정의 Android 빌드로 위조 될 수 있기 때문에 신뢰할 수 있는 유일한 솔루션입니다.
ZoltanF

나는 그것이 유일한 신뢰할만한 해결책이라고 생각합니다. 그러나 디버그 키가 원하는 것보다 더 빠르게 변경 될 수 있습니다.
rds

2
이 작업을 수행하는 더 좋은 방법은 BuildConfig.DEBUG입니다.
Mygod

13

이 코드는 나를 위해 작동합니다

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

장치에 SIM 카드가없는 경우 빈 문자열을 다시 조정합니다 : ""

Android 에뮬레이터는 항상 "Android"를 네트워크 운영자로 재조정하므로 위 코드를 사용합니다.


3
SIM 카드가없는 장치 (예 : 태블릿)는 무엇을 반환합니까?
rds

Android 2.1 용 에뮬레이터 실행 이 코드는 저에게 효과적이지만 Cordova를 2.7.0으로 업그레이드 한 이후 Context 변수가 정의되지 않은 것 같습니다. ADT에서 발생하는 오류는 다음과 같습니다. "컨텍스트를 변수로 해석 할 수 없습니다." 또한 위의 의견에 따르면 신뢰할 수있는 방법은 아닙니다 (실제로 실패하지는 않았지만).
Rustavore

2
@rds SIM 카드가없는 장치는 빈 문자열 ( "")을 반환합니다.
JJ Kim

에뮬레이터 로이 값을 가질 수있는 방법이 없습니까? SIM 카드가없는 모든 사용자를 차단하고 싶습니다.
c-an

11

다음은 모두 "google_sdk"로 설정되어 있습니다.

Build.PRODUCT
Build.MODEL

따라서 다음 행 중 하나를 사용하면 충분합니다.

"google_sdk".equals(Build.MODEL)

또는

"google_sdk".equals(Build.PRODUCT)

Windows에서 x86 에뮬레이터를 실행할 때 Build.Product는 sdk_x86입니다.
Edward Brey

PRODUCT로 확인하는 것은 다른 에뮬레이터에서 다양한 값을 반환하기 때문에 좋은 선택이 아닙니다
Beeing Jk

11

몇 가지 기술을 시도했지만 아래와 같이 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

나는 단지 _sdk, _sdk_또는 sdk_, 또는 심지어 sdk일부를 찾는다 Build.PRODUCT.

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

3
왜 안돼 contains("sdk")? 더 빠르지 않은 유일한 차이점은 matches(".*_?sdk_?.*")SDK 전후에 문자가있는 경우 밑줄 '_'이어야하며 확인해야 할 전부는 아닙니다.
Nulano

9

에뮬레이터에 있는지 알 수있는 좋은 방법을 찾지 못했습니다.

그러나 개발 환경에 있다면 detecet해야 할 경우 다음을 수행 할 수 있습니다.

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

이 도움을 바랍니다 ....


8

이 기능을 사용하십시오 :

 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;

    }

7

emu를 감지하는 더 좋은 방법이 있는지 모르지만 에뮬레이터는 파일 init.goldfish.rc을 루트 디렉토리에 갖습니다 .

에뮬레이터 별 시작 스크립트이며 에뮬레이터가 아닌 빌드에는 없어야합니다.


안드로이드 시스템을 시작하는 동안 리눅스 커널은 먼저 "init"프로세스를 호출합니다. init는 "/init.rc"및 "init.device.rc"파일을 읽습니다. "init.device.rc"는 가상 장치에서이 파일을 "init.goldfish.rc"라고하는 특정 장치입니다.
NET3

7

내 솔루션은 다음과 같습니다 (디버그 시스템에서 웹 서버를 실행하는 경우에만 작동합니다). 응용 프로그램이 시작될 때 시작되는 백그라운드 작업을 만들었습니다. 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("");

7

배터리에서 에뮬레이터 : 전원은 항상 AC 충전기입니다. 온도는 항상 0입니다.

Build.HOST호스트 값을 기록 하는 데 사용할 수 있으며 다른 에뮬레이터는 다른 호스트 값을 갖습니다.


전원과 온도는 어떻게 얻습니까?
안드로이드 개발자

5

또 다른 옵션은 ro.hardware 속성을보고 금붕어로 설정되어 있는지 확인하는 것입니다. 불행히도 Java 에서이 작업을 수행하는 쉬운 방법은 없지만 property_get () 사용하여 C에서 사소한 것 같습니다 .


4
이것은 NDK에서 작동하는 것으로 보입니다. <sys / system_properties.h>를 포함시키고 __system_property_get ( "ro.hardware", buf)를 사용한 다음 buf가 "goldfish"인지 확인하십시오.
NuSkooler

5

위의 제안 된 솔루션은 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);
    }
} 

5

한 가지 방법으로 모든 답변

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

좋은데 init.goldfish.rc에뮬레이터에만 존재합니다. 빌드 세부 사항 외에도 앞으로도 좋은 검사입니다.
sud007

2
@ sud007`/init.goldfish.rc에는 많은 장치가 있으며 이것은 잘못된 긍정으로 이어질 것입니다. 예를 들어 많은 Samsung Galaxy 시리즈 장치가 있습니다.
laalto

@ laalto 당신은 실제로 정확했습니다. 나는 나중에 그것을 업데이트하는 것을 잊어 버린 사과와 사과를 발견했습니다.
sud007

테스트 키는 나를 위해 잘못된 긍정을 생성했습니다.
Avi Parshan

어떤 장치에서 오 탐지를 생성합니까?
Aman Verma

5

새로운 에뮬레이터를 찾았습니다 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 레벨 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를 기다립니다.


5

내 추천 :

github에서 이것을 시도 하십시오 .

안드로이드 에뮬레이터를 쉽게 감지

  • 장치 팜에서 실제 장치를 확인했습니다 ( https://aws.amazon.com/device-farm/ )
  • 블루 스택
  • Genymotion
  • 안드로이드 에뮬레이터
  • 앤디 46.2.207.0
  • MEMU 플레이
  • Nox 앱 플레이어
  • 코 플레이어
  • .....

예제와 함께 사용하는 방법 :

EmulatorDetector.with(this)
                .setCheckTelephony(true)
                .addPackageName("com.bluestacks")
                .setDebug(true)
                .detect(new EmulatorDetector.OnEmulatorDetectorListener() {
                    @Override
                    public void onResult(boolean isEmulator) {

                    }
                });

4

IMEI 번호를 확인할 수 있습니다. http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29를

에뮬레이터에서 회수하면 0을 반환합니다. 그러나 보장 할 수있는 문서는 없습니다. 에뮬레이터가 항상 0을 반환하지는 않지만 등록 된 전화가 0을 반환하지 않는 것이 안전합니다. 비 전화 Android 기기 또는 SIM 카드가 설치되지 않은 기기 또는 현재 등록되지 않은 기기에서 발생하는 상황 회로망?

그것에 의존하는 것은 나쁜 생각 인 것 같습니다.

또한 전화 상태를 읽을 수있는 권한을 요청해야한다는 것을 의미합니다. 다른 상태가 필요하지 않은 경우에는 좋지 않습니다.

그렇지 않으면 서명 된 앱을 생성하기 전에 항상 어딘가에 약간의 변화가 있습니다.


5
IMEI는 0Android 태블릿 또는 SIM 카드가없는 휴대 전화 에서도 반환 될 수 있습니다 .
Paul Lammertsma

에뮬레이터에서 IMEI를 편집 할 수 있습니다. 따라서 이것은 목적에 부합하지 않을 수 있습니다. 또한 API 29부터는 IMEI에 액세스 할 수 없습니다.
Ananth

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

앱이 에뮬레이터에서 실행 중이면 true를 반환해야합니다.

우리가 조심해야 할 것은 에뮬레이터가 몇 개 밖에 없기 때문에 모든 에뮬레이터를 감지하지 않는 것입니다. 확인하기 쉽습니다. 실제 장치가 에뮬레이터로 감지되지 않도록해야합니다.

이를 확인하기 위해 ' Android 기기 정보 공유 ' 라는 앱을 사용했습니다 .

이 응용 프로그램에서 많은 장치의 다양한 정보를 볼 수 있습니다 (아마도 대부분의 장치 일 것입니다. 사용중인 장치가 목록에 없으면 자동으로 추가됩니다).


Mac에서 실행되는 Genymotion에서 Build.DEVICE = vbox86p
lxknvlk

3

실제로 2.2의 ANDROID_ID는 항상 9774D56D682E549C같습니다 ( 이 스레드따름). + 내 실험에 따라).

따라서 다음과 같은 것을 확인할 수 있습니다.

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

가장 예쁘지는 않지만 일을합니다.


8
때문에 나는이 끔찍한 버그가 조심해야 할 것 : code.google.com/p/android/issues/detail?id=10603
브랜든 러키

3

이것은 나를 위해 작동

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

3
사내 펌웨어 엔지니어는 이것을 업데이트하지 않았습니다. 하드웨어에서 Build.Manufacturer가 "알 수 없음"을 반환했습니다. 지문이 더 나은 방법 인 것 같습니다.
누군가 어딘가에

3

에뮬레이터의 파일 시스템에 파일을 넣습니다. 파일이 실제 장치에 존재하지 않기 때문에 파일이 안정적 일 때 안정적이며 안정적이며 수정하기 쉬워야합니다.


3

이 질문에 대한 모든 답변을 수집했으며 Android가 vm / emulator에서 실행 중인지 감지하는 기능을 생각해 냈습니다.

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 및 블루 스택에서 테스트되었습니다 (2015 년 10 월 1 일).


3

답변을 확인한 결과 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;
}


Andy_46.16_48 반환 Build.HARDWARE은 "앤디"
더그 Voss이

Samsung J 시리즈 장치에 대해 잘못된 오탐 (false positive). 에뮬레이터를 감지하기 위해 다음을 사용합니다 : github.com/gingo/android-emulator-detector
bluetoothfx

2

Genymotion의 기본 에뮬레이션 엔진은 VirtualBox이고 곧 변경되지 않을 것이므로 다음 코드가 가장 안정적이라는 것을 알았습니다.

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

2

에뮬레이터 감지를 위해 사용하는 코드에 관계없이 모든 Build.FINGERPRINT, Build.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;
    }
}

2

또 다른 옵션은 디버그 모드 또는 프로덕션 모드인지 확인하는 것입니다.

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

간단하고 신뢰할 수 있습니다.

질문에 대한 대답은 아니지만 대부분의 경우 디버깅 / 테스트 세션과 사용자 기반의 라이프 세션을 구분할 수 있습니다.

필자의 경우 디버그 모드에서 Google 분석을 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 가지 유형의 앱을 만들 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.