Advanced Notifications

Session 708 WWDC 2016

3D Touch on Notifications provides users with access to media attachments and live content. See how your app can take advantage of this new functionality to provide a rich interactive experience within the notification itself.

[ Music ]

[ Applause ]

Good morning.

Welcome to Advanced Notifications.

I'm Michele, and today we will be talking about a few things about new notifications in iOS X.

We'll start with the new notifications user interface.

We'll go over a little bit of an overview, and we'll see what changed in iOS X.

Then we'll see how to use media attachments in the new notifications, and, last, we'll see how to customize the user interface for user notifications in iOS X.

Let's start with the overview of the user interface.

User notifications in iOS X have a beautiful new design.

You see here the new lock screen with beautiful animations and raise to wake.

Here is a banner.

You see they are much more legible.

They have more content.

They show title, subtitle, and this is notification center, and notifications look the same in all three [inaudible] places.

In iOS 8, we introduced Actions Notifications where you can add actions to your notifications to make them more interactive and allow the user to deal with that much more quickly.

In iOS 9, we introduced Quick Reply to enhance actionable notifications so you can even allow the user to respond with text that they type to your notifications.

In iOS X, notifications are much more powerful because notifications now are more important to our device as we interact with them all the time.

They are a very important way we interact with the device, and a very important way the user interacts with your applications.

So in iOS X, you can press on notification, and notification will expand and show a much more detail specialized user interface for your application, and it's dedicated to your content.

It shows more detail, and it's more useful to the user.

The user can also tap on the actions, and the user interface can update and show what changed and the effect of the action that they just used.

Calendar, which just a simple example.

We also have Find My Friends, for example, that when a friend shares their location with you, you see their location immediately in notification so you can see how late they're going to be for your meeting.

We also have notifications for Photo Sharing.

If you shared a photo on iCloud, you can see the photo directly in the notification without opening the app, and you can like it or comment on it without opening the app to look at the, at the picture.

At last, messages.

This is not all of it.

Messages support Quick Reply starting in iOS 8, but you could only see one message, and you can only type one response.

Now you see the entire conversation when you open the notification, and you can respond to it, you can wait for your friends to respond, and you type, can type more responses.

This is the power of new notifications in iOS X.

But is this was all there was to it, I wouldn't need to stay here for half an hour and show you all the new notifications in iOS X.

So the most important feature I want talk to you about today is that everything I just showed you is implemented with the new API's that we are expand, exposing in iOS X so you can do exactly the same things that we've done and add all the same features to your own applications and your notifications.

The first thing you can do is media attachments.

You know, one of the most frequent notifications I receive by my friends are pictures that they're sharing or videos.

So it's really important that we have the content that was shared [inaudible] notifications so I can see it more quickly without having to open the app and download it.

But the problem is that, as you know, push notifications are delivered with push payload, and even if we increase the size last year to 4 kilobytes, that's not nearly enough to send an entire picture, even if it's a small one that we include in the notification.

So how do we do that?

We use the new service extensions that we introduced earlier today in the previous presentation.

So to do, to download the attachment in the service extension, you have to set your notification to be mutable, as you see here in the payload.

I send a mutable content flag, and then you add a reference to the attachment that you want to send with notification.

In this case, I use a simple URL, but you could also use a identifier that your app knows how to download from your own servers.

After you've done this, and the notification is delivered to the device, the system will run your service extension.

In the service extension, you can download the attachment anyway you want.

Perhaps you can use an URL session so that the system helps you manage resources.

And then the notification is delivered to the user with the attachment.

Let's see it, a little bit of code on how to do this.

This is a very basic example of my service extension.

At the top, I implemented the didReceive request withContentHandler, and this is called when the notification is received, and I have to download my attachment.

I download my attachment, again, for maybe using the URL session or other techniques that you prefer, and when I have the file downloaded locally, I can create a notification attachment object.

When I created the object, I added notification content, and I pass it onto the system to be delivered to the user.

After I've done this, this is my notification with a beautiful picture visible immediately to the user without waiting for it to download or without having to open the app.

And you see the notification suite attachments support actionable notifications to.

So you can like or comment this, this picture directly from here.

So media attachments, a quick recap.

They support local, every [inaudible] notifications.

We only talked about local here.

We only talked about remote because local ones are easier.

You just create the notification attachment object when you're scheduling the notification, and you're done.

Attachments support images, audio, and video, and the system will provide, customize UI for this three types of content.

You download the attachment in the service extension, but you have to remember that the service extensions has limited amount of time that it can run, and file sizes are also limited because these are meant to be sent with the notification.

They're not meant to deliver the entire content to the user.

So you may want to send a scaled-down version of the image, and then download the full resolution one when the user opens the app.

Or you may want to send a short video clip if you're sending a video, and then download the full video when they open the app.

When you downloaded it, you add it to the notification, and at this point, the system takes over and manages the file for you.

You don't need to worry about the file anymore.

The system moves it to a separate location and handles all the data.

Oh, yeah, I almost forgot.

Of course, we support GIFs.

[ Applause ]

