Provider Communication with Apple Push Notification Service
This chapter describes the interfaces(接口) that providers use for communication with Apple Push Notification service (APNs) and discusses some of the functions that providers are expected to fulfill(满足、实行).
General Provider Requirements
As a provider you communicate with Apple Push Notification service over a binary interface. This interface is a high-speed, high-capacity interface for providers; it uses a streaming TCP socket design in(设计) conjunction(结合) with binary content. The binary interface is asynchronous.
The binary interface of the production environment is available through gateway.push.apple.com, port 2195; the binary interface of the sandbox (development) environment is available through gateway.sandbox.push.apple.com, port 2195. You may establish multiple, parallel connections to the same gateway or to multiple gateway instances.
For each interface you should use TLS (or SSL) to establish a secured communications channel. The SSL certificate required for these connections is provisioned(配置) through the iOS Provisioning Portal. (See “Provisioning and Development” for details.) To establish a trusted provider identity(身份), you should present this certificate to APNs at connection time using peer-to-peer(对等) authentication(认证).
Note: 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 Mac OS X, this root certificate is already in the keychain. On other systems, the certificate might not be available. You can download this certificate from the Entrust SSL Certificates website.
You should also retain connections with APNs across multiple notifications. APNs may consider connections that are rapidly(急速) and repeatedly(多次) established and torn down(推倒) as a denial-of-service(拒绝服务) attack. Upon error, APNs closes the connection on which the error occurred.
As a provider, you are responsible for the following aspects of push notifications:
If you intend to support notification messages in multiple languages, but do not use the loc-key and loc-args properties of the aps payload dictionary for client-side fetching of localized alert strings, you need to localize the text of alert messages on the server side. To do this, you need to find out the current language preference from the client application. “Scheduling, Registering, and Handling Notifications” suggests an approach(途径) for obtaining this information. See “The Notification Payload” for information about the loc-key and loc-args properties.
The Binary Interface and Notification Formats
The binary interface employs a plain TCP socket for binary content that is streaming in nature. For optimum(最佳) performance, you should batch(批量) multiple notifications in a single transmission(传输) over the interface, either explicitly or using a TCP/IP Nagle algorithm.
The interface supports two formats for notification packets, a simple format and an enhanced format that addresses some of the issues with the simple format:
The enhanced format is recommended for most providers.
Let’s examine the simple notification format first because much of this format is shared with the enhanced format. Figure 5-1 illustrates this format.
Figure 5-1 Simple notification format
The first byte in the simple format is a command value of 0 (zero). The lengths of the device token and the payload must be in network order (that is, big endian). In addition, you should encode the device token in binary format. The payload must not exceed 256 bytes and must not be null-terminated(终止).
Listing 5-1 gives an example of a function that sends a push notification to APNs over the binary interface using the simple notification format. The example assumes prior SSL connection to gateway.push.apple.com (or gateway.sandbox.push.apple.com) and peer-exchange authentication(认证).
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
|
{
|
bool rtn = false;
|
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength)
|
{
|
uint8_t command = 0; /* command number */
|
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint16_t) +
|
DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
|
/* message format is, |COMMAND|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
|
char *binaryMessagePt = binaryMessageBuff;
|
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
|
uint16_t networkOrderPayloadLength = htons(payloadLength);
|
|
/* command */
|
*binaryMessagePt++ = command;
|
|
/* token length network order */
|
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
|
binaryMessagePt += sizeof(uint16_t);
|
|
/* device token */
|
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
|
binaryMessagePt += DEVICE_BINARY_SIZE;
|
|
/* payload length network order */
|
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
|
binaryMessagePt += sizeof(uint16_t);
|
|
/* payload */
|
memcpy(binaryMessagePt, payloadBuff, payloadLength);
|
binaryMessagePt += payloadLength;
|
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
|
rtn = true;
|
}
|
return rtn;
|
} |
Figure 5-2 depicts(描绘) the enhanced format for notification packets. With this format, if APNs encounters(遇到) an unintelligible(不知所云) command, it returns an error response before disconnecting.
The first byte in the enhanced notification format is a command value of 1. The two new fields in this format are for an identifier and an expiry value. (Everything else is the same as the simple notification format.)
If you send a notification and APNs finds the notification malformed(异常) or otherwise unintelligible(不知所云、无法理解的), it returns an error-response packet prior(在×××之前) to disconnecting. (If there is no error, APNs doesn’t return anything.) Figure 5-3 depicts the format of the error-response packet.
The packet has a command value(命令值) of 8 followed by a one-byte status code and the same notification identifier specified by the provider when it composed the notification. Table 5-1 lists the possible status codes and their meanings.
Table 5-1 Codes in error-response packet
Status code |
Description |
0 |
No errors encountered(遇到) |
1 |
Processing error |
2 |
Missing device token |
3 |
Missing topic |
4 |
Missing payload |
5 |
Invalid token size |
6 |
Invalid topic size |
7 |
Invalid payload size |
8 |
Invalid token |
255 |
None (unknown) |
Listing 5-2 modifies the code in Listing 5-1 to compose a push notification in the enhanced format before sending it to APNs. As with the earlier example, it assumes prior SSL connection to gateway.push.apple.com (or gateway.sandbox.push.apple.com) and peer-exchange authentication.
Listing 5-2 Sending a notification in the enhanced format via the binary interface
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
|
{
|
bool rtn = false;
|
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength)
|
{
|
uint8_t command = 1; /* command number */
|
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) +
|
DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
|
/* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
|
char *binaryMessagePt = binaryMessageBuff;
|
uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
|
uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400); // expire message if not delivered in 1 day
|
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
|
uint16_t networkOrderPayloadLength = htons(payloadLength);
|
|
/* command */
|
*binaryMessagePt++ = command;
|
|
/* provider preference ordered ID */
|
memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID, sizeof(uint32_t));
|
binaryMessagePt += sizeof(uint32_t);
|
|
/* expiry date network order */
|
memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
|
binaryMessagePt += sizeof(uint32_t);
|
|
/* token length network order */
|
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
|
binaryMessagePt += sizeof(uint16_t);
|
|
/* device token */
|
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
|
binaryMessagePt += DEVICE_BINARY_SIZE;
|
|
/* payload length network order */
|
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
|
binaryMessagePt += sizeof(uint16_t);
|
|
/* payload */
|
memcpy(binaryMessagePt, payloadBuff, payloadLength);
|
binaryMessagePt += payloadLength;
|
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
|
rtn = true;
|
}
|
return rtn;
|
}
|
Take note that the device token in the production environment and the device token in the development (sandbox) environment are not the same value.
The Feedback Service
If a provider attempts to deliver a push notification to an application, but the application no longer exists on the device, the device reports that fact to Apple Push Notification Service. This situation often happens when the user has uninstalled the application. If a device reports failed-delivery attempts for an application, APNs needs some way to inform the provider so that it can refrain(避免) from sending notifications to that device. Doing this reduces unnecessary message overhead and improves overall system performance.
For this purpose Apple Push Notification Service includes a feedback service that APNs continually updates with a per-application list of devices for which there were failed-delivery attempts. The devices are identified by device tokens encoded in binary format. Providers should periodically query the feedback service to get the list of device tokens for their applications, each of which is identified by its topic. Then, after verifying that the application hasn’t recently been re-registered on the identified devices, a provider should stop sending notifications to these devices.
Access to the feedback service takes place through a binary interface similar to that used for sending push notifications. You access the production feedback service via feedback.push.apple.com, port 2196; you access the sandbox feedback service via feedback.sandbox.push.apple.com, port 2196. As with the binary interface for push notifications, you must use TLS (or SSL) to establish a secured communications channel. The SSL certificate required for these connections is the same one that is provisioned for sending notifications. To establish a trusted provider identity, you should present this certificate to APNs at connection time using peer-to-peer authentication.
Once you are connected, transmission begins immediately; you do not need to send any command to APNs. Begin reading the stream written by the feedback service until there is no more data to read. The received data is in tuples having the following format:
Timestamp |
A timestamp (as a four-byte time_t value) indicating when the APNs determined that the application no longer exists on the device. This value, which is in network order, represents the seconds since 1970, anchored to UTC. You should use the timestamp to determine if the application on the device re-registered with your service since the moment the device token was recorded on the feedback service. If it hasn’t, you should cease(停止) sending push notifications to the device. |
Token length |
The length of the device token as a two-byte integer value in network order. |
Device token |
The device token in binary format. |
Note: APNs monitors providers for their diligence(勤奋) in checking the feedback service and refraining from sending push notifications to nonexistent(不存在 ) applications on devices.