Expo app

How to build a React Native Expo app on a PC

Apps, React Native Expo

One of the big advantages of Expo is that you can build for iOS on a PC. However, the answer to the question ‘how to build an expo app on a PC’ whilst well documented here, also contained lots of info I didn’t need as I was already set up with certificates in my Apple developer account, and was only publishing for iOS. So this is a more condensed overview for anyone wanting to build an Expo standalone iOS app using a PC.

Before you follow these steps I have presumed that as a Windows user you’ve already installed the WSL as outlined here. I’m also presuming that you’ve built an Expo app, and that you have an Apple Developer account. Once you have then you’re ready to build your Expo app.

  1. Open Powershell as administrator by right-clicking the Powershell icon and selecting ‘run as administrator’
  2. Type – Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    Restart PC (I’m not totally sure this is necessary, do your own tests!)
  3. Open git bash at the project root
  4. Type expo build:ios

Please note if you see a message saying “Additional information needed to setup credentials in non-interactive mode.” use CMD instead. I have seen lots of info saying don’t use Git Bash for this, but honestly on my PC it seems a bit hit or miss. Rule of thumb is try both!

Build your Expo App on the PC

Open CMD, navigate to project root, run expo:build:ios.

Let Expo manage the process for you and as long as you had all your profiles and certificates set up ok in your Apple Developer account then Expo should be able to put it all together. Once the Expo build process starts, it will ask you a series of questions, the first one asks you what kind of build you want – choose Archive if you want to upload this to TestFlight and run this on a device.

expo build on pc what type archive or simulator

Next, the Expo build process will ask you for your Apple account credentials:

expo build on pc apple account credentials

Once it’s complete you’ll see a message saying that your build is queued. There’s a link provided in the output which will let you both see the progress of your Expo build and download the IPA file once it’s finished, from the Expo website.

Expo credentials manager

If there are any issues with any stage of this and you need to take a look at the certificates and provisioning profiles that Expo is trying to use, then go to expo credentials:manager and follow the on-screen prompts. You can remove the certificates it’s trying to use and start the whole process again. This Expo page is really useful as it explains what each bit is for clearly.

Uploading the IPA file to TestFlight and the App Store

Now that you’ve downloaded your IPA file you are ready to submit it to the app store and / or TestFlight. And here’s where the wheels fall off a bit if you are trying to build your iOS Expo app using a Windows PC. You can get this far but to upload the IPA file you HAVE to use Transporter, and that only runs on a Mac. I find it a huge shame that you can’t do this any other way, but for now you’ll have to find a friend with a MAC to get your IPA file to Apple.

Build your Expo app on a Mac

If you can’t borrow a Mac then you’ll have to buy one, and the most cost effective way to do this is to buy a Mac Mini. They are small enough to be portable too, should you ever need it to be but a great machine that will enable you to develop, build and deploy Expo apps for the app store.

How to set up Expo app navigation using React Navigation

Apps, React Native Expo

Further to my previous post which explained how to build a react native app using Expo, this post takes it a step further and shows you how to set up all 3 types of Expo navigation in your app – Stack Navigation, Tab Navigation, and Drawer Navigation. I think some people search for ‘Expo Navigator‘ or ‘Expo React Navigation‘). By the time you’ve worked through both posts you should have a simple Expo app running on your device with the ability to navigate in different ways between pages. I’ll also cover some basic styling, so by the end you will have a great app framework to build on.

Which Expo navigation package?

There are a few different navigation packages available for Expo (React Navigation, React Router…) but for this article we’ll be using React Navigation, which is recommended to be used with Expo. I’ve never had any issues with it and I also know it works well with Redux. I won’t go into that now but it will become important as you build more complex apps, so it’s worth mentioning. Full details are here.

I’m presuming you’ve read my first Expo post, and completed all the steps. In that case you’ll already have a basic Expo app installed and running. That’s where this post takes over….

First of all you need to install the React Navigation package itself, so on the command line type this:

npm install @react-navigation/native

And then this, to install Expo dependencies:

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

Now you’re ready to start coding your pages and then navigating between them, and for this you need to install the Stack Navigator.

Expo stack navigator for basic navigation

The stack navigator is the simplest of the three, and let’s you simply move from one page to another using a link or button that you have put on your page. You’ll then define a ‘stack of pages’ and navigate through them. To install the Stack Navigator, type this :

npm install @react-navigation/stack

Once installed, we can start coding a simple 2 screen Expo app that let’s you navigate to and from each screen. This is the most basic navigation set up. First of all you need to reference all required packages in your app.js file :

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { StyleSheet, Text, Button, View } from 'react-native';

… and then create a Stack Navigator.

const Stack = createStackNavigator();

