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. 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. 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. A new node is created in the Trust Manager list. 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. 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. : Path prefix : /fcm/send Proxy host : Proxy service : Proxy user : \ The proxy user should have permissions in the firewall to send the notification request details to external services in this case FCM. Proxy password : In the ‘Logon & Security’ tab select the SSL certificate you created for FCM earlier from the drop down list. 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. 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=’ 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”: 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”: (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.