Skip to main content

React Native


Always open .xcworkspace not .xcodeproj.

Development environment setup

To develop with Expo we only need watchman, Xcode, the Command Line Tools and Android Studio. To develop normal React Native apps we need Ruby, Cocoapods etc.

Installing a Java JDK and setting $JAVA_HOME is only necessary if we want to re-use the same daemon between Android Studio and the terminal.

Important: this instructions are not complete yet, it's for Expo development, and they need to be expanded to work on normal React Native apps.



On macOS and Linus (not Windows), install watchman. On macOS run brew install watchman. See for more about how to install it.

If developing with Expo, install the CLI: npm install --global expo-cli. This is how I have it installed on my MBP 2016.


You need Xcode to have simulators and open Xcode projects. Install it with the App Store either by clicking this link or searching 'xcode' on the Store.

Install the Command Line Tools. At Xcode, go to Settings -> Locations and select a version at the 'Command Line Tools' dropdown.


You need Android Studio to have emulators, adb etc. Install it by downloading it from Make sure to pick the right CPU architecture (Intel/ARM) since there are 2 download buttons.

You need to have the environment variable $ANDROID_HOME set, pointing to the sdk location (usually ~/Library/Android/sdk). You also need to have $ANDROID_HOME/emulator and $ANDROID_HOME/platform-tools on your $PATH in order to have access to adb and emulator from the command line.

Add following to the .zshrc:

export ANDROID_HOME=$HOME/Library/Android/sdk

You can check if the environment variable is set with echo $ANDROID_HOME (just $ANDROID_HOME prints nothing, even if the envar set).

And you can check that adb and emulator are on the $PATH with which adb and which emulator.



Start Metro bundler: npx react-native start

Reset cache: npx react-native start --reset-cache

Also see


run-ios docs

Run instructions for iOS: npx react-native run-ios or open ios/YourAppName.xcworkspace in Xcode (or run "xed -b ios") and then hit the run button.

Run on a specific iOS simulator: npx react-native run-ios --simulator "iPhone XS Max". (Use xcrun simctl list devices to list the simulators.)

Run Release configuration: npx react-native run-ios --configuration Release (default configuration is 'Debug').


run-android docs

Run instructions for Android: npx react-native run-android. You may have an Android emulator running or a device connected.

Run on a specific Android emulator: npx react-native run-android --deviceId emulator-5554. You can get the emulator id with adb devices.

Launch Android emulator: ${ANDROID_HOME}/emulator/emulator -avd Galaxy_Nexus_API_22_5.1_xhdpi_-_Google_APIs &. (Use emulator -list-avds to list the existing emulators.)

Run Release variant: npx react-native run-android --variant=release

Show developer menu

  • Android
    • Press Cmd or Ctrl + M, or shake your device.
    • Run adb shell input keyevent 82 or adb shell input keyevent KEYCODE_MENU
  • iOS
    • Press Cmd + D, or shake your device (Cmd + Ctrl + Z).

Check platform

import { Platform } from 'react-native'

export const isAndroid: boolean = Platform.OS === 'android'
export const isIOS: boolean = Platform.OS === 'ios'


Full width

alignSelf: 'stretch'


Full height

import * as React from 'react'
import { ScrollView, ScrollViewProps, StyleSheet } from 'react-native'

export function FullHeightScrollView(
props: {
children: React.ReactNode
} & Omit<ScrollViewProps, 'contentContainerStyle'>
) {
return (
<ScrollView contentContainerStyle={styles.grow} {...props}>

const styles = StyleSheet.create({
grow: { flexGrow: 1 },

Avoid dismiss keyboard on touch

Fix it with <ScrollView keyboardShouldPersistTaps='handled'>. See issue #28871 (Touchable/Button in Modal dismisses keyboard on Touch if Modal's parent is a ScrollView without keyboardShouldPersistTaps).

Have to click 2 times on a button for the click event to work

Fix it with keyboardShouldPersistTaps='always' or keyboardShouldPersistTaps='handled'.

Note that keyboardShouldPersistTaps={true} is deprecated. The warning at the console also says "Use keyboardShouldPersistTaps='always' instead".


FlatList issues

Fix scroll bar in the middle of screen: scrollIndicatorInsets={{ right: 1 }}. See

New Architecture



Debug symbols on Android


If you see this message after uploading an aab at Google Play:

This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug.

Add this to android/app/build.gradle:

buildTypes {
debug {
release {
ndk {
debugSymbolLevel 'SYMBOL_TABLE'

This requires having the NDK installed (otherwise :app:extractReleaseNativeSymbolTables fails with error 'NDK is not installed'). Also, add ndk.dir=/Users/myusername/Library/Android/sdk/ndk/22.1.7171670 to the file so that it can be found - source.

Symbol files are automatically added to app bundles, but not to apk - see docs.

Useful links: