Google Cloud Messaging (GCM)

Follow this procedure to implement push notification with GCM.

Introduction to GCM push notification

The push notification solution described in this section is based on the Google Cloud Messaging service. Familiarize yourself with GCM by visiting the https://developers.google.com/cloud-messaging web site.

Google Cloud Message services allow push servers to send notification message data to registered Androidâ„¢ or iOS devices.

The system involves the following actors:
  • The Google Cloud Message service (GCM):

    GCM provides push server and client identification. It also handls all aspects of queuing of messages and delivery to the target application running on registered devices.

  • The registration tokens maintainer:

    A Web Services server program maintaining the database of registration tokens with application user information. This program must listen to new device registration events and store them in a database. The push server program can then query this database to build the list of registration tokens to identify the devices to be notified.

  • The push server program:

    Implemented by a third-party service or as a Genero BDL program using the Web Services API. This push server program will send notification messages to GCM with two connection servers (HTTP and XMPP).

  • Devices running the Genero app registered to the push notification server:

    Registered devices use the push notification client API to register, get notification data and unregister from the service.

Note: The database used to store registration tokens must be a multi-user database (do not use SQLite for example), since two distinct programs will use the database.

Creating a GCM project

To initiate a push notification service dedicated to your applications, you must first create a Google Cloud Messaging project on the Google web site. Creating a GCM project will give you the API Key and the Sender ID. The API Key is the authentication key to access Google services. The Sender ID identifies your GCM project; this id will be used by your mobile app to indicate that it wants to get messages from this GCM project.

To get details about GCM project creation, visit: https://developers.google.com/cloud-messaging.

To create a GCM project and get the API Key and Sender ID, follow the steps at: https://developers.google.com/cloud-messaging/android/client#get-config.

Write down the API Key and the Sender ID generated for you, as these will be used later on.

Implementing the registration tokens maintainer

To handle device registrations on the server side of your application, the same code base can be used for GCM and other token-based frameworks.

For more details, see Implementing a token maintainer.

Implementing the push server

The push server will produce application notification messages that will be transmitted to the GCM service. The GCM service will then spread them to all mobile devices registered to the service with the Sender ID.

Important: The size of an GCM notification content cannot exceed 4 Kilobytes. If more information needs to be passed, after receiving the push message, apps must contact the server part to query for more information. However, this is only possible when network is available.

The push server will use RESTFul HTTP POST requests to send notifications through the GCM service to the following URL:

"https://gcm-http.googleapis.com/gcm/send".

The HTTP POST header must contain the following attributes:
Content-Type:application/json
Authorization:key=API_Key

where API_Key is the API Key obtained during GCM project creation.

The push server program can be implemented with the Web Services API to make RESTFul requests as follows:
IMPORT com
IMPORT util

FUNCTION gcm_send_notif_http(api_key, notif_obj)
  DEFINE api_key STRING,
         notif_obj util.JSONObject

  DEFINE req com.HTTPRequest,
         resp com.HTTPResponse,
         req_msg STRING

  TRY
    LET req = com.HTTPRequest.Create("https://gcm-http.googleapis.com/gcm/send")
    CALL req.setHeader("Content-Type", "application/json")
    CALL req.setHeader("Authorization", SFMT("key=%1", api_key))

    CALL req.setMethod("POST")
    LET req_msg = notif_obj.toString()
    IF req_msg.getLength() >= 4096 THEN
       LET res = "ERROR : GCM message cannot exceed 4 kilobytes"
       RETURN res
    END IF
    CALL req.doTextRequest(req_msg)
    LET resp = req.getResponse()
    IF resp.getStatusCode() != 200 THEN
      DISPLAY SFMT("HTTP Error (%1) %2",
                   resp.getStatusCode(),
                   resp.getStatusDescription())
    ELSE
      DISPLAY "Push notification sent!"
    END IF
  CATCH
    DISPLAY SFMT("ERROR : %1 (%2)", STATUS, SQLCA.SQLERRM)
  END TRY

END FUNCTION
The body of the HTTP POST request must be a JSON formatted record using a structure similar to the following example:
{
  "collapse_key":  "stock_update",
  "time_to_live": 108,
  "delay_while_idle": true,
  "data":
  {
    "stock_change":
    {
      "stock_id" : "STK-034" ,
      "timestamp" : "2015-02-24 15:10:34.18345",
      "item_count" : 15023
    },
  },
  "registration_ids" : [ "APA91b...", "Hun4MxP...", "5ego..." ]
}
Note: This notification message uses the "registration_ids" attribute to provide a list of devices to be notified. If you want to notify a single device, use the "to" attribute instead of "registration_ids", and pass a single registration token instead of a JSON array.

