React Native: How can I detect if my code is running in the Simulator?

AndroidIosReact Native

Android Problem Overview


In a Obj-C iOS app I can use #if (TARGET_IPHONE_SIMULATOR) to write simulator-only code.

In react native I can use:

if (__DEV__) {
 .. do something special
}

.. to detect development mode.

We can use Platform.OS === 'ios' to detect the platform (Android/iOS). See here for more info Platform Docs

But how do we detect if the app is running in the simulator?

The reason I ask is that my app uses the camera to scan barcodes, and this isn't supported in the iOS Simulator.

Android Solutions


Solution 1 - Android

You can do this pretty easily with react-native-device-info, like so:

import DeviceInfo from 'react-native-device-info'

isSimulator() {
  // https://github.com/react-native-community/react-native-device-info#isemulator
  return DeviceInfo.isEmulator();
},

Solution 2 - Android

The easiest solution I can think of, which does not require creating a native module (or modifying an existing one), would be to pass this parameter as a react component property.

In your AppDelegate where the RCTRootView is initialized, you check if it's the simulator as you would do in a regular iOS app; you then pass this info to the react root-view as its initialProperties:

  BOOL isSimulator = NO;
#if TARGET_IPHONE_SIMULATOR
  isSimulator = YES;
#endif
  
  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"ReactDemo"
                                               initialProperties:@{@"isSimulator": @(isSimulator)}
                                                   launchOptions:launchOptions];

Now you can access it in the JavaScript via the props of your react component:

this.props.isSimulator

On Android, in you MainActivity which extends ReactActivity you can use a similar approach:

import android.os.Build;
import android.os.Bundle;

public boolean isEmulator() {
        return 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.MANUFACTURER.contains("Genymotion")
                || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                || "google_sdk".equals(Build.PRODUCT);
    }

@Override
protected Bundle getLaunchOptions() {
    Bundle opts = new Bundle();
    opts.putBoolean("isEmulator", isEmulator());
    return opts;
}

Solution 3 - Android

If you're building a CRNA/Expo app you can use Device.isDevice https://docs.expo.dev/versions/latest/sdk/device/#deviceisdevice

import * as Device from 'expo-device';
//....

console.log(Device.isDevice) // => false if simulator

Solution 4 - Android

Using react-native-device-info you can get the following data (executed on a simulator):

getUniqueID: DB71DCB5-6BB0-497B-BE9E-A02BCC1235B7
getInstanceID: undefined
getDeviceId: x86_64
getManufacturer: Apple
getModel: Simulator
getBrand: Apple
getSystemName: iOS
getSystemVersion: 10.1
getBundleId: org.reactjs.native.example.project
getBuildNumber: 1
getVersion: 1.0
getReadableVersion: 1.0.1
getDeviceName:MacBook Pro
getUserAgent: Mozilla/5.0 (iPhone; CPU iPhone OS 10_1 like Mac OS X) AppleWebKit/602.2.14 (KHTML, like Gecko) Mobile/14B72
getDeviceLocale: en
getDeviceCountry: US
getTimezone: America/Panama
isEmulator: true
isTablet: false

Solution 5 - Android

Currently, there isn't any way to see if you are running from a simulator in JS.

I would suggest to add the conditional TARGET_IPHONE_SIMULATOR to check in your native code (if you wrote your own module). Or perhaps use a 3rd party module that doesn't render the camera if in a simulator...ie: react-native-camera: https://github.com/lwansbrough/react-native-camera/search?utf8=%E2%9C%93&q=TARGET_IPHONE_SIMULATOR

Solution 6 - Android

import getHostForRN from 'rn-host-detect';
const IS_SIMULATOR = getHostForRN('127.0.0.1') == "localhost";

This works to differentiate my iOS simulator from my actual device because the simulator returns localhost and the iOS device returns 127.0.0.1. Have not tested it on Android but let me know if it helps you guys.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBen ClaytonView Question on Stackoverflow
Solution 1 - AndroidLane RettigView Answer on Stackoverflow
Solution 2 - AndroidArtalView Answer on Stackoverflow
Solution 3 - AndroidsguhaView Answer on Stackoverflow
Solution 4 - AndroidchachanView Answer on Stackoverflow
Solution 5 - AndroidDave SibiskiView Answer on Stackoverflow
Solution 6 - AndroidKamen TsvetkovView Answer on Stackoverflow