Reputation: 6866
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?
Upvotes: 384
Views: 216126
Reputation: 116332
How about this solution (class implementation of SystemProperties
is available here), which I also published on my public repository here:
val isProbablyRunningOnEmulator: Boolean by lazy {
return@lazy (
// Android SDK emulator
Build.MANUFACTURER == "Google" && Build.BRAND == "google" &&
((Build.FINGERPRINT.startsWith("google/sdk_gphone_")
&& Build.FINGERPRINT.endsWith(":user/release-keys")
&& Build.PRODUCT.startsWith("sdk_gphone_")
&& Build.MODEL.startsWith("sdk_gphone_"))
//alternative
|| (Build.FINGERPRINT.startsWith("google/sdk_gphone64_") && (Build.FINGERPRINT.endsWith(":userdebug/dev-keys")
|| (Build.FINGERPRINT.endsWith(":user/release-keys")) && Build.PRODUCT.startsWith("sdk_gphone64_")
&& Build.MODEL.startsWith("sdk_gphone64_")))
//Google Play Games emulator https://play.google.com/googleplaygames https://developer.android.com/games/playgames/emulator#other-downloads
|| (Build.MODEL == "HPE device" &&
Build.FINGERPRINT.startsWith("google/kiwi_") && Build.FINGERPRINT.endsWith(":user/release-keys")
&& Build.BOARD == "kiwi" && Build.PRODUCT.startsWith("kiwi_"))
)
//
|| 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")
}
Note that some emulators fake exact specs of real devices, so it might be impossible to detect it. I've added what I could, but I don't think there is a 100% way to detect if it's really an emulator or not.
Here a tiny snippet you can make in the APK to show various things about it, so you could add your own rules:
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"
Upvotes: 201
Reputation: 3695
Based on hints from other answers, this is probably the most robust way:
isEmulator = Build.HARDWARE.equals("ranchu")
Upvotes: 32
Reputation: 5441
if ("sdk".equals( Build.PRODUCT )) {
// Then you are running the app on the emulator.
Log.w("MyAPP", "\n\n Emulator \n\n");
}
Edit:
Tested on 2023-04 Android Studio IDE emulator and on real device.
public static boolean isRunningOnEmulator() {
return Build.PRODUCT.startsWith("sdk");
}
Upvotes: 2
Reputation: 10650
The Flutter community uses this code in the device-info plugin to determine if the device is an emulator:
private val isEmulator: Boolean
get() = (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");
}
Upvotes: 107
Reputation: 5277
This is how Firebase Crashlytics approaches it:
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);
}
Upvotes: 10
Reputation: 2548
It is a good idea to verify if the device has these packages installed:
mListPackageName.add("com.google.android.launcher.layouts.genymotion");
mListPackageName.add("com.bluestacks");
mListPackageName.add("com.vphone.launcher");
mListPackageName.add("com.bignox.app");
I just put it inside an ArrayList...
And then simply check against the package manager till it finds one.
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;
}
}
Just note that there are most likely some ways for a VM to fool the application, in that case it might be worthwhile looking at some physical sensors which wouldn't be present in a virtual device.
Upvotes: 2
Reputation: 387
In Android Studio under [Run > Edit Configurations... > Launch Flags]
In Launch Flags add the following...
--ei running_emulator 1
Then in your Activity onCreate
Bundle extras = getIntent().getExtras();
if (extras.getInt("running_emulator", 0) == 1) {
//Running in the emulator!... Make USE DEV ENV!!
}
Easy!
Upvotes: -2
Reputation: 450
Try using this method.
Tested on Google and Genymotion emulators.
public Boolean IsVM() {
String radioVersion = android.os.Build.getRadioVersion();
return radioVersion == null || radioVersion.isEmpty() || radioVersion.equals("1.0.0.0");
}
Upvotes: 3
Reputation: 846
this method work for me
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;
}
}
Upvotes: 0
Reputation: 609
Most commonly used technique is to match values from brand,name ... etc. But this method is static and for a limited versions of emulators. What if there are 1000+ VM manufacturers ? then you would have to write a code to match 1000+ VMs ?
But its time waste. Even after sometime, there would be new other VMs launched and your script would be wasted.
So based upon my tests, I got know
getRadioVersion()
returns empty on VM,
and returns version number on real android device.
public Boolean IsVM()
{
return android.os.Build.getRadioVersion().length() == 0;
}
//return true if VM
//return false if real
Although it works, But I don't have official explanation for this.
Code: http://github.com/Back-X/anti-vm/blob/main/android/anti-vm.b4a
Release: http://github.com/Back-X/anti-vm/releases/download/1/anti-vm.apk
Upvotes: 0
Reputation: 3520
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) {
if(isEmulator){
// Do your work
}
else{
// Not emulator and do your work
}
}
});
Upvotes: 4
Reputation: 21
try this link from github.
https://github.com/mofneko/EmulatorDetector
This module help you to emulator detection to your Android project suported Unity.
Basic checker
Upvotes: 1
Reputation: 40381
One common one sems to be Build.FINGERPRINT.contains("generic")
Upvotes: 121
Reputation: 819
This worked for me instead of startsWith
: Build.FINGERPRINT.contains("generic")
For more check this link: https://gist.github.com/espinchi/168abf054425893d86d1
Upvotes: 1
Reputation: 7292
I found the new emulator Build.HARDWARE = "ranchu"
.
Reference:https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU
And also I found the Android official way to check whether emulator or not.I think it's good reference for us.
Since 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");
}
We have ScreenShapeHelper.IS_EMULATOR
to check whether emulator.
Since 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");
}
We have Build.IS_EMULATOR
to check whether emulator.
The way the official to check whether emulator is not new,and also maybe not enough,the answers above also mentioned.
But this maybe show us that the official will provide the way of official to check whether emulator or not.
As using the above all ways mentioned,right now we can also use the two ways about to check whether emulator.
How to access the com.android.internal
package and @hide
and wait for the official open SDK.
Upvotes: 6
Reputation: 2353
Another option is to check if you are in debug mode or production mode:
if (BuildConfig.DEBUG) { Log.i(TAG, "I am in debug mode"); }
simple and reliable.
Not totally the answer of the question but in most cases you may want to distinguish between debugging/test sessions and life sessions of your user base.
In my case I set google analytics to dryRun() when in debug mode so this approach works totally fine for me.
For more advanced users there is another option. gradle build variants:
in your app's gradle file add a new variant:
buildTypes {
release {
// some already existing commands
}
debug {
// some already existing commands
}
// the following is new
test {
}
}
In your code check the build type:
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"); }
Now you have the opportunity to build 3 different types of your app.
Upvotes: 3
Reputation: 501
Checking the answers, none of them worked when using LeapDroid, Droid4x or Andy emulators,
What does work for all cases is the following:
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;
}
Upvotes: 4
Reputation: 9072
All answers in one method
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;
}
Upvotes: 4
Reputation: 25673
Whichever code you use to do emulator detection, I'd highly recommend writing unit tests to cover all the Build.FINGERPRINT
, Build.HARDWARE
and Build.MANUFACTURER
values that you are depending on. Here are some example tests:
@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();
}
...and here's our code (debug logs and comments removed for conciseness):
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;
}
}
Upvotes: 3
Reputation: 109
From Battery, the emulator: Power source is always AC Charger. Temperature is always 0.
And you can use Build.HOST
to record host value, different emulator has different host value.
Upvotes: 8
Reputation: 109
use this function :
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;
}
Upvotes: 8
Reputation: 98881
I've collected all the answers on this question and came up with function to detect if Android is running on a 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;
}
Tested on Emulator, Genymotion and Bluestacks (1 October 2015).
Upvotes: 3
Reputation: 1290
Since the underlying emulation engine for Genymotion is VirtualBox and that's not going to change any time soon I found the following code the most reliable:
public static boolean isGenymotion() {
return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
Upvotes: 2
Reputation: 4676
if (Build.BRAND.equalsIgnoreCase("generic")) {
// Is the emulator
}
All BUILD references are build.prop values, so you have to consider that if you are going to put this into release code, you may have some users with root that have modified theirs for whatever reason. There are virtually no modifications that require using generic as the brand unless specifically trying to emulate the emulator.
Fingerprint is the build compile and kernel compile signature. There are builds that use generic, usually directly sourced from Google.
On a device that has been modified, the IMEI has a possibility of being zeroed out as well, so that is unreliable unless you are blocking modified devices altogether.
Goldfish is the base android build that all other devices are extended from. EVERY Android device has an init.goldfish.rc unless hacked and removed for unknown reasons.
Upvotes: 1
Reputation: 29436
I just look for _sdk
, _sdk_
or sdk_
, or even just sdk
part in Build.PRODUCT
:
if(Build.PRODUCT.matches(".*_?sdk_?.*")){
//-- emulator --
}else{
//-- other device --
}
Upvotes: 12
Reputation: 2421
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.
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.
Upvotes: 12
Reputation: 819
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
This should return true if the app is running on an emulator.
What we should be careful about is not detecting all the emulators because there are only several different emulators. It is easy to check. We have to make sure that actual devices are not detected as an emulator.
I used the app called "Android Device Info Share" to check this.
On this app, you can see various kinds of information of many devices (probably most devices in the world; if the device you are using is missing from the list, it will be added automatically).
Upvotes: 4
Reputation: 328556
Put a file in the file system of the emulator; since the file won't exist on the real device, this should be stable, reliable and easy to fix when it breaks.
Upvotes: 3
Reputation: 166
I never found a good way to tell if you're in the emulator.
but if you just need to detecet if you're in a development environment you can do this :
if(Debug.isDebuggerConnected() ) {
// Things to do in debug environment...
}
Hope this help....
Upvotes: 13