For more details about the JSON request structure in a GCM HTTP POST, see https://developers.google.com/cloud-messaging/http.

By convention, if the "data" member of the JSON request defines a "genero_notification" member, the front-end will show graphical notification (popup hint) with the "title", "content" and the "icon" values.
Note: With GMA, the icon should be packaged in the APK and should be accessible by name (as the gma_ic_genero.png in the drawable folders)
For example:
...
  "data":
  {
    "genero_notification":
    {
      "title":    "Stock has changed",
      "content":  "New stock information will be retrieved from the backend server...",
      "icon":     "stock_update"
    },
    ...
  },
  "registration_ids" : [ "APA91b...", "Hun4MxP...", "5ego..." ]
}
The next code example implements a function that creates the JSON object, which can be passed to the gcm_send_notif_http() function described above. The only purpose of this notification message is to test the "genero_notification" popup hint. The function takes an array of registration tokens as a parameter, which will be used to set the "registration_ids" attribute:
FUNCTION gcm_simple_popup_notif(reg_ids, notif_obj, popup_msg)
    DEFINE reg_ids DYNAMIC ARRAY OF STRING,
           notif_obj util.JSONObject,
           popup_msg STRING
    DEFINE data_obj, popup_obj util.JSONObject

    CALL notif_obj.put("registration_ids", reg_ids)

    LET data_obj = util.JSONObject.create()

    LET popup_obj = util.JSONObject.create()
    CALL popup_obj.put("title", "Notification message!")
    CALL popup_obj.put("content", popup_msg)
    CALL popup_obj.put("icon", "genero")

    CALL data_obj.put("genero_notification", popup_obj)
    CALL data_obj.put("other_info", "Additional data...")

    CALL notif_obj.put("data", data_obj)

END FUNCTION
The gcm_simple_popup_notif() and gcm_send_notif_http() functions can then be used as follows:
IMPORT com
IMPORT util

MAIN
    CONSTANT api_key = "xyz..."
    DEFINE reg_ids DYNAMIC ARRAY OF STRING,
           notif_obj util.JSONObject

    LET reg_ids[1] = "APA91bHun..."
    LET reg_ids[2] = "B4AA2q7xa..."

    LET notif_obj = util.JSONObject.create()
    CALL gcm_simple_popup_notif(reg_ids, notif_obj, "This is my message!")
    CALL gcm_send_notif_http(api_key, notif_obj)

END MAIN
In order to use the tokens database maintained by a token maintainer program, your GCM push server can collect registration tokens as shown in the following example:
FUNCTION gcm_collect_tokens(reg_ids)
    DEFINE reg_ids DYNAMIC ARRAY OF STRING
    DEFINE rec RECORD
               id INTEGER,
               sender_id VARCHAR(150),
               registration_token VARCHAR(250),
               badge_number INTEGER,
               app_user VARCHAR(50),
               reg_date DATETIME YEAR TO FRACTION(3)
           END RECORD
    DECLARE c1 CURSOR FOR
      SELECT * FROM tokens
       WHERE sender_id IS NOT NULL -- In case if APNs tokens remain in the db
    CALL reg_ids.clear()
    FOREACH c1 INTO rec.*
        CALL reg_ids.appendElement()
        LET reg_ids[reg_ids.getLength()] = rec.registration_token
    END FOREACH
END FUNCTION
The above function can then be used by another function to send the push message to all registered devices:
FUNCTION gcm_send_text(api_key, the_text)
    DEFINE api_key, the_text STRING
    DEFINE reg_ids DYNAMIC ARRAY OF STRING,
           notif_obj util.JSONObject,
           info_msg STRING
    CALL gcm_collect_tokens(reg_ids)
    IF reg_ids.getLength() == 0 THEN
       RETURN "No registered devices..."
    END IF
    LET notif_obj = util.JSONObject.create()
    CALL gcm_simple_popup_notif(reg_ids, notif_obj, the_text)
    LET info_msg = gcm_send_notif_http(api_key, notif_obj)
    RETURN info_msg
END FUNCTION

Handle push notifications in mobile apps

To handle push notifications in mobile apps, the same code base can be used for GCM and other token-based frameworks.

For more details see Handling notifications in the mobile app.