If you come from native development background, you might be aware of a feature that both Android Studio and XCode provide to create different applications from the same code. These are known as flavors in Android Studio and targets in XCode. The idea is to create different packages with same core functionality but with minor difference in features. This can include different color schemes, branding or some functionalities unique to a package. A common example is creating a free and paid version of a same application, wherein the paid version has same core functionality as the free version with some added functionalities and features. Since the major functionality is the same there is no need to create different projects, but handle flavor/target specific changes at run-time. I hope you get the idea. If not follow these links to learn more.
Advanced Android Flavors Part 1 — Building White Label Apps on Android
Get started using Android Flavors to easily create variations in your app
Xcode “Targets” with multiple build configurations
How to create multiple applications that differentiate and share parts of the source code
For simplicity, I will be using the Android term
flavors to represent different product builds in React Native.
Now, lets move to the problem at hand
The project I was working on relies heavily on build flavors, and React Native does not have inbuilt functionality to handle the same. Sure, you can create different flavors from
react-native-cli but that only decides the build process, not the actual run-time changes that need to be made. So here is what I came up with, to bridge this gap between native and React Native.
Step 1: Configuration ( Native )
The first step is to setup product flavors in Android Studio and build targets in XCode. For the purpose of the tutorial, our application will be called
NoteTaker . This application has two flavors:
pro . You can read the above mentioned articles to help you setup the configuration on Android Studio and Xcode.
Step 2: Native Modules
Once we have setup the flavors on the native side, we need a way to pass the product flavor identifier from native to react-native at run time. This, definitely requires us to create native modules or bridge methods for both Android and iOS. For simplicity, we will keep our flavor identifiers as strings. In Android, the flavor in stored in the
BuildConfig and for iOS you can use
Take a look at the following documentation if you do not know what native modules are in React Native.
Native Modules · React Native
Sometimes an app needs access to a platform API that React Native doesn't have a corresponding module for yet. Maybe…
Step 3: Flavor.js
Step 4: Colors.js
pro versions have different color schemes, we create a
Colors.js file, that contains the flavor specific colors. Also this file exports a method to get the relevant colors based on the product flavor.
Our setup is now almost complete. We just need to call the build flavor method at the start of our react native application. But there is a catch. Since the build flavor is asynchronous, we need to ensure that the first component is mounted only when the flavor has been fetched from native. For this, we pass null in render method of our component initially, and on receiving callback from
buildFlavor method we re-render the component by using
Implementing flavor specific features
Now that our flavor has been fetched from native and have access to our product flavor in any component, writing flavor specific code is a piece of cake. In fact, we have already seen such implementation in
getThemeColors method. Consider a feature of adding images to notes which is only available in the
Implementing color schemes
When defining styles for a component you can use two approaches:
1. Directly apply styles using the styles prop
2. Use StyleSheets
The first method poses no problems since the styles are evaluated and applied at run time when that particular component is mounted. Thus the
getThemeColors method is evaluated properly and we get the required colors.
App.js after the flavor is fetched, fails to serve its purpose since even though the component is not mounted, its styles have already been evaluated. Thus,
getThemeColors returns the wrong set of colors. To overcome this, we need to create StyleSheets for the component only when it is going to be mounted. We achieve this by creating StyleSheet in
componentWillMount lifecycle method.
So now we have product flavor specific features and color schemes. The only drawback with this setup is that the styles and color schemes are now generated at run time rather than at compile time. Not that it has much of an impact on performance, but still, is a step behind. If you have any ideas to improve this setup, please feel free to share them with me either here in responses or via e-mail.
This is the fourth part in the series “An Android Developer’s Roadmap to React Native”. You can read previous articles in the series by following these links: