5-Local Notifications and Push Notifications--Provider Communication with Apple Push Notification Service
Posted on 2012-04-28 19:38 星尘的天空 阅读(300) 评论(0) 编辑 收藏 举报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:
- You must compose(组建、构建) the notification payload (see “The Notification Payload”).
- You are responsible for supplying the badge number to be displayed on the application icon.
- You should regularly connect with the feedback web server and fetch the current list of those devices that have repeatedly reported failed-delivery attempts. Then you should cease(停止,停息) sending notifications to the devices associated with those applications. See “The Feedback Service” for more information.
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:
- Notification expiry(期满). APNs has a store-and-forward feature that keeps the most recent notification sent to an application on a device. If the device is offline at time of delivery, APNs delivers the notification when the device next comes online. With the simple format, the notification is delivered regardless of the pertinence(有针对性的) of the notification. In other words, the notification can become “stale”(过时) over time. The enhanced format includes an expiry value that indicates the period of validity for a notification. APNs discards(丢弃) a notification in store-and-forward when this period expires.
- Error response. With the simple format, if you send a notification packet that is malformed(异常) in some way—for example, the payload exceeds the stipulated limit—APNs responds by severing the connection. It gives no indication why it rejected the notification. The enhanced format lets a provider tag a notification with an arbitrary(随意、随即) identifier(识别码). If there is an error, APNs returns a packet that associates an error code with the identifier. This response enables the provider to locate and correct the malformed notification.
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.)
- Identifier—An arbitrary(随意、随即) value that identifies this notification. This same identifier is returned in a error-response packet if APNs cannot interpret(解析、解释) a notification.
- Expiry—A fixed UNIX epoch date expressed in seconds (UTC) that identifies when the notification is no longer valid and can be discarded. The expiry value should be in network order (big endian). If the expiry value is positive, APNs tries to deliver the notification at least once. You can specify zero or a value less than zero to request that APNs not store the notification at all.
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.