Documentation Archive

Developer

Local and Remote Notification Programming Guide

On This Page

Legacy Notification Format

New development should use the modern format to connect to APNs, as described in Communicating with APNs.

These formats do not include a priority; a priority of 10 is assumed.

Legacy Notification Format

Figure B-1 shows this format.

Figure B-1Legacy notification format image: ../Art/aps_provider_binary.jpg

The first byte in the legacy format is a command value of 0 (zero). The other fields are the same as the enhanced format. Listing B-1 gives an example of a function that sends a remote notification to APNs over the binary interface using the legacy notification format. The example assumes prior SSL connection to gateway.push.apple.com (or gateway.sandbox.push.apple.com) and peer-exchange authentication.

Listing B-1Sending a notification in the legacy format via the binary interface
  1. static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
  2. {
  3. bool rtn = false;
  4. if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength)
  5. {
  6. uint8_t command = 0; /* command number */
  7. char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint16_t) +
  8. DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
  9. /* message format is, |COMMAND|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
  10. char *binaryMessagePt = binaryMessageBuff;
  11. uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
  12. uint16_t networkOrderPayloadLength = htons(payloadLength);
  13. /* command */
  14. *binaryMessagePt++ = command;
  15. /* token length network order */
  16. memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
  17. binaryMessagePt += sizeof(uint16_t);
  18. /* device token */
  19. memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
  20. binaryMessagePt += DEVICE_BINARY_SIZE;
  21. /* payload length network order */
  22. memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
  23. binaryMessagePt += sizeof(uint16_t);
  24. /* payload */
  25. memcpy(binaryMessagePt, payloadBuff, payloadLength);
  26. binaryMessagePt += payloadLength;
  27. if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
  28. rtn = true;
  29. }
  30. return rtn;
  31. }

Enhanced Notification Format

The enhanced format has several improvements over the legacy format:

  • Error response. With the legacy 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.

  • Notification expiration. APNs has a store-and-forward feature that keeps the most recent notification sent to an app on a device. If the device is offline at time of delivery, APNs delivers the notification when the device next comes online. With the legacy 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.

Figure B-2 depicts the format for notification packets.

Figure B-2Enhanced notification format image: ../Art/aps_binary_provider_2.jpg

The first byte in the notification format is a command value of 1. The remaining fields are as follows:

  • 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 uses network byte order (big endian). If the expiry value is non-zero, APNs tries to deliver the notification at least once. Specify zero to request that APNs not store the notification at all.

  • Token length—The length of the device token in network order (that is, big endian)

  • Device token—The device token in binary form.

  • Payload length—The length of the payload in network order (that is, big endian). The payload must not exceed 256 bytes and must not be null-terminated.

  • Payload—The notification payload.

Listing B-2 composes a remote notification in the enhanced format before sending it to APNs. It assumes prior SSL connection to gateway.push.apple.com (or gateway.sandbox.push.apple.com) and peer-exchange authentication.

Listing B-2Sending a notification in the enhanced format via the binary interface
  1. static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
  2. {
  3. bool rtn = false;
  4. if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength)
  5. {
  6. uint8_t command = 1; /* command number */
  7. char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) +
  8. DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
  9. /* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
  10. char *binaryMessagePt = binaryMessageBuff;
  11. uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
  12. uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400); // expire message if not delivered in 1 day
  13. uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
  14. uint16_t networkOrderPayloadLength = htons(payloadLength);
  15. /* command */
  16. *binaryMessagePt++ = command;
  17. /* provider preference ordered ID */
  18. memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID, sizeof(uint32_t));
  19. binaryMessagePt += sizeof(uint32_t);
  20. /* expiry date network order */
  21. memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
  22. binaryMessagePt += sizeof(uint32_t);
  23. /* token length network order */
  24. memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
  25. binaryMessagePt += sizeof(uint16_t);
  26. /* device token */
  27. memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
  28. binaryMessagePt += DEVICE_BINARY_SIZE;
  29. /* payload length network order */
  30. memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
  31. binaryMessagePt += sizeof(uint16_t);
  32. /* payload */
  33. memcpy(binaryMessagePt, payloadBuff, payloadLength);
  34. binaryMessagePt += payloadLength;
  35. if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
  36. rtn = true;
  37. }
  38. return rtn;
  39. }