Apple Push Notification Service (APNs)
Follow this procedure to implement push notification with APNs.
Introduction to APNs push notification
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 macOS) 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.- The Apple Push Notification Service (APNs):
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.
- The device tokens maintainer:
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.
- The push provider:
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. - Devices running the Genero app registered to the push notification server:
Registered devices use the push notification client API to register, get notifications data and unregister from the service.
APNs push notification security
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 buildtool.
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/TLS certificate.
Check also Apple Push Notification documentation for more details about certificate requirements for push notifications.
Identifying target devices
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.
Notification content (payload)
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.
notificationpushed
action was detected with an ON ACTION
handler.notificationpushed
action, but the
getRemoteNotifications
front call will return no message data
(data return param is NULL
). If such case,
implement a fallback mechanism (based on RESTFul web services for example), to
contact the push notification provider and retrieve the message information.getRemoteNotifications
front
call:[
{
"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" ]
}
]
Badge number handling
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.
Communication channels
- The binary interface of the APNs development environment is available
through the URL
gateway.sandbox.push.apple.com
on port2195
. - The binary interface of the APNs production environment is available through
the URL
gateway.push.apple.com
on port2195
. - The binary interface of the APNs feedback service is available through the
URL
feedback.push.apple.com
on port2196
.
For each interface, use TLS (or SSL) to establish a secured communication channel. The SSL/TLS 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 macOS, this root certificate is already in the keychain. On other systems the certificate might not be available.
Creating an APNs certificate for the app
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/TLS certificate.
Implementing the device tokens maintainer
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.
Implementing the push provider
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/TLS to the following URLs:
"tcps://gateway.sandbox.apple.com:2195"
(for development)"tcps://gateway.push.apple.com:2195"
(for production)
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" )
LET req = com.TcpRequest.Create( "tcps://gateway.sandbox.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)
DISPLAY "PUSH MESSAGE: ", deviceTokenHexa, "/", notif_obj.toString()
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 FUNCTION
The 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
apns_simple_popup_notif()
and
apns_send_notif_http()
functions can then be used as
follows: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,
notification_type VARCHAR(10),
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 notification_type = "APNS"
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
Handle push notifications in mobile apps
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.