Mobile applications / Push notifications |
Follow this procedure to implement push notification with APNs.
The push notification solution described in this section is based on the Apple Push Notification Service. Familiarize yourself with APNs by visiting the Apple Push Notification Service web site.
Apple Push Notification service allows push servers to send notification message data to registered iOS (and OS X) devices.
The APNs service transports and routes a remote notification from a given provider to a given device. A notification is a short message built from two pieces of data: the device token and the payload.APNs provides push server and client identification. It also handles all aspects of message queuing and delivery to the target applications running on registered devices. The APNs system includes a feedback service that can be queried to check for devices that have unregistered and no longer need to be notified.
A Web Services server program maintaining the database of device tokens, with application user information. This program must listen to new device registration events, store them in a database, and from time to time query the APNs feedback service to check for unregistrations.
This program will send notification messages to the APNs server by using the com.APNS class and TCP request API. The push provider program will query the device token database to know which devices need to be notified.
Registered devices use the push notification client API to register, get notification data and unregister from the service.
iOS apps must be created with an Apple certificate for development or distribution, linked to an App ID (or Bundle ID) with push notification enabled. The provisioning profile used when building the IPA must be linked to the App ID with push enabled. Certificate, provisioning and bundle id must be specified to the GMI build tool.
To create the push provider linked to your app, usually you need to create two Apple Push Notification certificates linked to your App ID (you select the App ID when you create a push certificate in the Apple member center): One certification for development and another for distribution. For more details about the push provider certificates, see APNs SSL certificate.
Check also Apple Push Notification documentation for more details about certificate requirements for push notifications.
Each APNs client device is identified by a device token. A device token is an opaque identifier of a device that APNs gives to the device when an app registers itself for push notification. It enables APNs to locate in a unique manner the device on which the client app is installed. The device shares the device token with the push provider. The push provider must produce notification messages for each device by including the device token in the message structure.
In a notification message, the payload is a JSON-defined property list that specifies how the user of an app on a device is to be alerted.
The payload must contain a list of "aps" records. Each "aps" record represents a notification message to be displayed as a hint on the device (for example, by adding a badge number to the app icon). The "aps" records can also contain custom data in a separate set of JSON attributes.
[ { "aps" : { "alert" : "My first push", "badge" : 1, "sound" : "default", "content-available" : 1 } }, { "aps" : { "alert" : { "title" : "Push", "body" : "My second push" } "badge" : 2, "sound" : "default", "content-available" : 1 }, "new_ids" : [ "XV234", "ZF452", "RT563" ], "updated_ids" : [ "AC634", "HJ153" ] } ]
With APNs, badge number handling is in charge of the application code: The push provider sends a badge number in the payload records, the app can check the message content, and must communicate with a server component, to indicate that the notification message has been consumed. The server program can then maintain a badge number for each registered device, decrementing the badge number.
In this tutorial, badge numbers are stored on the server database. The token maintainer handlers requests from apps to sync the badge number for a given device token, and the push provider program reads the database to set the badge number in the notification payload. When the app consumes messages, it queries and resets the app badge number with the getBadgeNumber/setBadgeNumber front calls, and informs the token maintainer to sync the badge number in the central database.
For each interface, use TLS (or SSL) to establish a secured communication channel. The SSL certificate required for these connections is obtained from Apple's Member Center.
To establish a TLS session with APNs, an Entrust Secure CA root certificate must be installed on the provider’s server. If the server is running OS X, this root certificate is already in the keychain. On other systems the certificate might not be available.
The Apple Push Notification Certificate identifies the push notification service for a given mobile app. This certificate will be created from an App ID (a.k.a. Bundle ID) and is used by the APNs system to dispatch the notification message to the registered devices.
For more details, see APNs SSL certificate.
To handle device registrations on the server side of your application, the same code base can be used for APNs and other token-based frameworks.
For more details, see Implementing a token maintainer.
The push provider will produce application notification messages that will be transmitted to the APNs service. The APNs service will then spread them to all registered mobile devices, identified by their device token.
To send notification messages, the push provider must build binary messages by using the com.APNS API, provided by the Web Services library, and send TCP message requests over SSL to the following URLs:
The following example demonstrates how to implement a function to send an APNs notification message. The function takes a device token and a JSON object as parameters. First, build the binary data with the com.APNS.EncodeMessage() method, then POST the data with a com.TCPRequest.doDataRequest() method. In case of success, the TCP request timeout will occur (APNs service only responds immediately in case of error), then use the com.TCPResponse.getDataResponse() method, to get status information. See com.APNS.EncodeMessage() for more details about notification message creation.
IMPORT com IMPORT security IMPORT util FUNCTION apns_send_notif_http(deviceTokenHexa, notif_obj) DEFINE deviceTokenHexa STRING, notif_obj util.JSONObject DEFINE req com.TCPRequest, resp com.TCPResponse, uuid STRING, ecode INTEGER, dt DATETIME YEAR TO SECOND, exp INTEGER, data, err BYTE, res STRING LOCATE data IN MEMORY LOCATE err IN MEMORY LET dt = CURRENT + INTERVAL(10) MINUTE TO MINUTE LET exp = util.Datetime.toSecondsSinceEpoch(dt) TRY LET req = com.TCPRequest.create( "tcps://gateway.push.apple.com:2195" ) CALL req.setKeepConnection(true) CALL req.setTimeout(2) # Wait 2 seconds for APNs to return error code LET uuid = security.RandomGenerator.createRandomString(4) CALL com.APNS.EncodeMessage( data, security.HexBinary.ToBase64(deviceTokenHexa), notif_obj.toString(), uuid, exp, 10 ) IF LENGTH(data) > 2000 THEN LET res = "ERROR : APNS payload cannot exceed 2 kilobytes" RETURN res END IF CALL req.doDataRequest(data) TRY LET resp = req.getResponse() CALL resp.getDataResponse(err) CALL com.APNS.DecodeError(err) RETURNING uuid, ecode LET res = SFMT("APNS result: UUID: %1, Error code: %2",uuid,ecode) CATCH CASE STATUS WHEN -15553 LET res = "Timeout Push sent without error" WHEN -15566 LET res = "Operation failed :", SQLCA.SQLERRM WHEN -15564 LET res = "Server has shutdown" OTHERWISE LET res = "ERROR :",STATUS END CASE END TRY CATCH LET res = SFMT("ERROR : %1 (%2)", STATUS, SQLCA.SQLERRM) END TRY RETURN res END FUNCTIONThe next code example implements a function that creates the JSON object defining notification content (payload). That object can be passed to the apns_send_notif_http() function described above:
FUNCTION apns_simple_popup_notif(notif_obj, msg_title, user_data, badge_number) DEFINE notif_obj util.JSONObject, msg_title, user_data STRING, badge_number INTEGER DEFINE aps_obj, data_obj util.JSONObject LET aps_obj = util.JSONObject.create() CALL aps_obj.put("alert", msg_title) CALL aps_obj.put("sound", "default") CALL aps_obj.put("badge", badge_number) CALL aps_obj.put("content-available", 1) CALL notif_obj.put("aps", aps_obj) LET data_obj = util.JSONObject.create() CALL data_obj.put("other_info", user_data) CALL notif_obj.put("custom_data", data_obj) END FUNCTION
IMPORT com IMPORT util MAIN DEFINE reg_ids DYNAMIC ARRAY OF STRING, notif_obj util.JSONObject, i INTEGER LET notif_obj = util.JSONObject.create() CALL gcm_simple_popup_notif(notif_obj, "This is my message!", 1) LET reg_ids[1] = "APA91bHun..." LET reg_ids[2] = "B4AA2q7xa..." ... FOR i=1 TO reg_ids.getLength() DISPLAY gcm_send_notif_http(reg_ids[i], notif_obj) END FOR END MAIN
FUNCTION apns_collect_tokens(reg_ids) DEFINE reg_ids DYNAMIC ARRAY OF RECORD token STRING, badge INTEGER END RECORD 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, x INTEGER DECLARE c1 CURSOR FOR SELECT * FROM tokens WHERE sender_id IS NULL -- In case if GCM tokens remain in the db CALL reg_ids.clear() FOREACH c1 INTO rec.* LET x = reg_ids.getLength() + 1 LET reg_ids[x].token = rec.registration_token LET reg_ids[x].badge = rec.badge_number END FOREACH END FUNCTION
FUNCTION save_badge_number(token, badge) DEFINE token STRING, badge INT UPDATE tokens SET badge_number = badge WHERE registration_token = token END FUNCTION
FUNCTION apns_send_message(msg_title, user_data) DEFINE msg_title, user_data STRING DEFINE reg_ids DYNAMIC ARRAY OF RECORD token STRING, badge INTEGER END RECORD, notif_obj util.JSONObject, info_msg STRING, new_badge, i INTEGER CALL apns_collect_tokens(reg_ids) IF reg_ids.getLength() == 0 THEN RETURN "No registered devices..." END IF LET info_msg = "Send:" FOR i=1 TO reg_ids.getLength() LET new_badge = reg_ids[i].badge + 1 CALL save_badge_number(reg_ids[i].token, new_badge) LET notif_obj = util.JSONObject.create() CALL apns_simple_popup_notif(notif_obj, msg_title, user_data, new_badge) LET info_msg = info_msg, "\n", apns_send_notif_http(reg_ids[i].token, notif_obj) END FOR RETURN info_msg END FUNCTION
See also Provider Communication with Apple Push Notification Service.
To handle push notifications in mobile apps, the same code base can be used for APNs and other token-based frameworks.
For more details see Handling notifications in the mobile app.