Building React Native Apps: Retrofitting an iOS app to Android
I. Introduction to React native
React Native is a framework for building mobile apps using React and JavaScript. It has support for building mobile apps for the iOS and Android platforms. The framework is open-sourced by Facebook on March 2015 and is built on the premise: Learn once, Write anywhere.
Using React for the UI, we can build both web and mobile apps—with React Native used for the latter because it has a set of React components for iOS and Android platforms. The React components available with React Native gets translated to native components which provide a better user experience that are consistent with the mobile platform.
This Facebook post explains why "native is necessary".
II. Build an app
This tutorial will extend a React Native Todo app from iOS to the Android platform. The Todo app is super-simple. It has two tabs and the first tab has the Todo list.
When the Todo item is done, press the Done button. This will remove the Todo item from the list. The second tab has the Add Todo
form.
The source code for the iOS app can be found in this Github project. And in this tutorial, we will retrofit the app for the Android platform.
A. Getting started with Android in React Native
There is a Getting started guide for setting up React Native for Android app development. The precise steps vary based on the development OS —Mac, Linux, or Windows. At high level, setting up React Native for Android involves:
- Installing Node.
- Installing Android Studio.
- Setting the
ANDROID_HOME
path. - Creating a new AVD (Android virtual device or emulator)
Any new React Native project has an Android project.
The android
folder has the app
folder which has the source code for the app and the gradle
folder which has the associated build settings.
The entry point for the React Native app is index.android.js
. When running the React Native app, the Todo component within index.android.js
is rendered.
B. Using equivalent Android components
The iOS app used TabBarIOS
component for displaying tabs. For Android, the TabBarIOS
component needs to be replaced with ToolbarAndroid
component. The render method of the index.android
component is shown below.
render() {
return (
<View style={styles.container}>
<ToolbarAndroid
actions={actions}
onActionSelected={this.handleActionSelected}
style={styles.toolbar}
subtitle={this.state.actionText}
/>
<ViewPagerAndroid
ref={c => { this.pager = c; }}
style={styles.viewPager}
initialPage={0}
>
<View>
<List
todos={this.state.todos}
onDeleteTodo={this.handleDeleteTodo}
/>
</View>
<View>
<Add onAddTodo={this.handleAddTodo} />
</View>
</ViewPagerAndroid>
</View>
);
}
The two views — Add
and List
— are embedded in the ViewPagerAndroid
component. The List component lists all the Todo items. The Add component adds a new Todo item. ToolbarAndroid
has the onActionSelected
event which must be handled to switch to a new view.
handleActionSelected(position) {
this.setState({
actionText: actions[position].title,
});
this.pager.setPage(position);
}
The reason we moved TabBarIOS
to ToolbarAndroid
is because of the native experience we get. The following video highlights the native experience when we select the toolbar actions.
React Native components render as native components in each platform. Components suffixed with IOS
are available only for iOS platform. Components suffixed with Android
are available only the for Android platform. For displaying progress, ProgressViewIOS
and ProgressBarAndroid
are equivalent React Native components for each platform.
C. Android-only components
ToastAndroid
is an API available only for Android. It displays a toast
or message that appears for a short duration. The handleAddTodo
method adds a Todo item to the Todo list. After the item is added, a toast message is displayed, like so:
handleAddTodo(todo) {
let { todos } = this.state;
todos = todos.slice();
todos.push(todo);
this.setState({ todos });
ToastAndroid.showWithGravity('Todo is added',
ToastAndroid.LONG, ToastAndroid.TOP);
}
We have already seen the ToolbarAndroid
and ViewPagerAndroid
components which exist only for the Android platform. DrawerLayoutAndroid is another Android-only React component that wraps the DrawerLayout
. DrawerLayout
renders the navigation view which can be pulled from the side of the app.
D. Other differences
Platform differences can be explicitly handled with React components. For example, for the TextInput
component, we don't want to show a border for the Android platform.
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
input: {
borderColor: '#ccc',
borderWidth: (Platform.OS === 'ios') ? 1 : 0,
borderRadius: 5,
},
});
React Native components are configured using props and some props are available only for the Android platform. For example, the numberOfLines
and returnLabel
props in TextInput
are available only for the Android platform. The keyboardType
prop in TextInput
also deserves to be mentioned. And not all the keyboard types are available on both platforms. Only default
, numeric
, email-address
and phone-pad
are available cross-platform.
III. Wrapping up
While extending an iOS-only React Native app to the Android platform, the following points should be kept in mind:
- There are platform specific components. Whenever an iOS-only component is used, an equivalent Android-only component should be used.
- There are Android-only components which should be used to enhance the native experience.
- Most of the React Native components are cross-platform but there are minor differences in the props available to each platform.
The underlying idea behind React Native is to provide the native experience to the user. There may be occasions where developers prefer to use JavaScript components to have the same look-and-feel across iOS and Android. A better approach is to take advantage of platform-specific features to provide a better native experience. Native experience is preferred over consistent look-and-feel.
There is an accompanying GitHub project to this tutorial that'll help you learn more about React Native. And for further consideration, you can also read this React Native and Ionic comparison tutorial.
I tried to convert this example https://www.raywenderlich.com/165140/react-native-tutorial-building-ios-android-apps-javascript to Android following your document. I just replaced NavigatorIOS to NavigatorAndroid in index.Android.js but I could not get it to work. I am getting this error https://stackoverflow.com/questions/46028469/react-native-element-type-is-invalid-when-converting-ios-to-android , would you mind clarifying. Much appreciated.
… btw, did you have to do any change in package.json and jsonconfig.json or any other files other than index.android.js and index.ios.js?
I am trying to learn RN and how it shares code btw Android and IOS.
Much apprecaited
There is no change in package.json. There is an accompanying Github project. Please feel free to clone it and see if it helps.
yes, I got that. thanks
By far best article so far Vijay, thank you so much.
Thanks for your feedback.