So attachments are pretty cool, and they provide a very rich interface for notifications, but at the beginning I said that you could implement everything that I showed you with the new notifications, and calendar, messages, and they were definitely not using attachments.

They were using custom user interface, and this is what we're talking about now.

To create a custom user interface, you use the second extension point that we added to our standard notifications, and it's a NotificationContentExtension.

The NotificationContentExtension allows you to add your own views, custom views.

You can draw anything you want, but the main, most important limitation is that there is no interaction with your views.

They don't receive touches.

The user cannot tap on them.

But notifications are still interactive because you can use notification actions, and the extension can handle those actions, and we'll see later how to do it.

So I said that we can implement the same things that the system is doing.

Let's start by seeing what calendar is doing, and then we'll see how to do the same thing.

This is a calendar notification.

You see at the very top there's a header with the notification icon that you can tap to open the app, the application name, and the dismiss button.

This is standard UI that the system provides to all notifications.

Underneath the header, there's the custom content, and this is where your notification extension will live.

This is where you draw your content.

You show all the extra details that you want to the user.

And underneath these, there's a default content that the system shows.

This shows the content that was delivered with the payload.

This was what was visible until iOS 9 in the notification.

And at the very bottom, there are actions that a user can tap and interact in notification.

When the user taps on them, the user interface can update and show what happened.

So let's see how to make one of these ourselves.

We'll start with a party invite.

Parties are fun, and we're going Thursday, right.

This is the basic notification that will be displayed by the user when you just send a push notification, and it's pretty similar to what you expect.

Let's see how to expand this and show custom user interface like we wanted.

The first thing you want to do is to create a new target in your application, and you do that by using the template that Xcode provides, the NotificationContentExtension template.

This template will create three files in a new target.

A view controller, main interface storyboard, and the info.plist where you can set up customizables for the extension.

This is the view controller for the NotificationContentExtension.

As you see, it's just a UI view controller subclass.

It's a regular view controller that you use as you're used to.

It also implements the NotificationContentExtension protocol, and this is what tells the system that you want to use these view controller for the notifications.

This protocol has only one required method.

The required method is didRreceive notification, as you see here, and this method is called together with the view controller life cycle method calls when the notification is delivered to your notification.

To your extension.

So when the user expands the notification, you will receive all the view controller calls and these one in addition.

So you can receive the notification object and update your UI and show different things.

The, the next thing you want to do is tell the system how to find your content extension.

Content extensions, you use the same notification categories that you use to register notifications actions.

In this case, I use the event invite for my party invite invitation, but extensions can also be associated with multiple categories in case you want to use the same UI for different types of notifications that may be similar.

In this case, I'm using the event-invite or event-update.

They could be very similar UI's.

So I can just use the same, different categories because they may have different actions.

So I set up everything.

I have my view controller.

Now I want to add some custom views to it to draw my own UI.

It's a very controller.

I added some labels in my storyboard that I'm not showing here, and I'm, when I receive the notification, I'm extracting the content to have the information I need, and I'm setting the content on the labels that I just created.

You see that I also have some custom information additional to the standard one that comes with the payload because I want to show something more than the standard payload for displays.

In this case, I'm showing the location because it's pretty important to know where the party is.

And this is my notification now.

You see that I have some custom content.

I draw my own UI with my custom labels, different styles, but these notifications has two problems.

The first problem is that this content is too big.

I don't need all that extra space.

It's all empty.

I have much smaller content to display.

The second problem is that the default content is duplicated.

I don't need it because I'm already displaying the same information up top with my custom style.

But we can fix both of these problems.

Well, let's fix the first, the second one first because it's easier, and this is an additional attribute in your info.plist, and you can just set default content hidden to yes to hide the default content.

The system will not add that anymore.

The second problem was the size of my notification, but since it's just the view controller, I can resize it the way I'm used to resizing view controllers.

In this case, I'm setting the preferred content size, but you can set the constraints without the layout.

You can use the storyboard, and they will both work.

And after fixing these two issues, this is my notification now.

It looks much better.

It's the right size that I wanted.

There's no duplicate content, but did you see there was another problem now.

When the notification was presented, it was not the right size.

So the system had to animate a resize the notification to show it the right size.

Let me show it to you again.

See? We could make it better.

The reason this happens is that the system needs to know the size of your final notification when it starts to display it so you can do the right animation.

But your extension is not yet running when the system starts presenting the notification.

So you need to tell the system in advance before any of your code runs what size you want to be at the end.

But the problem is that these notifications run in different devices with different sizes in different context.

So the way we do that is that we set a content ratio, content size ratio.

So these, this defines the ratio of the height and width that you want to use for your content.

Now this may, of course, not always be possible because you may have content of different sizes.

You don't know what content you're receiving.

You still want to display all of it.

So sometimes this may not be possible, but if you can, figure out a size that works for your notifications.

This is the way to do it.

And the result after I've done this is this new notification that now present it directly at the right size from the beginning.

So let's review what we have done so far.

We wanted to do a custom notification UI.

We may, we started with these custom UI.

That's pretty basic, but has all my custom content has additional information that was not in the payload, but it was the wrong size.

So we fixed the presentation size by using the initial content size ratio.

