I’d originally planned to make this a tutorial on how to build a React Native app. But to give it justice I’m doing a Webcast. Instead, what I’ll share with you here are some of my top takeaways from building my first iOS app with React Native. These are coming from the viewpoint of an experienced Web developer building a native app for the first time. Things I wish I’d known earlier kinda stuff. So without further ado…

App development

Tips to save you time developing an app with React Native.

Getting started

To get started quickly with app development consider your basic needs. You could start building your app using the React Native CLI but you may quickly run into friction scaling. If that’s a concern check out this list of awesome React Native Boilerplates.

Incorporating Swift

Swift feels a lot more like JavaScript, which is great for programmers coming from Web. I chose to start my app with Objective-C and then start using Swift once I became more comfortable with the creation process. At the time of writing creating Custom Native modules with Swift requires some extra care to work properly, though hacks are starting which may ease development in the future.

Create a Swift file and chose to allow Xcode to automatically create the bridge for a mixed project.

Xcode will automatically create a bridging header between languages called MyApp-Bridging-Header.h.

Update Build Settings to set “Defines Module” setting to YES.

Import to Objective-C like so: ModuleName-Swift.h (where ModuleName is your Product Module Name and -Swift is a fixed suffix. Tip: Confirm your Product Module Name by searching for “Product Module Name” in Build Settings for the main project target.

Import the .h file into your existing Obj-C classes to use Swift from existing Obj-C classes

Creating an App Icon

Your app is going to need an icon. They can be created for free without much design skill whatsoever.

Making a device preview image

A picture’s worth a thousand words. Show people what your app will look like on their actual device with iPhone Screenshot Maker. The application will frame an app screenshot inside the iOS device of your choosing and even put a slick gloss on the screen for you. Best of all, it’s free.

Incorporating a custom font

Avoid FOUC by bundling your font in the application binary rather than pulling pulling the font from the Web. Font flickers could be avoided by base-64 encoding the font and embedding it in an inline style declaration, but it’s easier to slip the font into the app itself. To do so review the Common Mistakes With Adding Custom Fonts to Your iOS App and follow the instructions provided to add your font.

Enabling Push Notifications

If your app is running a version of react-native before 0.13.0 you’re going to have a little friction getting started here due to an evolving RN codebase. Here’s how it’ll initially manifest itself:

RCTPushNotificationManager.h not found

When this happens it’s because your app cannot find the .h file in its Header Search Paths (in Build Settings). To fix this follow the sage advice in #1979. And don’t forget to link your library!

App submission

Getting your app in the App Store for real.

Beta testing with TestFlight

Getting your app onto the hands of others early is a good idea. There are many different devices of various form-factors, all potentially running different versions of iOS. Don’t make the assumption your app will “just work” for others if it worked for you. Use beta builds to squish bugs before your formal App Store submission. TestFlight can help.

New builds require a change in the build number in the project settings in Xcode.

You can leverage iTunes Connect with TestFlight to manage users and distribute your app for prerelease testing.

Unlike the old UDID request method all you need is the full name and iOS-linked email address of your beta tester to invite people to the beta group.

You can submit app store review requests against beta builds to get a feel for what’s left before official submission. Use the submission links next to the individual builds in iTunes Connect to make it happen.

When submitting new builds, ensure you create your Archive as iOS Device (i.e. unplug your actual device). If you don’t you’ll receive a “failed to code sign” error in Xcode.

You may be rejected for improper advertising identifier IDFA via Program License Agreement PLA 3.3.12 if you’re not serving ads and include RCTAdSupport Library (you’ll be notified during submission).

Getting screenshots can be a little tricky. There are a number of ways to go about it. You can even create custom frame borders of your app if you want to go all out. What worked best for me was the simplest solution of messing with the simulators to capture the images. But if you localize text in our app you may want to look at something like Snapshot and learn how to automate screen grabs.

Update 10 Aug 2016: I received an email from Apple today indicating screenshots have been made even easier. Just submit one set of screenshots and one optional app preview for the largest device size within a device family, and they will be used across all localizations and display sizes. If your app’s UI or behavior changes based on device size, or if you would like to include localized screenshots, you can use the new Media Manager to add custom screenshots.

Update 16 Aug 2016: See also instructions for re-enabling App Transport Security for iOS 9 on the RN Running on Device page.

If and when you run into issues uploading to App Store

I ran into a lot of friction here at first and once after changing something, so this gets its own section.

In the end what worked for me was to close the main Xcode window with the archive Organizer window still open, which I tried in desperation after 2 hours of a whole lotta no such luck otherwise. Weird, right?

Upgrading an existing app for Xcode 7 and iOS 9

If you’re using Webpack Dev Server to host your application you’ll need to update your Info.plist to ease security restrictions. Meteor was anticipated to have this problem way back in June. Here’s more info and a workaround for HTTP connections not supporting TLS 1.2.

Here’s the error I saw before updating Lumpen Radio, which uses Webpack Dev Server to dynamically generate index.ios.js over HTTP:

The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.

After updating Info.plist file using the workaround the issue was fixed.

While updating I bumped Lumpen Radio to React Native 0.11.0 and CocoaPods 0.39.0.beta.4 while updating to Xcode 7 and started getting generic archives instead of iOS Archives while trying to release. After several hours of debugging I found an answer. If you’re using CocoaPods and start seeing the same problem it could be a number of things, but what I encountered differed from most.