Push

Push messages provide a way to inform or remind a user that an action should be taken by delivering a short message that appears as a notification on the device.

When clicked on, the app that is associated with the message is opened.

The Kapsel push plugin provides an abstraction layer over the Google Cloud Messaging for Android (GCM) and Apple Push Notification Service (APNS). A notification can be sent to a device via a REST call to a specific registration id, a user id that may have registered on multiple devices, or to all users of an application as shown in the following examples of a URL used in a REST call.

http://localhost:8080/restnotification/registration/application_registration_id
http://localhost:8080/restnotification/application/com.mycompany.push/user/daniel_v
http://localhost:8080/restnotification/application/com.mycompany.push

The REST call should also include a payload for the message such as the following:

{"alert":"New Vacation Approval Request", "data":"For (i826565) request (7)" }


Note that both GCM and APNS require open ports that may be blocked on some corporate networks or routers. GCM uses ports between 5228 and 5230 on older Android devices as per Google Cloud Messaging not working on 4.1.2 devices on a corporate network. APNS uses the ports described here.

For additional details see C:\SAP\MobileSDK3\KapselSDK\docs\api\sap.Push.html or Using the Push Plugin.

The following steps will demonstrate this plugin using Google Cloud Messaging. Note, it requires either an Android 4.2.2 or higher device with Google Play Store installed (Setting Up Google Play Services) or an Android emulator that targets the Google API’s.

Note, the Push plugin on Android requires the below two checked components from the SDK Manager.

