Tuesday, 21 May 2019

Sending push notifications from SAP to Mobile device using Firebase Cloud Messaging (FCM)

Notifications on our mobile device is something we experience on a daily basis from various mobile apps we use for News, Entertainment, Shopping, Health etc. Notifications has tremendous value to deliver in the enterprise context as they can deliver the right information at the right time to the right person. If used effectively they can be used as a tool to improve employee productivity, speeding up business processes, improving the quality of services and many more benefits.

This started the exploration for the architecture for sending a notification from the SAP system to the mobile device. After much reading we chose to go with Firebase Cloud Messaging (FCM).

Main steps involved:

1. Creating a project in FCM for your mobile app to send notifications.
2. Setting up the RFC destination in SAP system to connect to FCM.
3. Sending the notification request from the SAP application to FCM.
4. Mobile app should register the subscriber in FCM for the project created in step 1 and maintain the mapping of the user & his FCM device registration id. It is mandatory to subscribe for notifications for the mobile app to receive the notification on the mobile device.
5. FCM will forward the notification to the device or devices.

In this blog we will focus in detail on steps 2 & 3.

Technical Architecture


The event occurs in SAP which triggers a notification request to FCM using a RFC destination. The RFC destination is created to connect the SAP system to FCM. FCM then forwards the notification to the mobile device of the subscriber.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

A. Setting up the RFC destination in SAP system to connect to FCM

Create a new SSL certificate for FCM to be used in the RFC destination.

Creating a new SSL certificate in SAP system to connect to FCM

Transaction: STRUST

Select menu option Environment -> SSL Client Identities to create a new system personal security environment (PSE) with certificates required for FCM.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

Press the button New Entries.

Enter Identity as ‘FCM’ and Description as ‘Firebase Cloud Messaging’.

Press the ‘Save’ button.

Your new System PSE for FCM is now created.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

A new node is created in the Trust Manager list.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

Next we need to add the required certificates to the new System PSE.

Certificates required:

◈ SSL certificate of firebase

◈ SSL certificate of the network domain of the SAP system. This certificate can be obtained from the browser in the section Privacy and security ->Manage certificates under ‘Trusted Root Certification Authorities’. In case you cannot find it then contact your network administrator.

Based on your network architecture, additional certificates may be required.

Check the expiration date of all the certificates and ensure they are valid. This is normally available in the certificate’s signature.

‘Save’ the certificates in the new System PSE created for FCM.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

Creating the RFC destination in SAP system to connect to FCM

Transaction: SM59

Connection Type      : G (HTTP connection to External Serv)

Target host                : fcm.googleapis.com

Service no.                : <port being used for https in your system normally 443>

Path prefix                 : /fcm/send

Proxy host                 : <proxy IP address for internet connectivity>

Proxy service            : <proxy port used for internet connectivity>

Proxy user                 : <domain>\<proxy username>

The proxy user should have permissions in the firewall to send the notification request details to external services in this case FCM.

Proxy password          : <password of the proxy username>

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

In the ‘Logon & Security’ tab select the SSL certificate you created for FCM earlier from the drop down list.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

Save the RFC destination and test this connection.

The RFC destination connection test is successful if a HTTP response status code 200 is received and in the ‘Response body’ tab the FCM HTTP protocol page is displayed.

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

SAP ABAP Certifications, SAP ABAP Study Materials, SAP ABAP Learning

If the HTTP response status is not 200 or the FCM page is not displayed then there is an error which is normally due to:

◈ Missing certificate – Follow guidelines in the trouble shooting guide.

◈ Lack of appropriate permissions in the firewall of the proxy user used in the RFC destination.

B. Sending the notification request from the SAP application to FCM

You can create a sample program following the steps given below.

◈ Create a HTTP client instance using the RFC destination created.

This instance will be used to send the notification request to FCM.

data: lo_http_client TYPE REF TO if_http_client.

cl_http_client=>create_by_destination(
EXPORTING     destination  = ‘TEST-GOOGLESERVICES’
IMPORTING
client                   = lo_http_client   ” HTTP Client Abstraction
EXCEPTIONS
argument_not_found       = 1
destination_not_found    = 2
destination_no_authority = 3
plugin_not_active        = 4
internal_error           = 5
OTHERS                   = 6
).

◈ Set the HTTP protocol version.

lo_http_client->request->set_version( version  = if_http_request=>CO_PROTOCOL_VERSION_1_1 ).

◈ Set the FCM authorized key.

