React-Native Push Notifications with Amazon SNS

Here’s a simple guide on how to register a mobile device and how to create an Amazon SNS endpoint programmatically.
Amazon SNS interacts with APN/FCM (and other services) for you, which scales easier than building your own implementations.
A simple diagram of how it works:

For security I’ll show you how to do this using an Amazon Cognito Identity Pool (which you need to setup on your own), but I’ll also give you the less secure alternative that doesn’t require one.
Requirements
- Credentials for your AWS or a Cognito identity pool.
- ARN for iOS (example: “arn:aws:sns:us-east-1:XXXXXXXXX:app/APNS_SANDBOX/CoolApp“)
- ARN for Android (example: “arn:aws:sns:us-east-1:XXXXXXXXX:app/GCM/CoolApp”)
- React-Native Notifications installed: https://wix.github.io/react-native-notifications/docs/getting-started/
- AWS SDK installed: https://www.npmjs.com/package/aws-sdk#getting-Started
- A backend to receive your subscription info (and to trigger the notification with SNS; neither is covered here)
First I’ll give you a breakdown, then you’ll find the whole working code below.
Getting Started
Register the device and get the token
import { Notifications } from 'react-native-notifications';//register the device with the push service
Notifications.registerRemoteNotifications();//setup the onRegistration listener (lambda for clarity)
Notifications.events().registerRemoteNotificationsRegistered((token) => onRegistration(token);
In your onRegistration, you need to first get your credentials
Setup the AWS Credentials
Using a Cognito Identity Pool
import AWS from 'aws-sdk/dist/aws-sdk-react-native';AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: cognitoPool }, {region:'us-east-1'});AWS.config.credentials.getPromise();
Or by hard-coding your credentials (which is not recommended)
AWS.config = new AWS.Config();
AWS.config.accessKeyId = "accessKey";
AWS.config.secretAccessKey = "secretKey";
AWS.config.region = "us-east-1";
Then you can go ahead and create the SNS endpoint specific for this device and send it to your backend.
Create the endpoint
const sns = new AWS.SNS();
sns.createPlatformEndpoint({ARN, Token}, callback);
After creating the endpoint, you want to get it’s attributes just to double check it’s ready to go. This flow is suggested by Amazon, even if it seems redundant.
Get the Endpoint Attributes
sns.getEndpointAttributes({EndpointArn}, callback);
After you get the attributes, make sure the endpoint is enabled and make sure that the tokens match. After that you can go ahead and send the created endpoint and the device token to your backend.
All the Codes
import { Notifications } from 'react-native-notifications';
import AWS from 'aws-sdk/dist/aws-sdk-react-native';
import { Platform } from 'react-native';const cognitoPool = "us-east-1:XXXXX-XXXX-XXXXX-XXXX-XXXX";
const iOSARN = “YOUR-IOS-ARN“;
const androidARN = "YOUR-ANDROID-ARN";const onRegistration = async(event)=>{ try{ console.log("Device Token Received", event.deviceToken); const endpointParams = {
PlatformApplicationArn: Platform.OS === "android" ?
androidARN : iOSARN,
Token: event.deviceToken
}; //fetch credentials from Cognito to create the SNS endpoint
AWS.config.update({region:'us-east-1'});
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: cognitoPool
},
{region:'us-east-1'}); await AWS.config.credentials.getPromise(); const endpointARN = await createARNAsync(endpointParams); if(!endpointARN){
throw new Error('error creating endpointARN');
} console.log("endpointARN:", endpointARN); //get endpoint attributes
let attributes = await getAttributesAsync({
EndpointArn: endpointARN }); console.log('attributes:',attributes); //if token does not match current token
//or the endpoint is disabled, throw an error
if(attributes
&& !attributes.Enabled ||
attributes.Token !== event.deviceToken){
throw new Error('endpoint error');
} //send the data to the backend
//registerDevice(endpointARN, event.deviceToken); }catch(e){ //create the endpoint again and store it
return 0 }};//register the device with the push service
Notifications.registerRemoteNotifications();//setup the onRegistration listener
Notifications.events().registerRemoteNotificationsRegistered(onRegistration);
Here’s the async helper functions. Put them wherever you’d like and btw, you don’t have to create separate instances in each function if you don’t want to.
const createARNAsync = (params) => new Promise((resolve,reject) => { const sns = new AWS.SNS();
sns.createPlatformEndpoint(params,(err, data)=>{ console.log("created endpoint", err, data); if(err || !data.EndpointArn){
return err ?
reject(err) :
reject('arn is missing');
} resolve(data.EndpointArn); });
});const getAttributesAsync = (params) => new Promise((resolve,reject) => { const sns = new AWS.SNS();
sns.getEndpointAttributes(params,(err, data)=>{ console.log('got attrs:', err, data); if(err || !data.Attributes){
return err ?
reject(err) :
reject('attributes are missing in the response');
} resolve(data.Attributes); });
});
Hopefully this helps get your app and device registered for push notifications since the docs don’t offer many examples.