Next we build the method for our pages, one for the Home page, and one for the Details page :

function Home({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Show me the Details screen"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

NOTE – I’ve included a bit of styling, which just makes sure the page content is centred nicely. Now we’ll build up the main method in app.js, which defines the overall StackNavigator and specifies which page to show first, in the initialRouteName property.

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Details" component={Details} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Now run that to test your changes – type expo start on the command line if it is not already running. Or simply save your file to refresh it if it already is. You’ll see the Home page load with a button on it. That button takes you to the Details screen, and on the Details screen is another button which takes you back to the Home screen. And that is all you need for some simple Expo navigation!

You’ll probably find that you also want to have another type of navigation in your app, either some Tab navigation, or Drawer navigation. Read on for how to combine them.

Combining stack navigation with tab navigation in Expo

Before you can add tab navigation to your Expo app, you need to decide whether you want to install top tabs or bottom tabs, and whether you want to :

  • nest a Stack Navigator in a Tab Navigator – or
  • nest a Tab Navigator in a Stack Navigator

I’m going to add some bottom tabs to our app, and we will be doing the first option, nesting a Stack Navigator in a Tab Navigator. So first, let’s install the package :

npm install @react-navigation/bottom-tabs

Now add a reference to that at the top, under where you referenced the Stack Navigator.

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

… and define the navigator, under your Stack definition.

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

Change your main App function to this, so that we have tabs as the main navigation:

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Details" component={Details} />
        <Tab.Screen name="Search" component={Search} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Reload your app and you’ll see your new tabs at the bottom of the screen. Note I have added one extra page called Search. You can create a method for this in the same way as we did for the Home screen, and the Details screen.

And now we need to include our Stack Navigator. We will include a Stack of pages under the Details section, so create a new method called DetailsStackScreen, that will reference each page in our Stack, like this:

function DetailsStackScreen({navigation}){
  return (
      <Stack.Navigator>
        <Stack.Screen name="Details Stack Screen" component={Details} />
        <Stack.Screen name="Further Details" component={FurtherDetails} />
      </Stack.Navigator>
  );
}

You will notice we’ve referenced a new page – Further Details, so we need to also add the method for this:

function FurtherDetails({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the FURTHER Details page</Text>
      <Button
        title="Back to the previous Screen"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="Back to the HOME Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

And also we need to update our Details page to include a link to drill down to the Further Details page:

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page. Now you can drill down to a further details page in this Stack of screens</Text>
      
      <Button
        title="Further Details"
        onPress={() => navigation.navigate('Further Details')}
      />

      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

Finally, we need to update the main App method to reference the DetailsStackScreen instead of our original Details method :

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Details" component={DetailsStackScreen} />
        <Tab.Screen name="Search" component={Search} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Now refresh your app to see the results, and you’ll see you have 3 tabs, each of which leads to a page. In the Details screen you will see that you can navigate through the Stack of pages you have defined.

Side navigation – also known as drawer navigation

To complete our app, we will be adding some Drawer navigation. To start we need to install the package :

npm install @react-navigation/drawer

… reference it at the top of our App.js page :

import { createDrawerNavigator } from '@react-navigation/drawer';

Then create the Drawer object :

const Drawer = createDrawerNavigator();

Now we make the main method in our App.js file reference the Drawer Navigator, which becomes the ‘wrapper’. This references each page you want to show in your side menu, like this:

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeTabsScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

HomeTabScreen is a new method that we need to define, that holds the TabNavigator that used to be in this main method, like this :

function HomeTabsScreen({navigation}){
  return(
    <Tab.Navigator>
         <Tab.Screen name="Home" component={Home} />
         <Tab.Screen name="Details" component={DetailsStackScreen} />
         <Tab.Screen name="Search" component={Search} />
    </Tab.Navigator>
  );
}

Then we just need to define the SettingsScreen :

function SettingsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Settings page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

And finally we need to reference our styles at the bottom the page :

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

If you now run your app, you will have a fully functioning app with all three types of navigation. Drag in the Drawer Navigation menu from the left hand side and try clicking each link. You’ll notice that the Settings page does not contain any Tab Navigation, but the Home page does, so you have total control over where and how you use each type of Expo Navigation.

The app is now ready for you to build your pages and style! I’ll probably write another post on how to style the app and do things like add icons to the Tab Navigation. Feel free to email me any questions or requests for the next post at hello@brainstormcreative.co.uk!

For completeness here is the final code:

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { StyleSheet, Text, Button, View } from 'react-native';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const Drawer = createDrawerNavigator();

function HomeTabsScreen({navigation}){
  return(
    <Tab.Navigator>
         <Tab.Screen name="Home" component={Home} />
         <Tab.Screen name="Details" component={DetailsStackScreen} />
         <Tab.Screen name="Search" component={Search} />
    </Tab.Navigator>
  );
}

function Home({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Show me the Details screen"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function DetailsStackScreen({navigation}){
  return (
      <Stack.Navigator>
        <Stack.Screen name="Details Stack Screen" component={Details} />
        <Stack.Screen name="Further Details" component={FurtherDetails} />
      </Stack.Navigator>
  );
}

function Details({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Details page. Now you can drill down to a further details page in this Stack of screens</Text>
      
      <Button
        title="Further Details"
        onPress={() => navigation.navigate('Further Details')}
      />

      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function FurtherDetails({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the FURTHER Details page</Text>
      <Button
        title="Back to the previous Screen"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="Back to the HOME Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function Search({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Search page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={styles.container}>
      <Text>This is the Settings page</Text>
      <Button
        title="Back to the Home Screen"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeTabsScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Create a React Native app with Expo

React Native Expo

I’ve been an app developer for years but recently had to work on a project that required me to create a React Native app with Expo. Expo is pretty easy to set up and use but I definitely found a few holes in the documentation online, so I’ve documented the steps to help you build an Expo app.

In summary this post will tell you how to :

  • Create a new Expo app project
  • Create a git repo and push your code into it
  • Run and debug an Expo app

The next post will show you how to :

  • Set up basic navigation (a Stack Navigator) using ReactNavigation
  • Add Tab navigation to your Expo app, and combine it with the StackNavigator
  • Add Drawer Navigation to the app
  • Apply some styling

I’m using Visual Studio Code on a PC to create this Expo app – I’m presuming that you’re already familiar with Visual Studio Code and the fundamentals of app development. I’ll also presume that you know the basics of using a command line tool and using Git repos. For all of this you can use CMD or Git Bash. I prefer Git Bash but it does occasionally have some issues with Expo, so bear that in mind and try CMD if that happens.

Get Started creating your app – Install the Expo client

The very first time you create an Expo app you will need to install the Expo CLI. In your command line tool of choice (Command or Git Bash), type:

npm install --global expo-cli

If you get an error message about npm not being recognised, then you haven’t yet got node package manager installed, and you will need that. In which case follow the instructions here – https://www.npmjs.com/get-npm and then try again.

You will also need to install the Expo client on your Android and / or iOS device.

1. Set up your new Expo project

Expo have plenty of documentation available at https://docs.expo.io/ so some of the process of creating a new React Native app with Expo is covered – do take a look. I’ve summarised the key required steps here. In summary. At the command prompt, navigate to the folder where you want your project folder to be, and type:

expo init my-project

….. where my-project should be the name of your new app. For this example we’ll call it myapp, so :

expo init myapp

Once you’ve typed that on the command line and pressed return you’ll see a question prompt asking you what type of project you want to set up. Choose the basic option from the Managed Workflow section and press return.

You’ll see lots of packages being installed. Once it’s finished type this on the command prompt:

cd myapp

That moves you into the directory of your new app. Type npm install to ensure React Native is installed. So your project framework is created, now you need to set up a git repo.

2. Set up a git repo for your Expo app

Create a new git repo for this project on github – I’ve now created a repo called myapp. Now we need to tell the local repo to connect to this remote repo. Presuming that you are still in your new project root directory with the command line tool open, type –

git remote add origin https://github.com/yourNameHere/myapp.git

… press return, and then type this to push your project code so far –

git push --set-upstream origin master

At that point you’ve created your blank Expo project, created a git repo and pushed your Expo project to the master branch. It’s worth checking that the Master branch in this new repo in github is showing that you just pushed your new Expo project code to it.

3. Test Your Expo App build Setup

Before we go any further, let’s make sure your basic Expo app set up is working ok. So first of all you need to start expo, by typing this in your project root on the command line:

expo start

You’ll see the Expo window open in your browser. With the camera of your device, scan the QR code and follow the prompt to open the Expo client. Please note it defaults to LAN, but quite a few routers are configured to block your local IP address, mine included. If you select Tunnel, the QR code will reload and it should run fine.

At this point you’ll see the code start to load on your device and you’ll see a basic app home page on your device. You can leave this running while you start to edit your code……

4. Edit your Expo app

Now go back to Visual Studio Code and open your Expo project, then open the App.js file, it will look like this:

Now change the text that says “Open App.js to start working on your app!” and change it to some of your own text, then save the file. This change will automatically be pushed to the Expo client, so if you now look on your device, you will see your new text. And that’s all the basics of how to create a React Native app using Expo.

5. Continue to create your React Native App with Expo!

If you want to just download an Expo skeleton app then download from my github repo here – https://github.com/EmilyChristy/expo-skeleton