This is the server key of the FCM project created for the mobile app in the firebase console.

data : lv_key type string.

concatenate ‘key=’ <FCM server key> into lv_key.

CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name  = ‘Authorization’
value = lv_key .

Sample authorization value

key=AAAAClj1IYY:APA91bEa4K6mDrTs0LvA9ykzF33RlayWi7u2xJ0TNJLWwxBr05CUoVRcjRuV3baAspndM8abcdefghqk4u8u9dPkSQk85TjOKjzT_07AhY2i4cnc9p0mkjQJ_JhWA4zyxWVKiicFszFT

◈ Set the HTTP method to be used to send the HTTP request to FCM.

In this case the ‘POST’ method will be used.

lo_http_client->request->set_method( if_http_request=>CO_REQUEST_METHOD_POST ).

◈ Set the HTTP request content type to JSON.

lo_http_client->request->set_content_type( ‘application/json’ ).

◈ Build & set the HTTP request payload

The basic HTTP request payload in JSON for FCM has two parts:

1. Notification header – the title & content of the notification popup which appears on the device.

“notification”:{ “title”:”From SAP “, “body”:”Demo notification from SAP!” }

2. Recipients of the Notification.

“to”: “/topics/all”

/topics is a keyword. A topic named ‘all’ (or any other custom name xyz) is sent to FCM from the mobile app when it registers the subscriber’s device. So all users are subscribed to the topic. To send notifications to all subscribers this topic can be used.

(For sending the notification to all notification subscribers for the mobile app)

OR

“to”: <Device registration id of a subscriber in FCM>

Sample device registration id

“c3uN4zsfDFE:APA91bHV7uPFerDdt3_M8xWgjNZwzfiM7N5ffshkgQb72eUxe9hs1v6Y8288wPKZaw500UN0AW7qC4HJXHjgb2VKYeZjYrhQ_LJMkiJyxBe0vo_sjLzrLmN7bRUy347j”

(For sending notification to a specific subscriber his device’s registration id in FCM is needed to send notification for the mobile app to his mobile device. The mapping of the subscriber to the FCM device registration id needs to be maintained externally.)

OR

“registration_ids”: <array of device registration ids>

(For sending notification to multiple users but not all users. An array of subscribers device registration id in FCM is needed to send notification for the mobile app to the subscribers mobile device. The mapping of the user to the FCM device registration id needs to be maintained externally.)

The JSON payload can have other parameters too based on requirement.

Sample payloads would look like:

{ “notification”:{ “title”:”Notification test”, “body”:”Notification from SAP!” }, “to”: “/topics/all” }

OR

{ “notification”:{ “title”:”Notification test”, “body”:”Notification from SAP!” }, “to”: “c3uN4zsfDFE:APA91bHV7uPFerDdt3_M8xWgjNZwzfiM7N5ffshkgQb72eUxe9hs1v6Y8288wPKZaw500UN0AW7qC4HJXHjgb2VKYeZjYrhQ_LJMkiJyxBe0vo_sjLzrLmN7bRUy347j” }

Now we need to set the HTTP request payload we have built.

data : lv_notif_hdr type string,

lv_recipient type string,

lv_payload   type string,

lv_payload_x type xstring.

lv_notif_hdr = ‘{ “notification”:{ “title”:”From SAP “, “body”:”Notification from SAP!” },’.

lv_recipient = ’ “to”: “/topics/all” } ’.

concatenate lv_notif_hdr lv_recipient into lv_payload RESPECTING BLANKS.

CALL FUNCTION ‘SCMS_STRING_TO_XSTRING’
EXPORTING
text   = lv_payload
IMPORTING
buffer = lv_payload_x.

lo_http_client->request->set_data( lv_payload_x ).

◈ Disable logon popup if any.

lo_http_client->propertytype_logon_popup = if_http_client=>co_disabled.

◈ Disable compression of the response received.

lo_http_client->PROPERTYTYPE_ACCEPT_COMPRESS = if_http_client=>co_disabled.

◈ Send HTTP request for sending notification to FCM.

CALL METHOD lo_http_client->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state         = 2
http_processing_failed     = 3
http_invalid_timeout       = 4
OTHERS                     = 5.

◈ Get response for HTTP request sent successfully to FCM.

CALL METHOD lo_http_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state         = 2
http_processing_failed     = 3.

data : lv_http_rc type sy-subrc,

lv_status_text type string.

lo_http_client->response->get_status( IMPORTING code   = lv_http_rc
reason   = lv_status_text ).

data : lv_response type string.