The process for iOS and Windows is covered by others. Here are a few posts to check out.
Apple Push Notification Services in iOS 6
[Kapsel] How to use the Push plugin on iOS
[Kapsel] How to use the Push plugin on Windows

  • Create a server key by creating a new project in the Firebase console. After the project is created, open it and then select Project Settings

  • Then click on the tab CLOUD MESSAGING to display the sender ID and Server API Key.
    Note, either the Server key or Legacy Server key can be used.For more details on the sender ID and Server API key see Key Concepts.See also Firebase Cloud Messaging.
  • Fill in the Push settings for the application.
  • The following instruction set the user name and password that can be used to send notifications when using an SMP server.
    Edit the Notification security provider and add a System Login (Admin Only) authentication provider. Set the user name and password to a value like smpPushUser and smpPushPwd and the role Notification User. Note this user name and password will need to be entered later when we send a notification to the device using the Advanced REST client.
  • Restart the SMP 3.0 server.
  • The following instructions specify the user that can send notifications with the HCPms server.
    Add your user to this role in the SAP HANA Cloud Platform Cockpit.
    Choose Services > Development & Operations > Configure Development & Operations > Roles > Notification User > Assign.

  • Delete the app KapselGSDemo from the device.
  • Remove the AppUpdate plugin and add push plugin.
    cordova plugin remove kapsel-plugin-appupdate
    cordova plugin add kapsel-plugin-push --searchpath %KAPSEL_HOME%/plugins
    
  • Replace www\index.html with the following content.
    <html>
        <head>
            <script type="text/javascript" charset="utf-8" src="serverContext.js"></script>
            <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
            <script>
                applicationContext = null;
    
                window.onerror = onError; 
    
                function onError(msg, url, line) {
                    console.log("EventLogging: onError");
                    var idx = url.lastIndexOf("/");
                    var file = "unknown";
                    if (idx > -1) {
                        file = url.substring(idx + 1);
                    }
                    alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
                    console.log("An error occurred in " + file + " (at line # " + line + "): " + msg);
                    return false; //suppressErrorAlert;
                }
                
                function init() {
                    console.log("EventLogging: init");
                    if (sap.Logger) {
                        sap.Logger.setLogLevel(sap.Logger.DEBUG);  //enables the display of debug log messages from the Kapsel plugins.
                        sap.Logger.debug("Log level set to DEBUG");
                    }
                    sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
                }
                
                function register() {
                   console.log("EventLogging: register");
                   sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
                }
    
                function logonErrorCallback(error) {
                    console.log("EventLogging: logonErrorCallback:  " + JSON.stringify(error));
                    if (device.platform == "Android") {  //Not supported on iOS
                        navigator.app.exitApp();
                    }
                }
                
                function unRegister() {
                    console.log("EventLogging: unRegister");
                    try {
                        sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, errorCallback);
                    }
                    catch (e) {
                        alert("problem with unregister");
                    }
                }
                
                function logonSuccessCallback(result) {
                    console.log("EventLogging: logonSuccessCallback " + JSON.stringify(result));
                    applicationContext = result;
                }
                
                function logonUnregisterSuccessCallback(result) {
                    console.log("EventLogging: logonUnregisterSuccessCallback");
                    alert("Logon Unregistration success");
                    applicationContext = null;
                }
                
                function errorCallback(e) {
                    console.log("EventLogging: errorCallback " + JSON.stringify(e));
                    alert("An error occurred " + JSON.stringify(e));
                }
    
                function registerForPush() {
                    console.log("EventLogging: registerForPush");
                    var nTypes = sap.Push.notificationType.SOUNDS | sap.Push.notificationType.ALERT;
                    sap.Push.registerForNotificationTypes(nTypes, pushRegistrationSuccess, pushRegistrationFailure, processNotification, null /* optional GCM Sender ID */);
                }
    
                function unregisterForPush() {
                    console.log("EventLogging: unregisterForPush");
                    var nTypes = sap.Push.notificationType.SOUNDS | sap.Push.notificationType.ALERT;
                    sap.Push.unregisterForNotificationTypes(pushUnregistrationCallback);
                }
    
                function pushRegistrationSuccess(result) {
                    console.log("EventLogging: pushRegistrationSuccess");
                    alert("Successfully registered for Push: " + JSON.stringify(result));
                }
                
                function pushRegistrationFailure(errorInfo) {
                    console.log("EventLogging: pushRegistrationFailure  " + JSON.stringify(errorInfo));                
                    alert("Error while registering for Push.  " + JSON.stringify(errorInfo));
                }
    
                function pushUnregistrationCallback(result) {
                    console.log("EventLogging: pushUnregistration: " + JSON.stringify(result));
                    alert("Successfully unregistered for Push: " + JSON.stringify(result));
                }
    
                function processNotification(notification) {
                    alert("in processNotification: " + JSON.stringify(notification));
                    console.log("EventLogging: processNotification: " + JSON.stringify(notification));
                }
    
                function onLoad() {
                    console.log("EventLogging: onLoad");
                }
    
                function onBeforeUnload() {
                    console.log("EventLogging: onBeforeUnLoad");
                }
    
                function onUnload() {
                    console.log("EventLogging: onUnload");
                }
    
                function onPause() {
                    console.log("EventLogging: onPause");
                }
    
                function onResume() {
                    console.log("EventLogging: onResume");
                }
    
                function onSapResumeSuccess() {
                    console.log("EventLogging: onSapResumeSuccess");
                }
    
                function onSapResumeError(error) {
                    console.log("EventLogging: onSapResumeError " + JSON.stringify(error));
                }
    
                function onSapLogonSuccess() {
                    console.log("EventLogging: onSapLogonSuccess");
                    registerForPush();
                }
    
                document.addEventListener("deviceready", init, false);
                document.addEventListener("pause", onPause, false);
                document.addEventListener("resume", onResume, false);
                document.addEventListener("onSapResumeSuccess", onSapResumeSuccess, false);
                document.addEventListener("onSapLogonSuccess", onSapLogonSuccess, false);
                document.addEventListener("onSapResumeError", onSapResumeError, false);
            </script>
        </head>
        <body onload="onLoad()" onbeforeunload="onBeforeUnload()" onunload="onUnload()" >
            <h1>Push Sample</h1>
            <button id="register" onclick="register()">Register</button>
            <button id="unregister" onclick="unRegister()">Unregister</button>
            <button onclick="unregisterForPush()">Unregister For Push</button><br>
    
        </body>
    </html>
    
    
  • Prepare, build and deploy the project.
    cordova run android
  • Note that after the Logon plugin registers or initializes, it triggers the onSapLogonSuccess event. In the event handler for the onSapLogonSuccess event, the registerForPush method is called which registers the device to receive push messages the first time it is called and on subsequent calls initializes the push functionality in the app. Notice that in index.html, the following listener is added which when called will registerForPush.
    document.addEventListener("onSapLogonSuccess", registerForPush, false);
    
  • Send a REST request to the SMP server to send a notification to the Kapsel app. Note the example below is using Postman and the provided collection from the section Accessing the Application using the REST API. Remember to use the credential smpPushUser and smpPushPassword under the Authorization tab after selecting Basic Auth.For further details see Notification Data Sent Using Push API.
    http://127.0.0.1:8080/restnotification/application/com.mycompany.push/
    {"alert":"New Vacation Approval Request", "data":"For (i82XXXX) request (7)" }
    
    http://localhost:8080/restnotification/registration/59a72605-2a64-4778-953d-c215a7d565eb
    {"alert":"New Vacation Approval Request", "data":"For (i82XXXX) request (7)" }
    
    http://localhost:8080/restnotification/application/com.mycompany.push/user/i82XXXX
    {"alert":"New Vacation Approval Request", "data":"For (i82XXXX) request (7)" }
    
  • Now press the back button to exit the app and send the notification again. The notification should appear on the device or simulator and clicking on it will open the app.
    The details of the selected notification will be processed in the processNotification method.
  • A logcat filter using the log tag value of PUSH will filter out the messages sent from the Kapsel push plugin. Note, this filter will not show the messages displayed using console.log().
  • Push notifications can be disabled on Android and iOS.
    On iOS open Settings > Notifications > PushDemo
    On Android open Settings > Apps > PushDemo > Uncheck Show Notifications
  • On Android, the sound played when a notification arrives can be selected. Settings > Sound & notification> Default notification ringtone.
  • On an Android emulator, the sound file first needs to be copied onto the device. Open the DDMS perspective in eclipse, select the File Explorer and copy C:\adt-bundle-windows-x86_64-20130917\sdk\platforms\android-19\data\res\raw\fallbackring.ogg to storage\sdcard\Notifications. Restart the emulator. Fallbackring should now be accessible in the settings.
  • Note, there is an open source push plugin that is described at Cordova Push Notifications Plugin.
  • The following posts may also be of interest.
    Keeping Google Cloud Messaging For Android Working Reliably
    How to call the REST Notification API of SMP 3 from ABAP in an Username based scenario
    Delay in receiving messages of 15 minutes or 28 minutes