And then we fixed the duplicated content by setting the default content type hidden flag, and we went from the beginning to this.

This looks better than when we started.

Still not great, but I do have an appointment that is unlocked today to fix it.

But I also know another trick to make notifications look nicer.

We can add pictures.

Pictures are always nice, especially on party invitations.

So we can use the same media attachments that we used earlier also in NotificationContentExtensions.

Since they're added to the notification content, you can access them inside your content extension.

So when you receive the notification [inaudible] notification method, you can extract the attachments from your content.

As I mentioned earlier, the attachment is managed by the system, and it's moved to a separate location.

This means that it's outside of your sandbox.

So you need to tell the system that you want to start using it and tell the system when you're done.

When you have access, you just use it as a file.

In this case, I'm adding it to my image view.

And here's my notification now.

You can tell this guy's ready to party.

[ Applause ]

This is much nicer than the one we started with, and it's our own custom UI.

We want, we wanted to show additional information to the user, and we added that.

We wanted to add a picture.

We have that, too.

Well, we missed the next step.

We want to make this interactive.

We want to implement the actions.

Let's do that now.

Default actions by default work the same way as you're used to since iOS 8.

They are delivered to the app.

When the user taps on the button, the app receives the [inaudible] request, and the notification gets dismissed immediately.

This is pretty convenient because it's a behavior that you often use, and it's pretty simple to implement, but sometimes you want to show the user the effect of the action for, like, in the example of the calendar invitation.

That when the user tapped accept, the content highlighted the event that I just accepted.

And you can do that in your NotificationContentExtensions.

You do that by intercepting the action in the notification extension.

When you do that, the action is delivered to the extension and it can decide to delay the dismissal of the notification.

So it has time to handle the action, update the UI, and dismiss when it's done.

This is very simple, and you do it with the second method inside the NotificationContentExtension protocol.

This method is optional.

You don't need to implement it if you don't need to intercept the actions, but if you do implement it, it means that you have to handle all the actions that are in that notification.

You cannot handle one and not look at the other ones.

So when you receive the notification, you can send a response of your server to update the information on the server.

When you receive the response from the server, you update the UI saying that the user is going to the party, of course.

And when it's done, you can dismiss the notification.

So that the interface was updated before dismissing it.

In case you want to still forward the action to your application, you can do that, too.

If you want to do additional handling, or you want to keep the code in, all in the same place, you just call completionHandler with a different parameter.

And what happens when we do this is that we receive notification, we tap on that, and we can update the UI, and we dismiss later.

So you saw in my example code that we implemented the accept and decline action, and we have a third one at the bottom.

Because sometimes when you're responding to a party invitation, you want to see, we want to tell your friends how excited you are to go to the party or how upset you are that you can't go.

So you tap on the comment action.

The comment action is a texting production, like the ones we introduced in iOS 9, and you use it in the same way, except with the new, awesome new framework.

This is a texting production.

A tiny bit of newer PI on this.

You can set the place holder in the text field, and when you created the action, you can add it to your category so that it's displayed with notifications.

So when the user taps on the comment button, the text will display.

Now since this is an action like the others ones, you can handle it in the same way.

So you can intercept it inside your extension and handle it there.

Here's how you do that.

You receive the notification.

You check if it's a text input action.

You extract the text of the user typed and send it to the server.

And when you're done, you dismiss the notification.

And this is what happens.

You tap, type, and there's a problem again here with this notification.

I want to respond to the invite, but there's only a send button, and I can't say if I want to accept or decline.

So what we would like to do is to have the text field but also two buttons so I can accept or decline the invitation.

Something like this.

Would that work?

Well, there's no new API to do this, and there's no new API because it already exists.

You can use the existing UIKit custom input accessory view API to add your own custom into the text field to the notification.

[ Applause ]

To do that, the first thing you want to do is to say that your controller can become first responder.

This tells both the UIKit system that it's part of the responder chain and the notification system tells that you don't want the standard text field.

Then you create your own custom inputAccessoryView, in this case, like mine, there was a text field and two buttons.

And then when I receive the response, the action, the comment action from the user, I can make it first responder so that the text field and the keyboard appears.

I need to do both calls here because the first one makes a view controller first responder.

So the text field appears, and the second one makes the text field first responder so that the keyboard appears.

You notice that in this case, I don't really, I'm not interested in the fact that it's a textable action or not.

You can use regular actions because I'm going to get the text from the user from my own inputAccessoryView.

So I have access to that UI.

And the result of this is that when you tap on comment, now you can type your response and actually respond to the invitation.

So this was all for NotificationContentExtensions.

There are some other small bits of the PI that you can come and talk to us at the labs a little later in the week.

And what we learned today is how to use attachments in custom UI, in Notification Content Extensions in iOS X.

We learned how to download and add attachments to notifications by using a service extension.

We learned how to do custom UI, fully custom UI with your specialized content with the content extensions that can use media attachments and can handle user interaction.

For more information about all of this, there's a special page for this session.

We had a session earlier today that if you missed you can catch up to learn about the new user notifications framework and more details about the service extension.

Thank you.

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US