lv_response = lo_http_client->response->get_cdata( ). 

Sample response for notification sent to all subscribers

{“message_id”:5345893630621085936}

Sample response for notification sent to a ONE subscriber

{“multicast_id”:5284586050326936339,”success”:1,”failure”:0,”canonical_ids”:0,”results”:[{“message_id”:”0:1555068985782964%0598d7180598d718″}]}

Sample response for notification sent to a multiple subscribers

{ “multicast_id”: 6022235721032706000,”success”: 2,”failure”: 0,”canonical_ids”: 0,”results”: [  { “message_id”:”0:1555071180867400%ff421e8cff421e8c” }, { “message_id”: “0:1555071180878290%ff421e8cff421e8c”}],}

◈ Close the HTTP client instance.

lo_http_client->close( ).

A sample demo program is attached. Kindly change the server key and device registration id.

REPORT Z_PUSH_NOTIFICATION_DEMO.

data: lo_http_client TYPE REF TO if_http_client.
data: lv_key type string.
data: lv_notif_hdr type string,
      lv_recipient type string,
      lv_payload   type string,
      lv_payload_x type xstring.
data: lv_return type sy-subrc.
data: lv_http_rc type sy-subrc,
      lv_status_text type string.
data: lv_response type string.

cl_http_client=>create_by_destination(
   EXPORTING     destination  = 'TEST-GOOGLESERVICES'
   IMPORTING
     client                   = lo_http_client   " HTTP Client Abstraction
   EXCEPTIONS
     argument_not_found       = 1
     destination_not_found    = 2
     destination_no_authority = 3
     plugin_not_active        = 4
     internal_error           = 5
     OTHERS                   = 6
 ).

lo_http_client->request->set_version( version  = if_http_request=>CO_PROTOCOL_VERSION_1_1 ).

lv_key = 'key=AAAAClj1IYY:APA91bEa4K6mDrTs0LvA9ykzF33RlayWi7u2xJ0TNJLWwxBr05CUoVRcjRuV3baAspndM8abcdefghqk4u8u9dPkSQk85TjOKjzT_07AhY2i4cnc9p0mkjQJ_JhWA4zyxWVKiicFszFT'.
CALL METHOD lo_http_client->request->set_header_field
  EXPORTING
    name  = 'Authorization'
    value = lv_key.

lo_http_client->request->set_method( if_http_request=>CO_REQUEST_METHOD_POST ).

lo_http_client->request->set_content_type( 'application/json' ).

lv_notif_hdr = '{ "notification":{ "title":"From SAP ", "body":"Demo Notification from SAP!" },'.
lv_recipient = ' "to": "/topics/all" } '.
*lv_recipient = ' "to": "c3uN4zsfDFE:APA91V7u-5PFerDdt3_M8xWgjNZwzfiM7N5ffshkgQb72eUxe9hs1v6Y8288wPKZaw500UN0AWe6leZjYrhQ_LJMkiJyxBe0vo_sjLzrLmN7bRUy347j" }'.
concatenate lv_notif_hdr lv_recipient into lv_payload RESPECTING BLANKS.
   CALL FUNCTION 'SCMS_STRING_TO_XSTRING'
   EXPORTING
     text   = lv_payload
   IMPORTING
     buffer = lv_payload_x.
lo_http_client->request->set_data( lv_payload_x ).

lo_http_client->propertytype_logon_popup = if_http_client=>co_disabled.

lo_http_client->PROPERTYTYPE_ACCEPT_COMPRESS = if_http_client=>co_disabled.

CALL METHOD lo_http_client->send
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      http_invalid_timeout       = 4
      OTHERS                     = 5.
IF sy-subrc = 0.

  CALL METHOD lo_http_client->receive
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3.

  lv_return = sy-subrc .

ELSE.

  lv_return = sy-subrc .

ENDIF.

IF lv_return  = 0.

  lo_http_client->response->get_status( IMPORTING code   = lv_http_rc
                                                  reason = lv_status_text ).

  lv_response = lo_http_client->response->get_cdata( ).
  write lv_response.

ELSE.

  write 'Error Message'.
  message id sy-msgid type sy-msgty NUMBER sy-msgno with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 into lv_response.
  write lv_response.

ENDIF.

lo_http_client->close( ).

Note: The subscriber’s device registration id in FCM changes when he reinstalls the app or clears the cache of his mobile device. Therefore ensure you keep the mapping of the subscriber to his latest device registration id for the same device.

No comments:

Post a Comment