Overview

To support different push platform engines an template engine system is needed which provide the transformation of a common push message into the platform target format. The data exchange format uses the json format so the template engine must support json to json transformation like XSLT for XML.

Push template engine jolt

Example

Input JSON
{
    "title": "title",
    "message": "message",
    "articleId": "123",
    "url": "http://test.de/123",
    "pushID": "1234567"
}
Transform template JSON
[
    {
        "operation": "shift",
        "spec": {
            "title": "customFields.title",
            "message": "customFields.subtitle",
            "url": "customFields.url",
            "pushID": "customFields.pushId",
            "articleId": "collapseKey"
        }
    },
    {
        "operation": "default",
        "spec": {
            "customFields": {
                "feedId": "blick.directpush.testfeed.1",
                "regId": "123"
            },
            "timeToLive": "1800",
            "delayWhileIdle": "false"
        }
    }
]
  1. Result JSON

{
  "collapseKey" : "123",
  "customFields" : {
    "feedId" : "http://test.de/feed/1",
    "pushId" : "1234567",
    "regId" : "123",
    "subtitle" : "message",
    "title" : "title",
    "url" : "http://test.de/123"
  },
  "delayWhileIdle" : "false",
  "timeToLive" : "1800"
}

Android json push format

  1. Push format JSON

{
    "collapseKey": "123",      (1)
    "delayWhileIdle": "false", (2)
    "timeToLive": "1800",      (3)
    "customFields": {          (4)
        "field1": "value1",
        "field2": "value2",
        "fieldX": "valueX"
    }
}
1 GCM setting collapseKey
2 GCM setting delayWhileIdle
3 GCM setting timeToLive
4 entry point for custom fields

Note: The Server Key obtained from GCM should be configured in App→ API Key

IOS push input format

For the alert, two different fields can be used: alert and alertObj. Here alert will in fact set only the alert body text, where alertObj can have title and body text specified. Only one of the two should be used. The silent flag is optional.

  1. Push format JSON

{
    "alert": "title",        (1)
    "alertObj": {            (2)
        "title": "alert title",
        "body": "alert body"
    },
    "badge": "0",            (3)
    "sound": "default",      (4)
    "silent": true,          (5)
    "rich": true,            (6)
    "customFields": {        (7)
        "field1": "value1",
        "field2": "value2",
        "fieldX": "valueX"
    }
}
1 APNS setting alert message
2 APNS setting alert title and message
3 APNS setting badge
4 APNS setting sound
5 APNS setting content-available (optional)
6 APNS setting mutable-content (optional)
7 entry point for custom fields

Note: The Keystore(Certificate)/Key(Token) obtained from APNS should be configured in App→ Keystore(Certificate)/Key(Token)

Firebase push input format

  1. Push format JSON

{
    "collapseKey": "123",      (1)
    "delayWhileIdle": "false", (2)
    "timeToLive": "1800",      (3)
    "customFields": {          (4)
        "field1": "value1",
        "field2": "value2",
        "fieldX": "valueX"
    }
}
1 FCM setting collapseKey
2 FCM setting delayWhileIdle
3 FCM setting timeToLive
4 entry point for custom fields

Note: The Server Key obtained from FCM should be configured in App→ Server Key

Web-browser (Chrome, Firefox, etc.) push input format

Api key for app is a GCM/FCM server key (required for Chrome push and for other browsers which use GCM, e.g. Opera).

Example transform template:

[
  {
    "operation": "shift",
    "spec": {
      "url": "data.url",
      "*": "&"
    }
  },
  {
    "operation": "default",
    "spec": {
      "icon": "icon.png",
      "data": { "url": "http://push.delivery" },
      "requireInteraction": "true"
    }
  }
]

This template transforms "url":"link" to "data":{url:"link"} (as required for notification options), writes all other key-value pairs as is and adds default elements to resulting json.

The API for showing a notification in browser (javascript):

<ServiceWorkerRegistration>.showNotification(<title>, <options>);

Title and options could be declared and used as following:

const notificationTitle = 'Title';
const notificationOptions = {
    "title":"eThinking Push Demo",
    "body": "Body text line 1 \n Body text line 2",
    "data": { "url": "http://push.delivery" },
    ...
};
...
self.registration.showNotification(notificationTitle, notificationOptions);

Thus if the above described template and demo service worker (see source code) are used, then the outgoing json should contain following options:

The list of common notification options:

* title - notification's title
* body - notification's body text
* icon - url to icon image
* image - url to body image
* url - url will opened in a new window by click on the notification
* requireInteraction - if true, then the notification will not disappear until user action
* badge - small monochrome icon
* actions - array of actions / buttons (see example 2)

Other options:

* timestamp
* sound
* vibrate
* dir
* tag
* renotify
* silent

Example push message 1 ( title, icon, body and image ):

{
    "title":"eThinking Push Demo",
    "icon":"icon.png",
    "url":"http://push.delivery",
    "body":"Good morning!",
    "requireInteraction":"true",
    "image":"https://imageUrl"
}

notification view in Chrome:

Example

"Image" and "Require interaction" options work only in Chrome at the moment (tested on Google Chrome 60, Firefox 55, Opera 47). An "Image" option requires "https" url.


Example push message 2 ( title, icon, body and buttons ):

{
    "title":"Demo title",
    "icon":"iconFile.png",
    "body":"Hello!",
    "requireInteraction":"true",
    "actions": [
       {"action": "like", "title": "Like", "icon": "https://example/like.png"},
       {"action": "reply", "title": "Reply", "icon": "https://example/reply.png"}
    ]
}

notification view in Chrome:

Example

Actions should be handled in service worker:

self.addEventListener('notificationclick', function (event) {
    event.notification.close();
    let clickResponsePromise = Promise.resolve();
    if (event.action === 'like') {
        clients.openWindow("http://...");
    }
    else if (event.action === 'reply') {
        clients.openWindow("http://...");
    }
    event.waitUntil(Promise.all([clickResponsePromise]));
});