Using the JavaScript SDK with cross-platform apps
A tutorial for adding the JavaScript SDK code to your app to allow your app users to receive push notifications from your Dotdigital account
Unlike our native mobile SDKs, the JavaScript SDK is for cross-platform apps, therefore, after you've added the JavaScript SDK code to your app, you must use a framework, such as Cordova (with PhoneGap) to get a native device token (registration ID), and send it to Dotdigital through the JavaScript SDK.
To set up push notifications for cross-platform apps, complete the following tasks:
- Install the JavaScript SDK
- Configure the JavaScript SDK
- Initialise the JavaScript SDK
- Register the push tokens for the app
- Handle deep links and link tracking
Sample Code
This tutorial explains how to use the SDK with JavaScript, but you can find a full sample of the TypeScript code in the 'JavaScript SDK sample code in TypeScript' section.
More sample apps can be found below, but please note they are provided as basic examples of how you could approach integrating the JavaScript SDK not production ready solutions:
Installing the JavaScript SDK
The JavaScript SDK can be installed from either NPM or Bower, depending on your intended usage.
ES6 Promises
ES6 Promises are used in this SDK which are widely supported in web containers and browsers, but depending on which browsers you are targeting, you may need to use a polyfill such as: es6-shim
Classical JavaScipt
If you use classical JavaScript in your project, and you just want to include a script that exposes some global objects on your page, use Bower.
Bower
- Install the JavaScript SDK
$ bower install comapi-sdk-js-foundation
- Import the script into your project
<script src="bower_components/comapi-sdk-js-foundation/dist/comapi-foundation.js"></script>
//Minified version
<script src="bower_components/comapi-sdk-js-foundation/dist/comapi-foundation.min.js"></script>
ES6 JavaScript
If you use ES6 modules in your project, for example in the Angular and Ionic 2 frameworks, use NPM. The examples for the NPM package are in TypeScript because the NPM version of the SDK is written in TypeScript.
NPM
- Install the JavaScript SDK
$ npm install @comapi/sdk-js-foundation --save
- Import the
Foundation
,ComapiConfig
, andIAuthChallengeOptions
modules from the SDK file
import { Foundation } from "@comapi/sdk-js-foundation"
import { ComapiConfig } from "@comapi/sdk-js-foundation"
import { IAuthChallengeOptions } from "@comapi/sdk-js-foundation"
White listing the SDKs API calls
The built in security in Cordova based apps will restrict the URIs the Cordova app pages can access, therefore you will need to white list the URIs the SDK uses in order for it to operate. To do this do the following:
If using the cordova-plugin-whitelist
Ensure the following line is added to your config.xml file in your project:
<allow-navigation href="https://*.comapi.com/*" />
If using Content-Security-Policy tags
Ensure your Content-Security-Policy tags include the following directive:
connect-src https://api.comapi.com:*
For example:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;connect-src https://api.comapi.com:*">
Configuring the JavaScript SDK
Before you can configure the JavaScript SDK, you need the following:
- The value of the API space ID field in Dotdigital
- A function that creates a JWT
- Create a
ComapiConfig
object by calling theComapi.ComapiConfig()
constructor
var comapiConfig = new COMAPI.ComapiConfig();
- Pass your API Space ID to the
withApiSpaceId()
method
var comapiConfig = new COMAPI.ComapiConfig()
.withApiSpace(appConfig.apiSpaceId);
- Pass the function that creates a JWT to the
withAuthChallenge()
method
var comapiConfig = new COMAPI.ComapiConfig()
.withApiSpace(appConfig.apiSpaceId)
.withAuthChallenge(challengeHandler);
Initializing the JavaScript SDK
After you've configured the SDK, pass the comapiConfig
object to the initialise()
method.
This method creates a valid session by calling your JWT function and by using the JWT to create the user's profile ID (profileId
string).
When a session is stopped and started again, a new JWT token is created and used to create a new profile ID.
A new session will be created under these circumstances when you call the initialise()
method:
- The user uninstalls the app, and then reinstalls it
- The user clears all of the app's data
- You invoke the endSession() method, but this should only be done if you want to stop push notifications being received or change the app user.
Your app needs a valid session in order to add an email address to the user's profile.
COMAPI.Foundation.initialise(comapiConfig)
.then(function (sdk) {
console.log("Foundation interface created", sdk);
})
.catch(function (error) {
$log.error("paragonService: failed to initialise", error);
});
Next in order to send push notifications to the device of your app users, you need to obtain a native device push token using a third-party framework and pass it to the SDK to use. This is covered in the next section.
Using a JavaScript framework to get a native device token and register them
Many frameworks, such as React Native, Cordova with the PhoneGap plugin, and Ionic Capacitor, can be used to acquire the native push tokens required to send push notifications from Dotdigital.
This tutorial uses the Cordova framework with the PhoneGap plugin, but any framework that you choose to use must be able to get a native device token (registrationId
).
Please ensure your APNS (iOS) token is formatted correctly
Our SDK is expecting the APNS push token to be formatted as a 64 character hexadecimal string. Most of the push plugins for the frameworks will do this automatically, and your token should look similar to this:
02df25c845d460bcdad7802d2af6fc1dfce97283bf75cc993eb6dca835ea2e2f
If you token doesn't look like the example above then it is likely that you have simply cast the raw bytes returned by iOS for the push token to a string instead of a hexidecimal string!
If your app is for use on iOS, you'll need to have your app ID's bundle ID. This ID must match the value of the id
attribute in the <widget>
element of your config.xml
file.
If your app is for use on Android, you'll need to have your app's package name that you entered in your push notification profile.
Getting a registration ID, using the Cordova framework with the Adobe PhoneGap plugin
Push notifications can be sent only if the registration ID (registrationId
) is successfully passed to the JavaScript SDK.
Getting the registrationId
(native push token) is an asynchronous task that is performed after the Cordova deviceready
event. In the example below you can see using the Ionic Push library an event handler is created to store the native push token when Ionic Push receives one, and then register it with the Javascript SDK.
The app must set the registrationId
(native push token) if possible when:
- The
platform.ready
event fires e.g. each time the app opens - Whenever the chosen mobile frameworks push library fires an event indicating a
registrationId
(native push token) has been acquired
The JavaScript SDK expects the registration ID to be passed to different methods, depending on the operating system. Therefore, use the cordova device plugin to find out which platform the user is on.
Ensure you bundle id and package id are correct
It is important that your bundle id for iOS and package id for Google FCM match those configured in the respective development portal.
When setting Apple APNS tokens
Please ensure that the environment parameter when calling setAPNSPushDetails() is correct for the app build type, otherwise APNS will not work! The environment parameter should be:
- For development builds - Set the parameter to Environment.development
- For adhoc builds - Set the parameter to Environment.production
- For production app store builds - Set the parameter to Environment.production
import { Environment } from "@comapi/sdk-js-foundation";
import { Push } from 'ionic-native';
const NATIVE_PUSH_TOKEN = "app.nativePushToken";
// Platform ready event handler
platform.ready().then(() => {
// Initialise Ionic push plugin, or your equiavalent for your mobile framework
let push = Push.init({
//For Android apps
android: { senderID: 'Your_Project_ID' },
//For iOS apps
ios: {
alert: "true",
badge: true,
sound: 'false'
}
});
// Register an event handler to handle when native push tokens are acquired async
push.on('registration', (data) => {
// Got a new native push token (registrationId)
console.log("Got a native push token: ", data.registrationId);
// Store the native token for reuse each launch
localStorage.setItem(NATIVE_PUSH_TOKEN, data.registrationId);
// Register the push token with the SDK
registerNativeToken();
});
// Error handling for the push plugin
push.on('error', (error) => {
console.error('Error with Push plugin', error);
});
// Your own push notfication handling for your app if required
push.on('notification', (data) => {
console.log("got a push notification", data);
});
// Try to register a native push token
registerNativeToken();
}
function registerNativeToken() {
// Retrieve the stored native push token (registrationId)
let registrationId = localStorage.getItem(NATIVE_PUSH_TOKEN);
// Skip if registrationId hasn't been collected yet
if(registrationId){
// There are separate methods to call, depending on the operating system
if (platform.is('ios')) {
// You need to create an APNs certificate in the Apple Developer Portal.
// You must upload this cerificate to your push notification profile in Dotdigital
// This certificate can be of type 'development' or 'production', hence the Environment parameter
sdk.device.setAPNSPushDetails("<Bundle Id>", Environment.development, registrationId)
.then(result => {
console.log("setAPNSPushDetails() succeeded", result);
})
.catch(error => {
console.error("setAPNSPushDetails() failed", error);
});
}else if(platform.is('android')){
sdk.device.setFCMPushDetails("<Package Name>", registrationId)
.then(result => {
console.log("setFCMPushDetails() succeeded", result);
})
.catch(error => {
console.error("setFCMPushDetails() failed", error);
});
}
}else{
// No native token
console.log("Can't register native push token as no native push token available yet");
}
}
const NATIVE_PUSH_TOKEN = "app.nativePushToken";
// Platform ready event handler
platform.ready().then(() => {
// Initialise Ionic push plugin, or your equiavalent for your mobile framework
let push = Push.init({
//For Android apps
android: { senderID: 'Your_Project_ID' },
//For iOS apps
ios: {
alert: "true",
badge: true,
sound: 'false'
}
});
// Register an event handler to handle when native push tokens are acquired async
push.on('registration', (data) => {
// Got a new native push token (registrationId)
console.log("Got a native push token: ", data.registrationId);
// Store the native token for reuse each launch
localStorage.setItem(NATIVE_PUSH_TOKEN, data.registrationId);
// Register the push token with the SDK
registerNativeToken();
});
// Error handling for the push plugin
push.on('error', (error) => {
console.error('Error with Push plugin', error);
});
// Your own push notfication handling for your app if required
push.on('notification', (data) => {
console.log("got a push notification", data);
});
// Try to register a native push token
registerNativeToken();
}
function registerNativeToken() {
// Retrieve the stored native push token (registrationId)
let registrationId = localStorage.getItem(NATIVE_PUSH_TOKEN);
// Skip if registrationId hasn't been collected yet
if(registrationId){
// There are separate methods to call, depending on the operating system
if (platform.is('ios')) {
// You need to create an APNs certificate in the Apple Developer Portal.
// You must upload this cerificate to your push notification profile in Dotdigital
// This certificate can be of type 'development' or 'production', hence the Environment parameter
sdk.device.setAPNSPushDetails("<Bundle Id>", Environment.development, registrationId)
.then(result => {
console.log("setAPNSPushDetails() succeeded", result);
})
.catch(error => {
console.error("setAPNSPushDetails() failed", error);
});
}else if(platform.is('android')){
sdk.device.setFCMPushDetails("<Package Name>", registrationId)
.then(result => {
console.log("setFCMPushDetails() succeeded", result);
})
.catch(error => {
console.error("setFCMPushDetails() failed", error);
});
}
}else{
// No native token
console.log("Can't register native push token as no native push token available yet");
}
}
Displaying push notifications
Displaying push notifications while the app is in the foreground
Push notifications are automatically displayed only while the app is in the background. These notifications are sent to the system tray (Android) or the Notification Center (iOS) and launch your app when users tap them.
If you want to display the push notification message while the app is in the foreground, do one of the following:
Android
For Android devices, you can choose to have push notifications displayed automatically when the app is in the foreground, or you can choose to display the push notification message yourself.
Displaying push notifications automatically
When you choose to have push notifications displayed automatically when the app is in the foreground, the on('notification')
callback is run only when the user taps the notification. Therefore, you can decide what happens when the user taps the notification
The push notification is passed as an argument to the push.on('notification')
callback.
- On the
init()
method of the push plugin, set theandroid
object'sforceShow
property totrue
(it's set tofalse
by default).
import { Push } from 'ionic-native';
let push = Push.init({
//For Android apps
android: { senderID: 'Your_Project_ID',
forceShow: true
}
});
const push = PushNotification.init({
//For Android apps
android: { senderID: 'Your_Project_ID',
forceShow: true
}
});
Displaying push notifications yourself
If you want contol over how push notification messages are displayed, you can implement your own way of displaying the push notification while the app is in the foreground.
For this option, the on('notification')
callback is run immediately, and the push notification is passed as an argument to it.
- On the
init()
method of the push plugin, make sure theandroid
object'sforceShow
property is set tofalse
(it's set tofalse
by default).
For iOS
You need to implement your own way of displaying the push notification while the app is in the foreground. The push notification is passed as an argument to the push.on('notification')
callback.
JavaScript SDK sample code in TypeScript
// some app specific imports
import { AppSettings } from "../settings";
import { AuthService } from "./auth";
// Comapi class / interface imports
import { Foundation, ComapiConfig, IAuthChallengeOptions } from "@comapi/sdk-js-foundation"
export class ComapiService {
public sdk: Foundation;
private challengeHandler(options: IAuthChallengeOptions, answerAuthenticationChallenge) {
this._authService.getToken(options.nonce)
.then((token) => {
answerAuthenticationChallenge(token);
});
}
constructor(private _authService: AuthService) { }
/**
* Public method to encapsulate up the initialisation of Comapi
*/
public initialise(): Promise<Foundation> {
return new Promise((resolve, reject) => {
if (this._authService.isAuthenticated()) {
let comapiConfig = new ComapiConfig()
.withApiSpace(AppSettings.APP_SPACE_ID)
// Note the this pointer binding so I can access this._authService in the authChallenge calllback
.withAuthChallenge(this.challengeHandler.bind(this));
Foundation.initialise(comapiConfig)
.then((sdk) => {
this.sdk = sdk;
console.log("foundation interface created");
resolve(sdk);
})
.catch((error) => {
console.error("initialise failed", error);
reject(error);
});
} else {
reject("Not logged in");
}
});
}
}
Deep link support and link tracking
Ensure your app works with deep links and link tracking reporting by following the guidance in this section:
JavaScript generic implementation
It is your responsibility to ensure your app supports any deep links you send in a push message, or you may send deep links for alternate apps such as Facebook etc...
The SDK does provide a function to allow your app to register that a link received in a push message from Dotdigital have been used used and it is highly recommended that you call this function when handling a push message click to ensure the push reporting in Dotdigital is updated!
In your app you must ensure that whenever a push message is clicked on that your app receives a callback with the body data of the push message. This data must be passed to the handleLink function in the SDK to track the links usage.
function handleLink(msg) {
sdk.handleLink(msg)
.then((url) => {
// Any code to run upon a successful call
console.log("Successful click tracking "+url);
})
.catch((error) => {
// Any error handling code
console.log("Error tracking click: "+JSON.stringify(error));
});
}
Cordova based apps
To be able to consume a deep link in your Cordova based app you will need to install the following cordova plugin: cordova-plugin-dotdigital-pushutils. This can be installed by running the following command:
cordova plugin add @comapi/cordova-plugin-dotdigital-pushutils
This plugin facilitates retrieving the link information from the push notification and requesting the device to open it from native code. The link itself can either be a deep link into some area of your app or a normal URL pointing a web page.
Ensure your app implements the push.on
event handler which will be invoked each time a push notification is received e.g.
push.on('notification', (data) => {
// Is there a deep link to process?
if (cordova && cordova.plugins && cordova.plugins.dotdigitalPlugin) {
// You don't need to call containsLink,
// it is safe to call handleLink with all notifications.
// the method is provided should you want to apply some logic in your app.
if (cordova.plugins.dotdigitalPlugin.containsLink(data)) {
cordova.plugins.dotdigitalPlugin.handleLink(data)
.then(() => {
console.log("Deep link handled 👍");
})
.catch((error) => {
console.log("Issue handling deep link 😌", error);
});
}
}
});
Now you have the ability to send deep links via a push message you may wish to implement deep links within your own app to trigger actions.
It is your responsibility to ensure your app supports any deep links you send in a push message, or you may send deep links for alternate apps such as Facebook etc...
To do this you will require a plugin to manage your deep links custom URL schemes. We recommend using cordova-plugin-customurlscheme due to its simplicity, however there are many other plugins which will perform this functionality. You may want to select something more tailored to the framework that you are using. Other options include:
Example of how to implement deep link in Cordova
You should add the plugin to your app and specify a scheme you want your app listen to. The scheme can be any short alphanumeric value that doesn't clash with existing schemes:
cordova plugin add cordova-plugin-customurlscheme --variable URL_SCHEME=yourUrlScheme
This will set a deep link for yourUrlScheme:// scheme.
You can add this function to your app to handle interpreting the deep links:
function handleOpenURL(url) {
setTimeout(function() {
alert("received url: " + url);
console.log(`handleOpenUrl(${url})`);
}, 0);
}
To correctly handle deep links in your app you will need to tweak the native project files:
iOS
You will need to add LSApplicationQueriesSchemes key to your info.plist file to allow opening of deep links.
You can set this in the projects info tab following these steps:
- In your apps project in XCode, go to the Info tab. Under the URL Types, click the + button.
- Put the app’s bundle identifier (e.g., com.example.yourApp) in the Identifier field.
- In the URL Schemes field, put in your deep link scheme.
Android
You will need to modify AndroidManifest.xml file for your app. Apply the following changes:
- android:launchMode needs to be set to singleTask
- Add an intent filter for your deep link scheme:
<intent-filter>
<data android:scheme="yourUrlScheme"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
Alternatively you could add the following configuration to your Cordova project config.xml file and the intent filter will be automatically created:
<platform name="android">
<allow-intent href="yourUrlScheme:*" />
</platform>
Next steps
Now ensure your app passes an email address to the SDK for the app user to ensure they get a contact created in Dotdigital by following these instructions
Want to know more about the SDK?
To find out more about the SDK and it features and functions please go here
Updated 5 months ago