React Native deployment with Fastlane

React Native is awesome! It enables web developers around the world to build native iOS and Android Apps without having to know much about the programming languages and frameworks used for such platforms.

Deploying an application to a test or a production environment on the web is an easy task compared to the normal deployment in the iOS environment. At weluse this is typically done with tools like capistrano and it only takes one command to have a new release shipped. Ideally this is done by our continious integration, so that no developer has to bother with deploying an application to a test system.

While developing with React Native we wanted to have the same or at least a similar environment, so the goal was to have one command to build and deploy the application to test devices. This blog post is a detailed explanation of how to set up such a deployment environment for your project (and propably mine too, as I will definitely have to reread this post to remember next time).

All together now

If you want to follow me through this tutorial you should ideally have a React Native App (v. 0.12. or above) installed and running. If not, do this now, we will wait for you.

Fine, so our application is named deploymentDemo and will not be changed from the default generated version as developing a React Native App is described in countless other blog posts. Our first goal is to build the application, so that it may run locally without the development server and our second goal is to get the App into TestFlight, the beta testing center of Apple.

Building the application

This is the easy part. There are only two things we need to do: First of all open ios/deploymentDemo/AppDelegate.m and replace everything between NSURL *jsCodeLocation; and RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation with the following:

#ifdef DEBUG
    jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif

Shortly explained the AppDelegate is the class used for the initialization of a iOS App and you are overwriting the location from which the JS code of your application is loaded. In a debug environment, so for example if you run the simulator, you load the JS code from your started packager script as you would normally do with a freshly initialized application. If you build your application this snippet automatically uses the bundled and minified version generated by running react-native bundle.

Deploying the application

First of all, let's set up our gitignore file, so that we don't commit any valuable information by accident.

fastlane/screenshots
*.zip
*.mobileprovision
*.cer
*.certSigningRequest
*.p12
fastlane/report.xml
ios/main.jsbundle

As capistrano is unable to deploy iOS Apps we use fastlane by Felix Krause. This tool is really awesome, it automates every setup and deployment step having to do with the apple developer program or itunes connect away. It has even the capability to generate screenshots for your website or for testing purposes and many more things. So basically the swiss army knife for iOS deployment.

First of all we need to have an app registered in the developer center. It needs to have an explicit app id as fastlane needs to know this for its configuration and we need to have an App created in iTunes Connect. Notice that this is the only time we need to open the development center and iTunes Connect, from now on our only touch point with apple is fastlane.

The only time we need to open XCode is now. We need to set the initial build version of our App by following the first two steps of this guide. Additionally you need to set the right team and bundle id in the general panel of your project configurator. At last we need to set an icon and a launch image for the application for this I can only recommend the Asset Catalog Creator to you, it makes generating these files extremely easy. After you have added them that's it, no need to open it anymore for a deployment. Now let's go on and use fastlane to get the App deployed.

As this post is more about the integration with React Native, than a guide to fastlane, please refer to their guide for the installation instead. Coming to think about it, you can even follow their guide for the fastlane init command. So, Congratulations, you now have a first fastlane setup! But wait there is more:

Now we need to configure our deployment, by overwriting the content of the beta lane in the fastlane/Fastfile to the following:

lane :beta do
    sigh

    increment_build_number(
      xcodeproj: './ios/deploymentDemo.xcodeproj'
    )

    gym(
      scheme: 'deploymentDemo',
      project: './ios/deploymentDemo.xcodeproj'
    )

    pilot
end

In order to achieve our goal to have one deployment command we change the package.json to match the following:

{
    "name": "deploymentDemo",
    "version": "0.0.1",
    "private": true,
    "scripts": {
        "start": "node_modules/react-native/packager/packager.sh",
        "deploy": "react-native bundle && fastlane beta"
    },
    "dependencies": {
        "react-native": "^0.12.0"
    }
}

Now we can simply run npm run deploy in order to deploy our application to iTunes Connect.