Push Notifications: Close but no cigar

Apple does not allow apps on the iPhone to run in the background. They do this for a multitude of reasons, among them: power consumption and battery life, which in their own words “compromises the iPhone experience.” This unfortunately harpoons an entire class of applications, most prominently instant messaging applications that depend on an active network connection to keep users logged in and able to receive messages instantly.

In order to satisfy this obvious need, Apple, likely with a little help from bug reports, came up with the concept of the Push Notifications Service. Push Notifications allow Apps to report interesting information to the user when that app is not running. It does this by requiring the app author to run a server that can maintain state on behalf of the complimentary iPhone app and send messages through the APNS cloud to the user’s phone. Again, I point out that this is while the app isn’t running and has no participation in these messages. So well suited this seems to the problem of IM that Apple’s first demonstration of Push Notifications was that of an IM client.

Push Notifications are limited to 256 bytes of a JSON encoded string payload. In this 256 bytes you’re expected to fit your message, and all the options you’d like for your alert including sound and message. With english strings this may not be too bad as you can reword until you find the right phrasing and characters usually have a 1-1 mapping of number of bytes to characters used. The problem starts here when you change to asian languages like Japanese and Chinese in which a character may be represented by up to 4 bytes in UTF-8 encoding, add to this the amount of escaping that is then needed and you go from a somewhat reasonable amount to not enough to get the point across. Add to this the fact that JSON also has its own escapes for certain characters, among them “/” so a URL for example might cost you more of the payload than you expected.

Back in the Eighth grade my english teacher introduced me to a phrase that I’ve found incredibly useful in all things design related, “Close but no cigar.” It refers to a situation in which an effort is made but it falls short of the desired outcome due to among many possible reasons a lack of the finer details. The best example on the iPhone that we have to the ideal of Push Notifications is the Messages app that provides the user with SMS and for some MMS functionalities. Comparing the way the two work readily reveals the shortcomings of Push Notifications as the stopgap solution to this problem.

Push Notifications have zero interaction with the application on your device outside of expecting sounds and localized versions of alert strings in it, however when your application is launched as a result of the user acting on the push notification that he or she was sent your application is given that push notification directly to inspect. Apple’s recommendation is to use that 256 bytes and whatever you have left after adding the message, sound, and localized strings to encode meaningful app information for the application to determine what to do with this notification. Going back to the case of IM, that means that if someone sent a really long message you have to truncate that message in order to fit the tracking information in the payload that tells the App who the IM was from and that it was incomplete. Contrast this to SMS which is running in the background and when you receive an SMS there is zero wait to receive your messages since they’re already there waiting for you.

SMS Messages have stacking behavior that sometimes gets invoked, most annoyingly during a phone call. If you have multiple SMSs they all queue up alerts to displays to you one by one during a phone call. This may be the single most annoying feature of the iPhone, but it’s actually useful that it’s a handled case since in the case of the locked screen this translates to a summary notification like “3 Karl Adam” or in the case where the messages are from different people and you have several pending notifications: “3 Texts.” Push Notifications don’t have any of this behavior. Firstly they don’t stack, so if in the case of IM someone has sent you multiple messages, you’ll only see the last one with no indication that there is more than one. Push Notifications from several apps are also treated the same so if it’s only 1 IM, a new update from the NYT might be the last push notification received on the device. Push Notifications don’t control their behavior outside of the app so it’s up to Apple to fix this. A more Growl-like model might be appropriate in which there’s a registration process or at least a local entry in the applications Info.plist that gives a general description of the types of messages expected so you could at least see “3 Instant Messages” on the locked summary screen.

Now that you’re popular and received these several messages you go ahead and swipe or launch the SMS app and all your messages are waiting for you. Herein lies the key distinction that iPhone apps using Push Notifications have to deal with compared to Messages.app which runs in the background. Once an application has launched in response to push notifications it needs to connect to the network and sync with the server side status which depending on your network conditions may not be a short period of time such that you’re left waiting for what your friends have sent you. Considering that you may not know how many messages they sent it’s less than optimal to launch an application assuming the last message is the only one and forming a response for it. This could be easily solved by a small db for push notifications since the last launch of the app, mated with a larger push notification size to include the tracking information that allows the app to have the necessary state information since the last time it was launched. Then the app can quickly dirty sync its state until a full sync can be achieved but the user is not left waiting. In the case of IM this means at app launch the messages you saw in your push notifications are already waiting for you.

If you receive a push notification and read the alert then hit the close button, this is enough to indicate to the Messages app that you have read the message it wanted to inform you about so the unread messages badge is then decremented by that 1 message. Push Notifications again lack this behavior, the application gets zero notification that the left button was tapped, and while the right button can be localized to more accurately reflect the action that will be taken upon hitting this button, the left button is not available for localization or customization and will always read “Close”, or its equivalent in your language of course. So if you did fit the entire message in an alert the user would not be able to dismiss their unread badge and eventually will forget that they read the message when they go venturing into the app to find what they missed. Again with a small db of notifications you’d be able to locally determine this sort of status, since again Apple would have to provide this behavior.

Finally, the Messages app will re-notify you of messages that you’ve yet to acknowledge. You can acknowledge a Messages.app alert by viewing the message and hitting the close button, view button, or physical sleep button at the top of the device. In the case of the Messages app you can control this feature by turning it off in your preferences. In the case of push notifications this doesn’t apply, you don’t get this behavior at all.

For those interested:
rdar://7166298 – Push Notifications size should be limited to 256B as the alert, not the pay load
rdar://7114805 – Push Notifications lack a summary behavior
rdar://7114789 – Push Notifications should offer a db of the notifications since last launch
rdar://7114757 – Left Button on Push Notifications isn’t Localizable