I’ve found that the best way to upgrade to the latest React Native is to gut your entire project, generate a new project with react-native-cli, and then carefully restore on top of it.

This approach minimizes “drift” over time by ensuring that the your XCode project files and such are up to date with the latest React Native. Using react-native upgrade is another option, but given XCode’s unwieldy, difficult to merge file formats, things become error-prone and dificult to reason about.

Furthermore, node’s pervasive color obsession does not benefit those of us who stick to the default Terminal.app color scheme:

bad-colors

NextChessMove

I use this checklist specifically for NextChessMove, my personal iOS and Andorid app. Much of it is specific to NextChessMove, but the basic approach should apply elsewhere.

Start from Scratch

Branch, delete everything in the repository, re-init, and commit:

cd NextChessMove
git checkout -b rn-upgrade
git rm -r .
git clean -f -d -x
git commit -m "emptying prior to react-native update"
cd ..
yes | react-native init NextChessMove
cd NextChessMove
git add .
git commit -m "react-native init NextChessMove"

Restore .gitignore

git checkout master .gitignore
git commit -m "restoring .gitignore"

Restore Javascript

The Javascript shouldn’t change much between releases, so just restore it verbatim:

git checkout master index.android.js index.ios.js js coffee.sh coffee
git commit -m "restoring javascript"

Restore Changes to package.json

Add dependencies (reflux) and update version number:

{
  "name": "NextChessMove",
  "version": "2.0.3",
  "private": true,
  "scripts": {
    "start": "react-native start"
  },
  "dependencies": {
    "react-native": "^0.17",
    "reflux": "^0.3.0",
    "underscore": "^1.8.3",
    "react-native-dialogs": "^0.0.9"
  }
}

Install and commit:

npm install
git commit -am "updating package.json"

Restore CocoaPods

Restore your Podfile, checked-in Pod source, install to generate the workspace, and commit:

cd ios
git checkout master Podfile Podfile.lock Pods
pod install
git add .
git commit -m "restoring CocoaPods"

Restore Changes to Project Settings

Open up the workspace and make the following changes:

  • Change the bundle identifier to com.nextchessmove
  • Update the version and build numbers
  • Uncheck all device orientations except for Portrait
  • Under Build Settings, append $(inherited) to OTHER_LDFLAGS
  • Under Build Settings (All) → Build Options, disable bitcode. (For Google Analytics.)

And commit:

git commit -am "updating project settings"

Restore Objective C Source Code

Restore the source files and commit:

git checkout master Stockfish
cd NextChessMove
git checkout master React Models SavedBoards
git checkout master Icons.xcassets Pieces.xcassets Images.xcassets
git checkout master GoogleService-Info.plist
cd ..
git commit -m "restoring ObjC source"

Add the files to the Xcode project, excluding the following:

  • Stockfish/src/Makefile
  • Stockfish/src/main.cpp

Exclude the following from the source files to be compiled:

  • Stockfish/src/tbcore/tbcore.cpp

And commit:

git commit -am "Adding ObjC source to project and build"

Restore AppDelegate

There tend to sometimes be changes to the generated AppDelegate source files between React Native releases, so pay attention to the diff’s here:

git checkout master NextChessMove/AppDelegate.h NextChessMove/AppDelegate.m
git commit -m "restoring AppDelegate"

Restore Fabric

Add a new Run Script phase named “Upload dSYM to Crashlytics” with the following:

/bin/sh "${SRCROOT}/fabric.sh"

Restore, commit script, and decrypt:

git checkout master ./fabric.sh.gpg
git commit -am "restoring fabric dSYM upload script"
gpg -d fabric.sh.gpg > fabric.sh
chmod +x fabric.sh

Add the following Fabric configuration to NextChessMove/Info.plist so that it knows your public API key:

<key>Fabric</key>
<dict>
  <key>APIKey</key>
  <string>4e7f47e4f49e08d627c246cafa327e763f4d82c7</string>
  <key>Kits</key>
  <array>
    <dict>
      <key>KitInfo</key>
      <dict/>
      <key>KitName</key>
      <string>Crashlytics</string>
    </dict>
  </array>
</dict>

And commit:

git commit -am "restoring Fabric configuration in Info.plist"

Restore the Launch Image

In the settings under “App Icons and Launch Images:”

  • click “Use Asset Catalog,” select “Icons,” and press “Migrate”
  • select LaunchImage as the “Launch Image Source”
  • clear out the “Launch Screen File” dropdown
  • delete LaunchScreen.xib

Commit:

git commit -am "restoring launch image"

Final Build and Test

Clean up everything:

cd ..
git clean -f -d -x
npm install
gpg -d ios/fabric.sh.gpg > ios/fabric.sh
chmod +x ios/fabric.sh

Delete all data from the iOS Simulator. Careful with this:

rm -rf ~/Library/Developer/CoreSimulator

Kill the React packager, fire up Xcode, build, and run!

Restore Android Scripts

cd android
git checkout master ./scripts
git commit -m "restoring android scripts"

Restore Java Source

git checkout master app/src/main/java/com/nextchessmove
git commit -am "restoring Java source"

Restore Images

git checkout master ../images
git commit -m "restoring images"

Install react-native-dialogs

Full instructions on the project page. Some has already been done as part of prior steps.

Replace include ':app' in settings.gradle with the following:

include ':app', ':react-native-dialogs'
project(':react-native-dialogs').projectDir = file('../node_modules/react-native-dialogs/android')

In app/build.gradle, add the following top-level section:

repositories {
    maven { url "https://jitpack.io" }
}

And inside the dependencies section, add the following line:

compile project(':react-native-dialogs')

And commit:

git commit -am "restoring react-native-dialogs"

Enforce Portrait-only Orientation

Add android:screenOrientation="portrait" to the ".MainActivity" activity in app/src/main/AndroidManifest.xml.

And commit:

git commit -am "enforcing portrait-only orientation"

Configure JNI

We compile our JNI libraries manually: add the following to the top of the android/ section in app/build.gradle:

sourceSets.main {
  jniLibs.srcDir "src/main/libs"
  jni.srcDirs = [ ]
}

And comit:

git commit -am "configuring JNI"

Configure Release Builds

Make the following changes in app/build.gradle:

  • change applicationId to com.nextchessmove
  • add the following below the defaultConfig section:

      signingConfigs {
        release {
          storeFile file(NCM_RELEASE_STORE_FILE)
          storePassword NCM_RELEASE_STORE_PASSWORD
          keyAlias NCM_RELEASE_KEY_ALIAS
          keyPassword NCM_RELEASE_KEY_PASSWORD
        }
      }
    
  • in buildTypes/release, append the following:

      signingConfig signingConfigs.release
    
  • Restore and decript the keystore:

      git checkout master app/ncm.keystore.gpg
      gpg -d app/ncm.keystore.gpg > app/ncm.keystore
    

And commit:

git commit -am "configuring release build" 

Note: The above, as described here, assumes that the NCM_* variables are defined in ~/.gradle/gradle-properties.

Restore and Build Stockfish

Restore the Stockfish source and commit:

git checkout master app/src/main/jni
git commit -m "restoring stockfish"

Then build the libraries:

ndk-build --directory=app/src/main/jni