Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-517
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 517
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 517] Using Local...

WWDC11 • Session 517

Using Local And Push Notifications on iOS and Mac OS X

Internet & Web • iOS, OS X • 41:46

Local and push notifications let background or inactive apps notify users that an event of interest has occurred, or that an app has new information for them. See how to use notifications to display a message, play a distinctive sound, or update a badge on your app icon. Understand how to register for push notifications, learn how to schedule local notifications, and discover the best practices for handling both.

Speakers: Darryl Bleau, James Callender, Darrin Jewell, Jason Thorpe

Unlisted on Apple Developer site

Downloads from Apple

HD Video (236 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hello, everybody. Thanks for coming. Welcome to session 517, Using Local and Push Notifications on iOS and Mac OS X. My name is Darryl Bleau. I am the engineering manager for the Apple Push Notification Service. And I'm here to talk to you today about notifications. So here's some of the topics we'll be covering. First, we'll be giving an introduction to notifications in general.

Then we'll be walking through the push architecture, some of the protocols, and generally how the service works. We'll then be talking to you about local and push notifications on iOS, followed by a talk on notifications for Mac OS X. After that, we'll follow through with some best practices for using notifications in general.

So, an introduction to notifications. First of all, what is a notification? Generally, a notification is user visible information that reflects some event, such as a service center letting you know that your vehicle is ready for pickup. Why should I use notifications? One good reason to use notifications is to ensure time-sensitive delivery even when your app is not running. For example, I have a stock alert.

How does using the push service compare to, say, having your app poll? Well, push notifications are driven by your server and are immediate, if possible, whereas polls are driven by your app and are potentially latent. In the example app shown here, if we have a doorbell application that lets you know someone's at your door, you'd want to know that immediately, and not five or ten minutes later.

Okay, so an overview of notifications, specifically with push. Notifications are sent directly to a target device. They are intended as a tap on the shoulder. And by that we mean they should reflect some server-side state. Also, push notifications feature a store and forward mechanism. Which means that notifications which are sent to devices that are not currently connected are stored and delivered when the device reconnects.

When a device reconnects, it will receive the latest notification per application. Notifications can also be sent with an expiry time. However, it is important to note that the expiry only affects storage. Notifications which are sent to devices that are online at the time are delivered regardless of any set expiry time.

Let's take a look at the push notification service architecture. The first component of the push notification service is a device of some type, followed by your server and the service in the middle. Each device has an identifying token. Your application will deliver that token to your server. And when your server has a payload ready to send, you'll combine those two together in a notification and send that to the service. The push notification service will then deliver to the device.

Let's take a closer look at that protocol between the push notification service and your server. The protocol used is a binary protocol, and there are two different protocols that you can use for sending a notification. The first protocol involves the device token, the JSON payload, and the command of zero. We also prefix the token length and payload length. This makes up the entirety of the first binary protocol.

The second protocol that you can use is composed of much of the same, except that we command as 1, and we also insert. An identifier and a set expiry time. Using the set second protocol is how you can set an expiry time for your message. Remember that again the expiry affects the storage. If the device is online at the time, notification will be sent regardless of any set expiry.

All right, so what makes up a message payload? Message payloads are strict RFC 4627 JSON. An example is as depicted here. JSON is human readable, it's relatively compact, and is easily mapped to an NSDictionary. When constructing your payloads, though, it's important to remember that there is a 256-byte maximum. Also note that you can make use of keys outside of the APS key for your own use.

So some sizing considerations. If we have JSON as depicted here, with new lines and spaces, much as you would type it out to be human readable, this particular set of JSON would be 150 bytes. However, if we strip all that white space, we can get the same notification down to 96 bytes. This is generally a good idea.

All right, so we've spoken a little bit about the server-side aspects of push notifications. We're now going to take a closer look at the client side aspects, and for that, I'm going to invite up onto stage my colleague, James Callender. My name is James Callender. I'm an iOS engineer.

I want to talk to you today a little bit about the push and local notification API for iOS. So I'm going to start with push notifications, specifically how to register to receive push notifications, how to construct a payload, and how iOS acts on your behalf so your application doesn't have to be running.

But first, why would you want to use push notifications? Well, some examples would be for social networking. Push is a great way to update your friends about your current status or remind them of upcoming events. Second is for current events like sports scores and news. Push is a great way of sending information to users about events as they occur. Finally, I've seen some great examples of push being used in games to alert players when it's their turn to take a move. Now you notice this is sort of the new banner style notification. I'll be presenting with both banner and the old alert style notification.

So when would you not want to use push notifications? You don't want to use push to deliver any kind of critical application information. What do I mean by that? Imagine that you're writing an app that delivers some sort of content to a user, sort of like an email.

You don't want to rely on push to be your primary communication channel to your application. There's a number of reasons for this. Primarily, push may not be available. The user may be moving in and out of service areas, or they could have disabled push altogether for your app. They also may ignore the notification and launch your app at some later point, and you'll never actually receive the push payload. Because of this, it's always a better idea to pull data from your server while your application is running.

So say that you have decided you want to use push notifications in your app. How do you get started doing that? The first thing to do is to register using the UI application API. A good time to do this is that the application did finish launching with options delegate callback. You'll want to call the register for remote notification types on the UI application object and pass in the type of notifications you wish to receive. In this case, we're passing in sound types and badge types.

So once you've registered with iOS to receive push notifications, one of two things will happen depending on your app's current state. First -- oh, sorry. One of two things will happen when you register depending on various things. So first, if you successfully register, you'll get the delegate callback, application did register for remote notifications with device token. You'll get an NSData object, which you'll want to pass up to your server and associate that token with the user's device and possibly an account.

Alternatively, if you fail to register, you'll get the application did fail to register for remote notifications with error. At this point, you might want to check your provisioning profile and make sure you have the correct entitlements. Also note that push is not supported in the simulator, but your application should be able to handle this case gracefully in the event that you're testing in the simulator.

So I want to talk just a little bit about the device token. The device token is for uniquely identifying a particular device. However, this is separate from the UDID of that particular device. The main difference is that the device token can actually change. Because of this, it's always a good idea to call the registration API on every single launch. You don't want to depend on a cached copy of the device token, either on the device or on the server.

So now we're ready to begin constructing our push notification. As Darryl said, a push notification is composed of a JSON object, the heart of which is the APS dictionary. Here you'll be able to specify the appearance of the notification by indicating an alert, a badge, and a sound, as well as you'll be able to use the rest of the payload for any kind of application-specific information.

So the first style of notification is a badge. To set a badge in your application, you want to use the badge key and indicate a positive integer. Because badges are meant to reflect the current state of your application, simply omitting the badge key will clear the badge. The next one is the sound.

To have a custom sound for your notification, all you need to do is specify a name of a sound file in your application bundle. Alternatively, if you want to use the default sound for notifications, you can use the string default. Note that vibration of the device is handled automatically by the user's settings. Now, the simplest form of an alert is just a basic string.

However, you can customize an alert using the dictionary form, which will let you use the localizable.strings file to localize the alert into the user's set language. You want to use the-- for the low key arg, you want to use the key and the key value pair in the localizable dot strings.

And you can also specify a custom localized action for the notification. Now, this notification is the old style modal, which is still supported in iOS 5 based on user settings. But if your notification appears as a banner, the action button will appear when you swipe while at the lock screen.

So you've dispatched your notification from your server, and you're ready to receive it on the device. And one of two things will happen depending on the state of your app. If your app's running, you'll get the application did receive remote notification callback with the user info dictionary that reflects the contents of the JSON object. However, if your application is not running, but the user taps on the notification, you'll get the application did finish launching with options delegate callback, at which point you can extract the notification from the launch options dictionary.

So that's about it for push notifications. The next thing I want to talk about is local notifications. I want to talk about how they're similar, how to construct a local notification, and again, how iOS acts on your behalf. So how are local notifications and push notifications similar? Well, for one, they appear the same to the user. They can have the same combination of badges, alerts, and sounds. The other similarity is that in both cases, iOS acts on your behalf, so your application doesn't need to be running for the user to get a notification.

So how are they different? Well, push notifications originate from a server. So the device needs to have a network connection to actually get the notification. Local notifications originate from the app. They're scheduled and dispatched entirely on the device without the need for a network connection. Also, push notifications are single shot. You send them once with the server, and if possible, will deliver that one notification immediately to your device. On the other hand, local notifications can be scheduled for some point in the future and optionally marked as repeating.

So, when would you want to use local notifications? One example is an alarm clock for some kind of alert that you want to have happen at the same time every day, or a reminder for some kind of upcoming event like a vacation. Also, for users of our multitasking and location-aware APIs, push notifications are a great way of alerting the user about some kind of location-based event, like a nearby friend, and give them the option of bringing your app to the foreground.

When don't you want to use local notifications? For any kind of general alert and error that you want to show to your users while your application is running, it's better to use a more general use API like UILertView. Also, for calendar-based events, consider using the Event Kit API. This will let you schedule an event in the user's calendar and optionally attach some sort of alert to that event.

So if you've decided to use local notifications, you can begin constructing the notification. To do that, we want to use the UI local notification object. This includes properties for setting a badge, an alert, and a sound. As well as those properties for scheduling, optionally marking it as repeating, And again, we have a user info dictionary to attach any kind of meta information you want to use for your app. I'll start by talking about badges, alerts, and sounds.

To set a badge, use the application icon badge number property on your UI local notification object and set it to a positive integer. Note, however, that in this case, setting this value to zero will not actually clear the badge. Instead, you'll want to use the UI application property application icon badge number while your application is running.

The next is alerts. Again, the basic form of an alert is just a string. You can use the alert body and assign it to a basic NSString. Optionally, you can set the alert action property and mark it as having a custom action by setting the has action property to true. And again, you can localize your alerts. Use the same kind of mechanism. Use the key part of the key value pair in the localizable.strings file. This will allow iOS to localize your application at the time that the notification is actually displayed to the user.

So the other thing that you can do with a local notification is actually set a custom launch image for your app. You might know that iOS lets you set an image to be displayed to the user while your application is launching. So you can set the alert launch image property to change this.

So in this case, This app, the default launch image is just a blank image that will eventually want to populate with some kind of menu system. However, by setting the alert launch image, when the user taps the action button, It'll display a custom image that might better reflect the location in your app that the notification is bringing you. In this case, we're saying that we're ready to watch a baseball game, and the launch image is a baseball triangle.

So the last property you can set for the appearance of the notification is the sound. To set this, you use the sound name property. Again, just as with push, you can use the default sound name by setting the sound name property to the UI local notification default sound name.

So now that we've covered how to customize the look and feel of your notification, we'll talk about how to schedule it and mark it as repeating. But first, I want to talk about different kinds of dates. Specifically, I want to talk about this notion of universal time versus wall time.

Universal time is the idea that events occur at the same instant no matter where you are in the world. This is essentially just a single NSDate object. This is good for things like a conference call where some of the participants are in different time zones, or the time at which a stock market closes.

The other kind of time is wall time. This is basically time that occurs at different relative points depending on where you are in the world. So essentially you're combining an NSDate object with an NSTimeZone object. Examples of this is an alarm clock that goes off at 9:00 a.m. or the time at which a network broadcasts a television show.

So once you've decided that your notification is more of a universal time or wall time notification, you're ready to actually schedule it. To do this, use the fire date and time zone properties. Note here that we've specified a number of seconds relative to the current time. This might be okay if what we want is some sort of countdown timer.

But if our intention was to display the notification, say, at the same hour as this time tomorrow, that might not work if tomorrow, for instance, is the beginning or end of daylight savings time. Your notification will be delivered either an hour early or an hour late. To get around this, we can use the NSDateComponents object and set a custom day, month, year, and hour, and have it do the work of calculating the appropriate NSDate object.

So the last thing you can do is schedule a notification as repeating at some sort of regular interval. To do this, use the repeat interval and repeat calendar properties. In this example, we're using the NSDay calendar unit to have it repeat once a day. Alternatively, we could use another unit, like NSWeek calendar unit, and have it repeat once a week.

Note that I'm keeping the repeat calendar at whatever default calendar is set, but you want to make note of this, because not all users actually use the Gregorian calendar, and your repeat interval might be different depending on the type of calendar that's currently set. So you just want to take care and make sure that you're taking that into consideration.

So the last part of a local notification is the user info dictionary. This is a great place to put any kind of meta information for your local notification, like maybe an identifier for that notification, or instructions to your app on where to bring you once you've been launched.

So now that you've constructed your notification, you're ready to schedule it with iOS. To do this, we have a couple of methods. You'll want to use the UI application methods, schedule local notification, to schedule a notification you just created. Or if you want to cancel a notification that you've already scheduled, you can use the cancel local notification method. Also, for background apps, we have the present local notification now, which ignores the fire date property and displays the notification immediately to the user and gives them the option of bringing your application to the foreground.

So again, the notification has been dispatched, and we're ready to receive it. Just as with push, if your application is running, you'll get the application did receive local notification. The important thing to remember is that in this case, iOS will not actually perform any of the badging, sounds, or alerts. You'll want to take the appropriate action that's specific for your app once you get the notification.

And if your application is not running, you'll get the application did finish launching with options callback. And again, you can extract the notification from the launch options dictionary. That's actually all there is to push and local notifications on iOS. Next, I'd like to call up my colleague, Jason, to talk about push notifications on Mac OS X.

All right, good afternoon, everybody. My name is Jason Thorpe. I'm an engineering manager for Mac OS X. And I'm going to tell you all about how to implement push notifications for your applications on the Mac. So the first thing to be aware of is the push notification support we've added to the Mac and Lion is very similar to the push notification support you're probably all familiar with in iOS. So the AppKit API is as identical to the UIKit API as is possible. And the notifications are delivered to applications that are running via the NSApplicationDelegate object.

And then finally, if your application is not running, your icons will be badged in the dock and in Launchpad. But there are a few differences. So first of all, the Mac only supports badges, not alerts or sounds. And because of that, there's no alerts, your application can't be launched in response to a push notification.

Since we are only supporting badges, which are potentially a lot less annoying than having your phone beep at you and whatnot, there's no system-wide preferences for push notifications on the Mac. And we don't have the iOS style local notifications API. Local notifications on the Mac are done with a different API.

So there is some server-side impact. So because your application -- so if you have an application for which you have an iOS and a Mac version, they're going to have different application identifiers, different bundle IDs. And because of this, you're going to have two different push provider certificates. So when you register your device token with your server, you're going to need to identify what kind of client you're coming from.

And the best or the easiest way to do this is probably just to send either your application identifier or your bundle identifier up to the server when you register your token. But that's really about it. Even though we don't support the alert and sound notification types, you can construct your payload once and send it to all the devices that are registered, and the Mac will simply ignore the alert and sound.

So some developer considerations that are new to the Mac. So the push notifications require your application to be correctly entitled. And to do that, you're going to need a provisioning profile from the Apple Developer Certificate Utility. If you're already developing applications for iOS, this should be familiar to you.

And that provisioning profile will need to be associated with your Xcode project and then installed on any Macs that are going to run the development version of the application. And then next, only applications that are distributed through the Mac App Store can use the Apple Push Notification service.

Okay, so let's get into the API details. So as on iOS, the best time to register your token is when you get the application did finish launching NS application delegate callback. You'll call the register for remote notification types method in NS application and then register in this case for badges.

So when you register for notification, just like on iOS, you'll get one of two different callbacks. The first one would be, did register for remote notifications with device token? And this is when you'll send your device token to the APNS -- sorry, to your server. And again, make sure to distinguish between the iOS and the Mac version of your application. And then when you fail to register, you would get, did fail to register for notifications with error. And in this case, you'll want to check your provisioning profile to ensure your app is correctly entitled.

So getting the payload is pretty straightforward. You'll get the did receive remote notification callback on your application delegate. And again, I just want to point out that you may get alert and sound keys within the APS dictionary, but probably the best practice is for your application to simply ignore those, since Doc won't display them on your behalf. And that's it. That's really the only differences for push notifications for the Mac as compared to iOS. And to show you how this all works, I'd like to invite Darrin Jewell up here to give you a quick demo.

Darrin? Hi there. My name is Darrin, and I'm going to bring you through an Xcode demo of how to add push notifications to an application. So let me switch over to our Demo. Okay, so I'd like to introduce Cumulus. Cumulus is a simple file sharing application for those of you who can't use AirDrop yet.

And Cumulus is great. Your friends can send you files, and you can see and browse the files that your friends have sent you and share them that way. Unfortunately, it has one significant problem, and that's that you have to hit the refresh button to see what files are waiting for you. So you're sitting here pushing the refresh button all day.

We're going to show you how you can add push, which we recently added to the Mac, to this application. It's pretty easy. And we'll walk you through the code. We'll show you some pitfalls you might find along the way. And we'll bring that up in Xcode. So let me clear out the file here. We'll exit our little program. And we'll bring up the application delegate class in Xcode.

So this is the NSApplicationDelegate class for Cumulus, and we're going to show you you need to add one new function call to your application, and we're going to implement three methods that Jason just covered that you need to handle push events as they arrive in your application. So the first one we're going to show you is the application did finish launching method in your delegate. Your delegate probably already has this. In this case, we just create and open the first window on the screen.

So the call that we're going to add to this delegate is the NSApplicationRegisterForRemoteNot ificationTypes call. And we're going to give it the NSRemoteNotificationTypeBadge constant to indicate that when we're not running, we would like to be badged in the dock. So we'll just uncomment the call that I've already put in here now. OK.

So the next function, okay, now we're going to cover the three methods that you'll want to implement new to your application to handle push events in your application. First one, application did register for remote notifications with device token. This method will be called when your application successfully registers for push.

You'll be handed an NSData object with a device token. That device token represents the unique instance of your application running on this Mac. You'll want to send that to your server, in this case the Cumulus server. We send it up there with the MyWindowControllerSendProvider device token. We'll let the window controller handle sending it upstream to the Cumulus server. And we also log it here so we can see what's going on.

Okay, so now that's when your application successfully registered for push, but when your application does not successfully register for push, The application will call the application did fail to register for remote notifications with error call. This indicates something went wrong registering for push. Most likely, if you're under development and you get this call, you want to check that your application is properly entitled, because if you're not entitled, this will be called with an error.

And we'll show you how to add entitlements to your application in a minute, and what happens when they don't. And finally, in order to actually handle incoming pushes, you'll want to implement application did receive remote notification, and you'll be handed a dictionary, an NSDictionary, which corresponds to the JSON payload that was sent by your server through the Apple Push service.

We log it here so you can see it. And in this case, we just take the same action as if the user had hit the refresh button every time we get a push. So let me show you now what happens when you actually run the app. So now we'll compile, launch our application here. We'll bring up the window full screen.

So now you'll see that because we weren't entitled, we didn't compile with a provisioning profile yet, the application did fail to register for remote notifications with error method. It's a mouthful, but it gets called indicating that your application was not entitled. So we need to take the provisioning profile here, which you downloaded from the Mac Developer Certificate Utility, as Jason discussed, and we'll add that into Xcode so that when you compile your application, it's bundled in to your application for submission to the Mac App Store, and your application is signed with the entitlements contained inside this profile.

In order to do that, you open the Organizer panel in Xcode. Those of you who have worked with iOS have probably gone through this process before. It's new to Mac developers. But we go to the Organizer panel under Devices, Provisioning Profiles. You can either import it with this import button here, or what we're going to do right now is drag it into Xcode. So that's how you add the provisioning profile for this application into Xcode. We'll close that window.

So now we can recompile. First we'll stop the one that's running here, so we're done with that one. And we'll recompile and run the application again. This time the application's entitled. Now you'll notice that when we try to run it, it drops immediately into the debugger. Now that your application is entitled, it needs permission to run on this specific system. In order to do that, any system that wants to run your development application has to have the provisioning profile installed, or else it will be refused to be allowed to run.

So once you submit your app to the Mac App Store and your users download the app, they won't need to deal with the provisioning profile anymore. It'll just run because the Mac App Store has signed it. But if you want your testers, your fellow developers to be able to run the application, they need to have a provisioning profile installed in their system, and that provisioning profile has to match the hardware UUID of the machine they're trying to run it on. So when you go to the developer certificate utility, you'll have to specify what machines you wish to run it on to get your profile.

So we'll show you how to add that to your system. So now if you double click on the profile, which we have here on the desktop in the upper right hand corner, It'll bring up your system preferences window. We have a new profiles pane. And ask if you want to install this profile.

It shows you that the signature of the profile is verified, and asks you if you're ready to install. So we'll say yes, we'd like to install our provisioning profile. Since it's being installed system-wide, it's asking us for your password. Okay, now the provisioning profile for our Cumulus application is installed. You should be able to run on this Mac.

Close that. We've already stopped the program. So now we'll relaunch. Okay, now you'll notice the program successfully launched, and we got the application did register for remote notifications with device token call. So this indicates that the application successfully registered for push. It gave us the device token, which we have to send to our cumulus server, which contains the files we want to download. And so we've done that. And now when your friends send you files, they show immediately in your application. You no longer have to hit the refresh button.

So you'll notice here that the application did receive remote notification was called. And we got the payload here. Is it MS dictionary which we logged, showing that the server has one file waiting for us. We also refreshed our contents of the server so we could see the file in the file browser here that we have ready waiting for us to download. So finally, final feature of push on the Mac, we'll clear this out and exit it.

When you quit your program, and even when your program is not running, notice it's no longer running, when your friend sends you files, You get a badge icon in the dock indicating that you have files waiting for you on the server even though the application is not running. The dock will badge on your behalf. Your users will know that they need to launch the application.

They can browse and see the files that are waiting for them. So hopefully you'll find that adding push notifications on the Mac is pretty easy. It's the same as iOS, and we're looking forward to seeing what you will do with push notifications on the Mac. So with that, I'll hand the presentation back to Darryl, who will talk about some best practices in implementing your push system. Thank you.

All right, let's talk about some of the best practices for using notifications. One thing to remember is that your app should pull data from your server when your app is running. The reason for this is that the push service may be turned off, as the user may have disabled notification for your app or globally. However, your app should continue to be fully functional even without the push service.

Also remember to upload the device token to your server often. You want to make sure that the token that your server has matches the token of every particular user for their device. Finally, don't annoy your users with alerts. You want to make sure that you're sending notifications that your users care about. And if your application doesn't need to send an alert, don't send them.

Right on cue. All right, let's talk a little bit about badges. Badges are the primary notification type. A badge represents some information that the user can take action on. So you're sending a badge because you want the user to click on the application and do something. So remember to keep a server-side count, and this is what the badge should reflect.

You'll want to test the logic that you use for the server-side count. Remember that the count can change while your app is inactive. Notifications can arrive while your app is active. And in every scenario, you want to ensure that the badge count that you're sending represents accurate information.

For more information on push in all of the various frameworks and APIs, there are several options. We can go to our evangelist, Bill Dudney. You can definitely visit the Apple Developer Forums. And for a sample application representing notifications on the Mac, there is a sample app at the URL listed. I'm going to leave this up for a second, if any of you want to write down these URLs. All right, that concludes our session. Thank you all for coming.