We are pleased to announce that you can now send push notifications to mobile devices (iOS and Android) using LoopBack with the release of the loopback-push-notifications module. What’s LoopBack? It’s an open source mobile backend, powered by Node.js, perfect for building API servers.
In this blog, we’ll walk you through a round trip of push notifications between a LoopBack Node.js server and a demo iOS application. (If you are looking for how to get push notifications working in Android, check out this blog.) The server side is an instance of LoopBack with a simple web page to list device registration records and send out push notifications to selected devices. The client side is an iOS application that uses the LoopBack iOS SDK to register itself with the server and respond to push notifications. You can get the demo applications on Github from these links:
Example: the marketing dept wants to “push” a promotion
To illustrate the end to end flow, let’s start with a simple scenario to understand what components and steps are involved. Let’s suppose the marketing department needs to send a promotion to all users on the company’s iPhone application in the United States. What APIs are needed on the server side?
LoopBack’s push notification service provides the facilities for the server-side to produce and send notifications to mobile devices. The models involved are:
Now that we understand that the server side can identify devices of interest and push notifications to these devices, what about the client applications? How do we enable an iOS application to support push notifications?
Later in this blog, we’ll show you the necessary code to make your application capable of receiving notifications.
The demo server application
Set up the push notification model
The demo server is just a regular LoopBack instance. To support push notifications, we need to create a push model with a database based data source using the fooling code example. The database is used to load/store the corresponding application/user/installation models.
var loopback = require('loopback');
var app = loopback();
var db = require('./data-sources/db');
// Load & configure loopback-push-notification
var PushModel = require('loopback-push-notification')(app, { dataSource: db });
var Application = PushModel.Application;
var Installation = PushModel.Installation;
var Notification = PushModel.Notification;
Sign up an client application with push settings
To support push notifications, the mobile application needs to be registered with LoopBack so that we can have an identity for the application and corresponding settings for APNS.
First, we need to load the certificate and key files into strings.
var fs = require('fs');
var path = require('path');
// You may want to use your own credentials here
exports.apnsCertData = readCredentialsFile('apns_cert_dev.pem');
exports.apnsKeyData =readCredentialsFile('apns_key_dev.pem');
//--- Helper functions ---
function readCredentialsFile(name) {
return fs.readFileSync(
path.resolve(__dirname, 'credentials', name),
'UTF-8'
);
}
The Application model has APIs for the sign-up.
Application.register('strongloop',
config.appName,
{
description: 'LoopBack Push Notification Demo Application',
pushSettings: {
apns: {
certData: config.apnsCertData,
keyData: config.apnsKeyData,
pushOptions: {
},
feedbackOptions: {
batchFeedback: true,
interval: 300
}
},
gcm: {
serverApiKey: config.gcmServerApiKey
}
}
},
function(err, app) {
if (err) return cb(err);
return cb(null, app);
}
);
Configure the database
By default, the demo application uses an in-memory database to store applications and installations. You can customize it by setting MONGODB environment variable to a URL that points to your MongoDB, for example:
mongodb://127.0.0.1/demo.
Start the demo application
$ node app
Send notifications
For the purpose of demonstration, we create a custom endpoint for the AngularJS client to send out a dummy notification for the selected device:
// Add our custom routes
var badge = 1;
app.post('/notify/:id', function (req, res, next) {
var note = new Notification({
expirationInterval: 3600, // Expires 1 hour from now.
badge: badge++,
sound: 'ping.aiff',
alert: '\uD83D\uDCE7 \u2709 ' + 'Hello',
messageFrom: 'Ray'
});
PushModel.notifyById(req.params.id, note, function(err) {
console.log('pushing notification to %j', req.params.id);
});
res.send(200, 'OK');
});
LoopBack provides two Node.js methods to select devices and send notifications to them.
- notifyById: Select a device by registratrion id and send a notification to it
- notifyByQuery: Select a list of devices by the query (same as the where property for Installation.find()) and send a notification to all of them.
Prepare your iOS application
Add LoopBack iOS SDK as a framework
Open your xcode project, select targets, under build phases, unfold ‘Link Binary with Libraries’, and click on ‘+’ to add LoopBack framework.
LoopBack iOS SDK provides the LBInstallation and LBPushNotification classes to simplify the push notification programming for iOS applications.
- http://apidocs.strongloop.com/loopback-ios/api/interface_l_b_installation.html
- http://apidocs.strongloop.com/loopback-ios/api/interface_l_b_push_notification.html
LBInstallation allows the iOS application to register mobile devices with LoopBack. LBPushNotification provides a set of helper methods to handle common tasks for push notifications.
Respond to application launch
When the iOS application is launched, it should initialize an instance of LBRESTAdapter for the SDK to communicate with the LoopBack server. If the application is launched by an offline notification, we can get the message and process it.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.settings = [self loadSettings];
// Instantiate the shared LBRESTAdapter. In most circumstances, you'll do this only once; putting that reference in a
// singleton is recommended for the sake of simplicity. However, some applications will need to talk to more than one
// server - create as many Adapters as you need.
self.adapter = [LBRESTAdapter adapterWithURL:[NSURL URLWithString:self.settings[@"RootPath"]]];
// Reference to Push notifs List VC
self.pnListVC = (NotificationListVC *)[[(UINavigationController *)self.window.rootViewController viewControllers]
objectAtIndex:0];
LBPushNotification* notification = [LBPushNotification application:application
didFinishLaunchingWithOptions:launchOptions];
// Handle APN on Terminated state, app launched because of APN
if (notification) {
NSLog(@"Payload from notification: %@", notification.userInfo);
[self.pnListVC addPushNotification:notification];
}
return YES;
}
Respond to device tokens
An instance of the iOS application should receive a device token. The application needs to register the device token with other information such as appId, userId, timeZone, or subscriptions with the backend so that push notifications can be initiated from LoopBack by querying the installation model. The iOS application receives the device token from the application:didRegisterForRemoteNotificationsWithDeviceToken method.
__unsafe_unretained typeof(self) weakSelf = self;
// Register the device token with the LoopBack push notification service
[LBPushNotification application:application
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken
adapter:self.adapter
userId:@"anonymous"
subscriptions:@[@"all"]
success:^(id model) {
LBInstallation *device = (LBInstallation *)model;
weakSelf.registrationId = device._id;
}
failure:^(NSError *err) {
NSLog(@"Failed to register device, error: %@", err);
}
];
...
}
If your app fails to register for push notifications, the following method will be invoked:
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
// Handle errors if it fails to receive the device token
[LBPushNotification application:application didFailToRegisterForRemoteNotificationsWithError:error];
}
Respond to received notifications
If your app is already running when the notification is received, the notification message is made available in the application:didReceiveRemoteNotification: method through the userInfo parameter.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Receive push notifications
LBPushNotification* notification = [LBPushNotification application:application
didReceiveRemoteNotification:userInfo];
[self.pnListVC addPushNotification:notification];
}
Now we know how to enable the iOS application to interact with LoopBack push notification services. Let’s review the architecture behind.
Architecture
Key Components
- Device model and APIs to manage devices with applications and users
- Application model to provide push settings for device types such as ios and android
- Notification model to capture notification messages and persist scheduled notifications
- Optional Job to take scheduled notification requests
- Push connector that interact with device registration records and push providers such as APNS, GCM, and MPNS.
- Push model to provide high level APIs for device-independent push notifications
What’s Next?
- Learn more about LoopBack, the open-source mobile backend built with Node
- Get our “Mobilizing Enterprise Data with LoopBack Models” whitepaper.
- Ready to build your next mobile app with a Node backend? We’ve made it easy to get started either locally or on your favorite cloud, with a simple npm install.