Apple Push Notification Service
Apple Push Notification service (APNs for short) is the centerpiece of the push notifications feature. It is a robust and highly efficient service for propagating information to devices such as iPhone, iPad, and iPod touch devices. Each device establishes an accredited and encrypted IP connection with the service and receives notifications over this persistent connection. If a notification for an application arrives when that application is not running, the device alerts the user that the application has data waiting for it.
Software developers (“providers”) originate the notifications in their server software. The provider connects with APNs through a persistent and secure channel while monitoring incoming data intended for their client applications. When new data for an application arrives, the provider prepares and sends a notification through the channel to APNs, which pushes the notification to the target device.
In addition to being a simple but efficient and high-capacity transport service, APNs includes a default quality-of-service component that provides store-and-forward capabilities. See “Quality of Service” for more information.
“Provider Communication with Apple Push Notification Service” and “Scheduling, Registering, and Handling Notifications” discuss the specific implementation requirements for providers and iOS applications, respectively.
A Push Notification and Its Path
Apple Push Notification service transports and routes a notification from a given provider to a given device. A notification is a short message consisting of two major pieces of data: the device token and the payload. The device token is analogous to a phone number; it contains information that enables APNs to locate the device on which the client application is installed. APNs also uses it to authenticate the routing of a notification. The payload is a JSON-defined property list that specifies how the user of an application on a device is to be alerted.
Note: For more information about the device token, see “Security Architecture”; for further information about the notification payload, see “The Notification Payload” .
The flow of remote-notification data is one-way. The provider composes a notification package that includes the device token for a client application and the payload. The provider sends the notification to APNs which in turn pushes the notification to the device.
When it authenticates itself to APNs, a provider furnishes the service with its topic, which identifies the application for which it’s providing data. The topic is currently the bundle identifier of the target application on an iOS device.
Figure 3-1 A push notification from a provider to a client applicationFigure 3-1 is a greatly simplified depiction of the virtual network APNs makes possible among providers and devices. The device-facing and provider-facing sides of APNs both have multiple points of connection; on the provider-facing side, these are called gateways. There are typically multiple providers, each making one or more persistent and secure connections with APNs through these gateways. And these providers are sending notifications through APNs to many devices on which their client applications are installed. Figure 3-2 is a slightly more realistic depiction.
Figure 3-2 Push notifications from multiple providers to multiple devicesFeedback Service
Sometimes APNs might attempt to deliver notifications for an application on a device, but the device may repeatedly refuse delivery because there is no target application. This often happens when the user has uninstalled the application. In these cases, APNs informs the provider through a feedback service that the provider connects with. The feedback service maintains a list of devices per application for which there were recent, repeated failed attempts to deliver notifications. The provider should obtain this list of devices and stop sending notifications to them. For more on this service, see “The Feedback Service.”
Quality of Service
Apple Push Notification Service includes a default Quality of Service (QoS) component that performs a store-and-forward function. If APNs attempts to deliver a notification but the device is offline, the QoS stores the notification. It retains only one notification per application on a device: the last notification received from a provider for that application. When the offline device later reconnects, the QoS forwards the stored notification to the device. The QoS retains a notification for a limited period before deleting it.
Security Architecture
To enable communication between a provider and a device, Apple Push Notification Service must expose certain entry points to them. But then to ensure security, it must also regulate access to these entry points. For this purpose, APNs requires two different levels of trust for providers, devices, and their communications. These are known as connection trust and token trust.
Connection trust establishes certainty that, on one side, the APNs connection is with an authorized provider with whom Apple has agreed to deliver notifications. At the device side of the connection, APNs must validate that the connection is with a legitimate device.
After APNs has established trust at the entry points, it must then ensure that it conveys notifications to legitimate end points only. To do this, it must validate the routing of messages traveling through the transport; only the device that is the intended target of a notification should receive it.
In APNs, assurance of accurate message routing—or token trust—is made possible through the device token. A device token is an opaque identifier of a device that APNs gives to the device when it first connects with it. The device shares the device token with its provider. Thereafter, this token accompanies each notification from the provider. It is the basis for establishing trust that the routing of a particular notification is legitimate. (In a metaphorical sense, it has the same function as a phone number, identifying the destination of a communication.)
Note: A device token is not the same thing as the device UDID returned by the uniqueIdentifier
property of UIDevice
.
The following sections discuss the requisite components for connection trust and token trust as well as the four procedures for establishing trust.
Service-to-Device Connection Trust
APNs establishes the identity of a connecting device through TLS peer-to-peer authentication. (Note that iOS takes care of this stage of connection trust; you do not need to implement anything yourself.) In the course of this procedure, a device initiates a TLS connection with APNs, which returns its server certificate. The device validates this certificate and then sends its device certificate to APNs, which validates that certificate.
Provider-to-Service Connection Trust
Connection trust between a provider and APNs is also established through TLS peer-to-peer authentication. The procedure is similar to that described in “Service-to-Device Connection Trust.” The provider initiates a TLS connection, gets the server certificate from APNs, and validates that certificate. Then the provider sends its provider certificate to APNs, which validates it on its end. Once this procedure is complete, a secure TLS connection has been established; APNs is now satisfied that the connection has been made by a legitimate provider.
Note that provider connection is valid for delivery to only one specific application, identified by the topic (bundle ID) specified in the certificate. APNs also maintains a certificate revocation list; if a provider’s certificate is on this list, APNs may revoke provider trust (that is, refuse the connection).
Token Generation and Dispersal
An iOS-based application must register to receive push notifications; it typically does this right after it is installed on a device. (This procedure is described in “Scheduling, Registering, and Handling Notifications.”) iOS receives the registration request from an application, connects with APNs, and forwards the request. APNs generates a device token using information contained in the unique device certificate. The device token contains an identifier of the device. It then encrypts the device token with a token key and returns it to the device.
The device returns the device token to the requesting application as an NSData
object. The application then must then deliver the device token to its provider in either binary or hexadecimal format. Figure 3-3 also illustrates the token generation and dispersal sequence, but in addition shows the role of the client application in furnishing its provider with the device token.
The form of this phase of token trust ensures that only APNs generates the token which it will later honor, and it can assure itself that a token handed to it by a device is the same token that it previously provisioned for that particular device—and only for that device.
Token Trust (Notification)
After iOS obtains a device token from APNs, as described in “Token Generation and Dispersal,” it must provide APNs with the token every time it connects with it. APNs decrypts the device token and validates that the token was generated for the connecting device. To validate, APNs ensures that the device identifier contained in the token matches the device identifier in the device certificate.
Every notification that a provider sends to APNs for delivery to a device must be accompanied by the device token it obtained from an application on that device. APNs decrypts the token using the token key, thereby ensuring that the notification is valid. It then uses the device ID contained in the device token to determine the destination device for the notification.
Trust Components
To support the security model for APNs, providers and devices must possess certain certificates, certificate authority (CA) certificates, or tokens.
-
Provider: Each provider requires a unique provider certificate and private cryptographic key for validating their connection with APNs. This certificate, provisioned by Apple, must identify the particular topic published by the provider; the topic is the bundle ID of the client application. For each notification, the provider must furnish APNs with a device token identifying the target device. The provider may optionally wish to validate the service it is connecting to using the public server certificate provided by the APNs server.
-
Device: iOS uses the public server certificate passed to it by APNs to authenticate the service that it has connected to. It has a unique private key and certificate that it uses to authenticate itself to the service and establish the TLS connection. It obtains the device certificate and key during device activation and stores them in the keychain. iOS also holds its particular device token, which it receives during the service connection process. Each registered client application is responsible for delivering this token to its content provider.
APNs servers also have the necessary certificates, CA certificates, and cryptographic keys (private and public) for validating connections and the identities of providers and devices.
The Notification Payload
Each push notification carries with it a payload. The payload specifies how users are to be alerted to the data waiting to be downloaded to the client application. The maximum size allowed for a notification payload is 256 bytes; Apple Push Notification Service refuses any notification that exceeds this limit. Remember that delivery of notifications is “best effort” and is not guaranteed.
For each notification, providers must compose a JSON dictionary object that strictly adheres to RFC 4627. This dictionary must contain another dictionary identified by the key aps
. The aps
dictionary contains one or more properties that specify the following actions:
-
An alert message to display to the user
-
A number to badge the application icon with
-
A sound to play
Note: Although you can combine an alert message, icon badging, and a sound in a single notification, you should consider the human-interface implications with push notifications. For example, a user might find frequent alert messages with accompanying sound more annoying than useful, especially when the data to be downloaded is not critical.
If the target application isn’t running when the notification arrives, the alert message, sound, or badge value is played or shown. If the application is running, iOS delivers it to the application delegate as an NSDictionary
object. The dictionary contains the corresponding Cocoa property-list objects (plus NSNull
).
Providers can specify custom payload values outside the Apple-reserved aps
namespace. Custom values must use the JSON structured and primitive types: dictionary (object), array, string, number, and Boolean. You should not include customer information as custom payload data. Instead, use it for such purposes as setting context (for the user interface) or internal metrics. For example, a custom payload value might be a conversation identifier for use by an instant-message client application or a timestamp identifying when the provider sent the notification. Any action associated with an alert message should not be destructive—for example, deleting data on the device.
Important: Because delivery is not guaranteed, you should not depend on the remote-notifications facility for delivering critical data to an application via the payload. And never include sensitive data in the payload. You should use it only to notify the user that new data is available.
Table 3-1 lists the keys and expected values of the aps
payload.
Key | Value type | Comment |
---|---|---|
| string or dictionary | If this property is included, iOS displays a standard alert. You may specify a string as the value of Alternatively, you can specify a dictionary as the value of |
| number | The number to display as the badge of the application icon. If this property is absent, the badge is not changed. To remove the badge, set the value of this property to |
| string | The name of a sound file in the application bundle. The sound in this file is played as an alert. If the sound file doesn’t exist or |
Key | Value type | Comment |
---|---|---|
| string | The text of the alert message. |
| string or | If a string is specified, displays an alert with two buttons, whose behavior is described in Table 3-1. However, iOS uses the string as a key to get a localized string in the current localization to use for the right button’s title instead of “View”. If the value is |
| string | A key to an alert-message string in a |
| array of strings | Variable string values to appear in place of the format specifiers in |
| string | The filename of an image file in the application bundle; it may include the extension or omit it. The image is used as the launch image when users tap the action button or move the action slider. If this property is not specified, the system either uses the previous snapshot,uses the image identified by the This property was added in iOS 4.0. |
Note: If you want the iPhone, iPad, or iPod touch device to display the message text as-is in an alert that has both the Close and View buttons, then specify a string as the direct value of alert. Don’t specify a dictionary as the value of alert
if the dictionary only has the body
property.
Localized Formatted Strings
You can display localized alert messages in two ways. The server originating the notification can localize the text; to do this, it must discover the current language preference selected for the device (see “Passing the Provider the Current Language Preference (Remote Notifications)”). Or the client application can store in its bundle the alert-message strings translated for each localization it supports. The provider specifies the loc-key
and loc-args
properties in the aps
dictionary of the notification payload. When the device receives the notification (assuming the application isn’t running), it uses these aps
-dictionary properties to find and format the string localized for the current language, which it then displays to the user.
Here’s how that second option works in a little more detail.
An iOS application can internationalize resources such as images, sounds, and text for each language that it supports, Internationalization collects the resources and puts them in a subdirectory of the bundle with a two-part name: a language code and an extension of .lproj
(for example, fr.lproj
). Localized strings that are programmatically displayed are put in a file called Localizable.strings
. Each entry in this file has a key and a localized string value; the string can have format specifiers for the substitution of variable values. When an application asks for a particular resource—say a localized string—it gets the resource that is localized for the language currently selected by the user. For example, if the preferred language is French, the corresponding string value for an alert message would be fetched from Localizable.strings
in the fr.lproj
directory in the application bundle. (iOS makes this request through the NSLocalizedString
macro.)
Note: This general pattern is also followed when the value of the action-loc-key
property is a string. This string is a key into the Localizable.strings
in the localization directory for the currently selected language. iOS uses this key to get the title of the button on the right side of an alert message (the “action” button).
To make this clearer, let’s consider an example. The provider specifies the following dictionary as the value of the alert property:
"alert" : { "loc-key" : "GAME_PLAY_REQUEST_FORMAT", "loc-args" : [ "Jenna", "Frank"] }, |
When the device receives the notification, it uses "GAME_PLAY_REQUEST_FORMAT"
as a key to look up the associated string value in the Localizable.strings
file in the .lproj
directory for the current language. Assuming the current localization has an Localizable.strings
entry such as this:
"GAME_PLAY_REQUEST_FORMAT" = "%@ and %@ have invited you to play Monopoly"; |
the device displays an alert with the message “Jenna and Frank have invited you to play Monopoly”.
In addition to the format specifier %@
, you can %
n$@
format specifiers for positional substitution of string variables. The n is the index (starting with 1) of the array value in loc-args
to substitute. (There’s also the %%
specifier for expressing a percentage sign (%).) So if the entry in Localizable.strings
is this:
"GAME_PLAY_REQUEST_FORMAT" = "%2$@ and %1$@ have invited you to play Monopoly"; |
the device displays an alert with the message "Frank and Jenna have invited you to play Monopoly".
For a full example of a notification payload that uses the loc-key
and loc-arg
properties, see the last example of “Examples of JSON Payloads.” To learn more about internationalization in iOS, see ““Advanced App Tricks”” in iOS App Programming Guide; for general information about internationalization, see Internationalization Programming Topics. String formatting is discussed in “Formatting String Objects” in String Programming Guide.
Note: You should use the loc-key
and loc-args
properties—and the alert
dictionary in general—only if you absolutely need to. The values of these properties, especially if they are long strings, might use up more bandwidth than is good for performance. Many if not most applications may not need these properties because their message strings are originated by users and thus are implicitly "localized."
Examples of JSON Payloads
The following examples of the payload portion of notifications illustrate the practical use of the properties listed in Table 3-1. Properties with “acme” in the key name are examples of custom payload data. The examples include whitespace and newline characters for readability; for better performance, providers should omit whitespace and newline characters.
Example 1: The following payload has an aps
dictionary with a simple, recommended form for alert messages with the default alert buttons (Close and View). It uses a string as the value of alert
rather than a dictionary. This payload also has a custom array property.
{ |
"aps" : { "alert" : "Message received from Bob" }, |
"acme2" : [ "bang", "whiz" ] |
} |
Example 2. The payload in the example uses an aps
dictionary to request that the device display an alert message with an Close button on the left and a localized title for the "action" button on the right side of the alert. In this case, “PLAY” is used as a key into the Localizable.strings
file for the currently selected language to get the localized equivalent of “Play”. The aps
dictionary also requests that the application icon be badged with 5.
{ "aps" : { "alert" : { "body" : "Bob wants to play poker", "action-loc-key" : "PLAY" }, "badge" : 5, }, "acme1" : "bar", "acme2" : [ "bang", "whiz" ] } |
Example 3. The payload in this example specifies that device should display an alert message with both Close and View buttons. It also request that the application icon be badged with 9 and that a bundled alert sound be played when the notification is delivered.
{ |
"aps" : { |
"alert" : "You got your emails.", |
"badge" : 9, |
"sound" : "bingbong.aiff" |
}, |
"acme1" : "bar", |
"acme2" : 42 |
} |
Example 4. The interesting thing about the payload in this example is that it uses the loc-key
and loc-args
child properties of the alert
dictionary to fetch a formatted localized string from the application’s bundle and substitute the variable string values (loc-args
) in the appropriate places. It also specifies a custom sound and include a custom property.
{ |
"aps" : { |
"alert" : { "loc-key" : "GAME_PLAY_REQUEST_FORMAT", "loc-args" : [ "Jenna", "Frank"] }, |
"sound" : "chime" |
}, |
"acme" : "foo" |
} |
Example 5. The following example shows an empty aps
dictionary; because the badge
property is missing, any current badge number shown on the application icon is removed. The acme2
custom property is an array of two integers.
{ |
"aps" : { |
}, |
"acme2" : [ 5, 8 ] |
} |
Remember, for better performance, you should strip all whitespace and newline characters from the payload before including it in the notification