React Native is a great framework for developing mobile applications with JavaScript and ReactJS.
But what about your existing iOS code?
In this guide I will show you how to use native Objective-C code along with JavaScript. In this way you can use existing iOS code (you might already have) inside your JavaScript code, awesome right?!
The React Native documentation is not that big by now, but there is already a part about native iOS Modules. This article presents you the complete guide on how to get started with native modules in a simple demo app. The result will be this demo app which calculates the square of a number, but all the action takes place in native Objective-C code!
Start with a blank app
We will start with the boilerplate template React Native offers us. If you haven’t set up React Native or have no idea what’s it about, I recommend you take a look at my React Native getting started guide or my simple demo on setting up a Tab bar!
If you are ready, go to your command line and start a new project:
react-native init devdactic_nativeModules
As this template is already working, you can open the devdactic_nativeModules.xcodeproj and hit CMD+R to run your app in the simulator. If it’s working now, we can head on.
Remember, to the date of making this tutorial you can only build iOS apps so you will need a Mac, and I am using the version 0.4.4!
Creating a simple iOS Module
If you have never worked with Objective-C the next part might scare you a bit. But if you have been looking for help on how to include iOS modules in React Native, I guess you already have an idea what this might be about.
You can open the Xcode project inside your folder and add a new class called MyObjcClass or add 2 files to your folder: MyObjcClass.h and MyObjcClass.m. This creates the header and implementation file for our iOS Module.
Now open the MyObjcClass.h and replace the content with:
#import "RCTBridgeModule.h" @interface MyObjcClass : NSObject <RCTBridgeModule> @end
As you can see, we need to import the RCTBridgeModule which allows us to bridge our native code to JavaScript and additional we need to add the Protocol as well.
The guys behind React Native have created a system using macros to bridge the code, which they are not completely happy about, but it works at the moment and it’s safe for future updates. By now we are not performing any work, so open the MyObjcClass.m and replace everything inside with:
#import "MyObjcClass.h" @implementation MyObjcClass // The React Native bridge needs to know our module RCT_EXPORT_MODULE() - (NSDictionary *)constantsToExport { return @{@"greeting": @"Welcome to the DevDactic\n React Native Tutorial!"}; } RCT_EXPORT_METHOD(squareMe:(int)number:(RCTResponseSenderBlock)callback) { callback(@[[NSNull null], [NSNumber numberWithInt:(number*number)]]); } @end
First of all we need to call a macro which notices the bridging module that this class should be available from our JavaScript code.
The first function is an example for how to use constants. The name of this function is fixed, so don’t change it or your code won’t work. We return a dictionary which contains a simple string, just to demonstrate the workflow.
Does the second function look scary to you?
Don’t worry, it’s easier than you think. We just need to call this export macro to export our function, just like we did with the complete class. Inside the macro we define our function squareMe
which takes a number as argument and also a callback.
We need to go this way, as all those calls are asynchronous so we can’t just return a value. But no problem, we call the callback with an array consisting of 2 objects. The first is an error object which should be nil at this point, the second is the result of our very hard calculation.
Note, the same functions without the callback stuff would look like this in Objective-C:
- (NSInteger)squareMe:(int)number { return number*number; }
So the system might look ugly, but in fact it’s so straight forward you will get used to this in no time. There are some more macros, but at the moment really just a fistful.
Do you want to see the same happen with Swift? Just tweet @schlimmson!
For now this is everything we need to make our Objective-C iOS Module ready for use inside our JavaScript app!
Using the bridged Code from our JavaScript app
I expect you to have a little knowledge about React Native, so let’s go ahead and implement a simple demo app.
Do you know what we would like to achieve now?
There are 2 tasks we want to perform:
- Retrieve a constant from our Objective-C class
- Call a function from the iOS module and show the result
Therefore, we will have 2 simple textviews and a textinput. Additional, we use the ES6 syntax so make sure to really copy everything of this to your index.ios.js or otherwise you might get some errors:
var React = require('react-native'); // 1 var { Component, AppRegistry, StyleSheet, Text, TextInput, View, } = React; // 2 var MyObjcClass = require('NativeModules').MyObjcClass; class devdactic_nativeModules extends Component { // 3 constructor(props) { super(props); this.state = { number: 0 }; } // 4 render() { return ( <View style={styles.container}> <Text style={styles.welcome}> {MyObjcClass.greeting} </Text> <TextInput style={styles.input} onChangeText={(text) => this.squareMe(text)}/> <Text style={styles.result}> {this.state.number} </Text> </View> ); } // 5 squareMe(num) { if (number == '') { return; } MyObjcClass.squareMe(num, (error, number) => { if (error) { console.error(error); } else { this.setState({number: number}); } }) } }; // 6 var styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 20, }, input: { width: 100, height: 40, borderColor: 'red', borderWidth: 1, alignSelf: 'center' }, result: { textAlign: 'center', color: '#333333', fontSize: 30, fontWeight: 'bold', margin: 20, }, }); AppRegistry.registerComponent('devdactic_nativeModules', () => devdactic_nativeModules);
There is no magic here, but let’s go through all of those points.
- 1. First of all we extract all those components so we can use them more easy later
- 2. This line imports our Objective-C iOS module to our JavaScript code
- 3. Our constructor sets the initial value of the result textfield
- 4. The render function takes care of drawing our view (or the state of our view). The first textview shall show the constant, therefore we call
{MyObjcClass.greeting}
. Do you remember we put the greeting inside a dictionary? Here we can just call the key to get that value.
The TextInputField calls thesquareMe
function whenever we change the text, and the last view just shows the result of the calculation (initial 0) - 5. This function is called when we type, so we just check if there is anything inside the field and call our bridged class again. As we expect a callback, we have to wait for the result and if receive get no error we update our state variable, so the view get’s update as well!
- 6. A bit of styling so our demo doesn’t look like a piece of shit.
If you have started your app previously you might need to start it again to load the Objective-C classes, otherwise just refresh the view (cmd+r inside the simulator) and square the hell out of your app!
See a video version of this article below, and make sure to follow my YouTube channel for more great video tutorials.
If all of this was helpful, I would be happy to see a follower more on @schlimmson and leave a comment/ tweet it!
Make sure to subscribe to my mailing list to receive new posts and updates by mail!
So long,
Simon
The post How To Easily Make Your Objective-C Code Work With React Native appeared first on DevDactic.