AWS IoT and React Native, I love you, but you can do better.
I recently started working with React Native and AWS IoT for a new project. Being a hardcore iOS developer, this change was a little hard to take on. Luckily I had a team of solid React Native developers to guide me.
My part of the project was not building the UI/UX or API integration, but baking real time communication using MQTT! for the app.
The concept of MQTT may seem familiar to you if you’ve already worked with Firebase Cloud Messaging.
If not, no worries … this post isn’t going to help you much either … just kidding :)
How MQTT Works? ⚙️
Publisher:
Subscriber:
A publisher can create and publish to multiple Channels (also called Topics).
A Subscriber can listen to multiple channels and fetch the real time published message. The message that is published is not stored anywhere unless you design your own MQTT broker.
Consider the MQTT broker as a box. Publisher pushes message into the box. Subscriber can connect to the box with the corresponding Channel name(Topic) and receive the message.
The most common convention to name a channel is using the pattern : “Topic/Subtopic”.
GETTING STARTED ON AWS IoT 👍
Step 1: You need an AWS account.
Step 2: Create a Cognito pool. This is for authentication purpose. If you don’t know how to create a Cognito pool check here.
Step 3: When you are in your AWS home page search for “IoT Core” and visit the AWS IOT dashboard. If I were you I’d bookmark this page :)
Step 4: To setup MQTT you will need the following :
1.The AWS Cognito pool Id
2. A Policy
3. Your AWS IoT Specific IoT endpoint url.
You already have a Cognito pool id from where you created the Cognito pool. If not create one. This one is Generic and can be used for all kinds of AWS Authentication (I believe … but hey, I’m no AWS wizard).
The detailed instructions for creating a policy can be found here. AWS IoT policies are JSON documents. They follow the same conventions as IAM policies. AWS IoT supports named policies so many identities can reference the same policy document. Named policies are versioned so they can be easily rolled back. To know more click check here. After creating the policy, click on it, inside your policy’s overview tap on the “Edit policy document” button. and replace the JSON with:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Subscribe",
"iot:Receive"
],
"Resource": "*"
}
]
}
Find your custom endpoint in the AWS IoT console. (From the dashboard, in the left navigation pane, choose Manage, and then choose Things. Select the box representing your button to show its details page. On the details page, in the left navigation pane, choose Interact and look for the HTTPS section, near the top.) Your endpoint will look something like the following:
ABCDEFG1234567.iot.us-east-2.amazonaws.com
where ABCDEFG1234567 is the subdomain and us-east-2 is the region.
Now the setup part is over! Let the coding beginzzz ! 😅😎
React Native has no native components available for our purpose through their regular packages. So I had to look for third party packages out there on the wild wild internet.
One such package that I came across was react-native-mqtt. In this repo they recommend us to use paho.mqtt.javascript due to reasons that are not solved for a very long time! Nevertheless both packages where useless to me (as I am new to React Native and desperate to make MQTT work quickly), these packages didn’t run well with our AWS IoT usage.
Then came the good times when I found some packages which uses AWS. The packages I came across are:
- react-native-aws-iot-device-shadows a github repo by jamesjara.
- aws-iot-device-sdk-js by aws.
- aws-mqtt another github repo by kmamykin.
I also found some interesting reading here.
I was testing all these packages on my iPhone 6+ … and all of them failed! But they did give me good knowledge of how AWS IoT and MQTT works.
How did I do it then, you ask ? 😔
I moved into native (iOS and Android) coding. Yes, I really did that, sorry React Native.
If you need to know where to look for native SDK’s visit this page.
AWS has given a nice sample code example here that works like a charm. We only have to make changes to their constants file about our 3 essential items I’ve mentioned above.
While starting the subscribe and publish for AWS IOT, the app needs to have a certificate. You can download the certificate from the AWS console. But in this app I prefer to create the certificate(only once) on run time and save it in the local memory to reuse it whenever needed.
AWS IoT and iOS-Swift 🍎
React Native supports only Objective C codes! But we are going to write the code in Swift. You will have to open the XCode project inside the iOS sub-folder in the React Native project’s workspace. Follow the following steps to implement the functionality.
Step 1: Just as the good guys at AWS have in their sample app, initialize cocoapods and install the pod:
pod ‘AWSIoT’, ‘~>2.6.0'
Step 2: Create a swift file to write the AWS IoT code. I called it AWSMqtt.swift. As soon as you create this file, XCode will ask you to create a bridge file. Create it, this is important. Your bridge file will of the name <Project name>-Bridging-Header.h. Add the following code to the bridge file.
#import <React/RCTBridgeModule.h>#import <React/RCTEventEmitter.h>#import "AWSCore.h"#import "AWSIoT.h"
Step 3: We will also have to create an Objective-C file to link the bridged native code to React Native’s Javascript. Name it the same as the swift file you created before, like: AWSMqtt.m.
Step 4: Create AWSConstants.swift file to write the constants for the AWS IoT. Add the following values to it, remember to replace the necessary values of your own.
let AWSRegion = AWSRegionType.<your region>//enumlet CognitoIdentityPoolId = <Your Cognito pool id>//Stringlet CertificateSigningRequestCommonName = <name for the singing request>//Stringlet CertificateSigningRequestCountryName = <Country name>//String, get it from localelet CertificateSigningRequestOrganizationName = <Organization’s name>//Stringlet CertificateSigningRequestOrganizationalUnitName = <Organization’s Unit name>//Stringlet PolicyName = <Your policy name>//String. The name of the policy you already created for AWS IoT// This is the endpoint in your AWS IoT console. eg: https://xxxxxxxxxx.iot.<region>.amazonaws.comlet IOT_ENDPOINT = <The IoT endpoint url>//String
Step 5: Take a look at the code here. Add only the necessary code for the AWSMqtt.swift.
Step 6: Now we need to make sure that the React Native knows what all methods are accessible. In-order to do that add the following code to the AWSMQtt.m file.
#import <React/RCTBridgeModule.h>#import <React/RCTEventEmitter.h>@interface RCT_EXTERN_MODULE(AWSMqtt, RCTEventEmitter)RCT_EXTERN_METHOD(setupAAWSMQTT)RCT_EXTERN_METHOD(connectToAWSMQTT)RCT_EXTERN_METHOD(publishToAWSMQTT:(NSString *)topic message:(NSString*)message)RCT_EXTERN_METHOD(subscribeFromAwsMqtt:(NSString*)topic)RCT_EXTERN_METHOD(unsubscribeTopic:(NSString*)topic)RCT_EXTERN_METHOD(unsubscribeAllTopics)@end
The code above supports all the methods in AWSMqtt.swift file here.
Step 7: With step 6 you are all done with the iOS part. Now open your React Native project in your favourite text editor and open the JavaScript file you need to implement AWS IoT. Now add the following items to the React Native import.
- NativeModules
- NativeEventEmitter
- DeviceEventEmitter
import {NativeModules, NativeEventEmitter, DeviceEventEmitter} from "react-native";
Add the constants like:
const { IoTModule } = NativeModules;//For androidconst AWSMqttEvents = new NativeEventEmitter(NativeModules.AWSMqtt);//for ios
Step 8: To initialize AWS IoT for iOS devices,
//Add necessary ListenersAWSMqttEvents.addListener("connectionStatus",this.handleMqttStatusChange);AWSMqttEvents.addListener("message", this.handleMessage);//Setup MqttNativeModules.AWSMqtt.setupAAWSMQTT();//implemented in AWSMqtt.swiftsetTimeout(() => {//Establish Mqtt ConnectionNativeModules.AWSMqtt.connectToAWSMQTT();//implemented in AWSMqtt.swift}, 500);//Handle changes for the MQTT ConnectionhandleMqttStatusChange(params) {console.log("Connection Status", params);}//Process the MQTT datahere.handleMessage(message) {console.log("message: ", message);
}
This will setup and connect the AWS IoT. As you can see there is 500ms delay between calling setup and connect calls. This is because of the actual time delay experienced in setting up the AWS IoT. After connect wait for another second to make the subscribe and publish calls. Delays are only needed when you are executing all these code in one shot.
To Subscribe to a particular MQTT topic:
NativeModules.AWSMqtt.subscribeFromAwsMqtt(<topic>);
To UnSubscribe from a MQTT topic:
NativeModules.AWSMqtt.unsubscribeTopic(<topic>);
To UnSubscribe all MQTT topics:
NativeModules.AWSMqtt.unsubscribeAllTopics();
To Publish to a MQTT topic:
NativeModules.AWSMqtt.publishToAWSMQTT(<topic>, <message>);
We can now run the iOS app successfully!
AWS IoT and Android-Java. 🤖
I am an iOS Developer, so most of the code written for the Android part of AWS IoT, was by my friend @SriHarish_60989. Here is how it works:
Step 1: Update the MainApplication.java’ s “getpackages” function by adding
new MainReactPackage(),new AwsIoTPackage(),
Step 2: We have to create the package “AwsIoTPackage”. Create AwsIotPackage.java like we have done here. Add this file in the same folder as the MainApplication.java.
Step 3: Create a new java file on the same folder. We called it AwsIoTModule.java. Refer the code here to create your own module and make the necessary changes for the constants that you need to add.
Step 4: With the above 3 steps and codes you can implement the Java code. Now open the React Native project and write necessary code from Step 7 of iOS AWS IoT. The DeviceEventEmitter is the component needed for Android. Also don’t forget to add the constant:
const { IoTModule } = NativeModules;//For android
Step 5: To initialize AWS IoT in Android devices:
//Add necessary ListenersDeviceEventEmitter.addListener("Status", this.handleMqttStatusChange);DeviceEventEmitter.addListener("subscribe", this.handleDriverData);//Setup MqttsetTimeout(() => {console.log("Initialise Aws Mqtt");IoTModule.initializeAWSMqtt();}, 1500);//Establish Mqtt ConnectionsetTimeout(() => {IoTModule.connectAWSMqtt();}, 3000);
The delays are necessary due to the initialisation process, only needed when you are executing all these code in one shot.
To Subscribe to a particular MQTT topic/channel:
IoTModule.subscribe(<topic>);
To UnSubscribe a MQTT topic/channel:
IoTModule.unsubscribe(<topic>);
To UnSubscribe all the MQTT channels/topics:
IoTModule.unsubscribeAll();
To Publish to a MQTT topic:
IoTModule.publish(<topic>, <message>);
That’s it for the Android part.
How to test the code? 😈
Open AWS IoT Console, take a look at the panel on the left side of the page. The last option is Test. Open it. The page itself is self explanatory. You can subscribe and publish from the same page.
Stuff that I would love to have: ❤️
- An nice React Native package to do this, instead of writing the code for both iOS and Android separately. The package should have a sample project and step by step details on how to implement it.
Why write this article? 🤔
I was new to React Native and started working on this topic without any knowledge. While working on this topic I always wanted get a article like this to help me around, but there were none.
Some interesting reads, links and references: 🧐
- https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices
- http://www.steves-internet-guide.com/understanding-mqtt-topics/
- https://www.youtube.com/watch?v=jZL4uohxuPc&feature=youtu.be
- https://diyprojects.io/8-online-mqtt-brokers-iot-connected-objects-cloud/
- https://docs.aws.amazon.com/iot/latest/developerguide/configure-iot.html
- https://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html
- https://github.com/jamesjara/react-native-aws-iot-device-shadows
- https://docs.aws.amazon.com/iot/latest/developerguide/view-mqtt-messages.html
- https://github.com/aws/aws-iot-device-sdk-js/issues/86
- https://github.com/awslabs/aws-sdk-ios-samples/tree/master/IoT-Sample/Swift/
- https://github.com/awslabs/aws-sdk-android-samples
- https://teabreak.e-spres-oh.com/swift-in-react-native-the-ultimate-guide-part-1-modules-9bb8d054db03
Thanks to Murtuza Kutub.
AWS IoT and React Native, I love you, but you can do better. was originally published in F22 Labs on Medium, where people are continuing the conversation by highlighting and responding to this story.