Troubleshooting

  • On some Android devices there is an error while registering for notification.
    java.lang.UnsupportedOperationException: Device does not have package com.google.android.gsf

    This may occur if the Google Play Services are missing. In order to receive push notifications, follow the below instructions.
    Open the Android SDK Manager click on the Obsolete checkbox and download Extras >Google Cloud Messaging for Android Library (Obsolete)
    Copy the below jar into the libs folder of the PushDemo project.

    C:\Android\adt-bundle-windows-x86_64-20130522\sdk\extras\google\gcm\gcm-client\dist\gcm.jar
  • If the status is 403, this indicates a permission problem. Double check that that the correct user id and password for the Notification security profile were correctly entered. Also double check that the correct role name of Notification User was assigned to the Roles of the authentication provider for the Notification security profile.
  • If the status is 404, this may indicate that the app did not successfully register for notifications. Try pressing the Register for Push button again and verify that the Successfully registered alert displays.
  • The message Invalid Notification target id indicates that device did not successfully register for push. This can be investigated further via the below select command.
    SELECT * from SMP-NOTIFICATION-TARGET where TARGETID = '<connection id>'
    Verify that the 
    - row exists, 
    - TARGETID value is the connection ID, 
    - CONFIGID value is the application ID
    - DEVICENOTIFICATIONKEY1 is the device ID from the gateway/ device ID from APNS or GCM
    - NOTIFICATIONTYPE  must not be null, 0 for APNS, 1 for GCM, 2 for Blackberry, 4 for WNS and 5 for MPNS
    
  • If the status is 200, this may indicate that the app has not registered and received a registration id from Google or perhaps that there is some issue reaching the Google GCM service. Double check that the sender ID was added to the index.html.

Back to Getting Started With Kapsel

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply