Hi. My name is Alex Schaefer, and I'm an engineer on the iOS system UI team. And this is Targeting Content with Multiple Windows. To get a sense of the problem we're going to talk about today, let's take a quick detour to iOS 12.
In iOS 12, we had a 1-to-1 mapping between your application and your user interface.
Let's say a notification comes in.
The user taps on it. It gets routed to your app, and your app will update your user interface in response. Great. What could be different? Well, in iOS 13, you could have multiple user interfaces running which raises the question - Which scene should activate in response to this notification? Well, I know what you're all saying.
Just ask my app. Well, I guess. But what if your app isn't running? Who cares? Just launch my app.
Well, hold your horses.
iOS needs to know which scene in your application should be frontmost and activated in response to that launch event, like that incoming notification.
So, if we're going to background launch your app and ask for the appropriate scene, we'd have to wait until your app is fully loaded and then wait again until you could've made that determination.
This could lead to a less-than-desirable user experience. The system would basically grind to a halt waiting for that feedback. And when I tap a notification, I expect it to go somewhere immediately.
So, what could we do about that? Well, let's take a step back and let's think about what we have to work with with the system. We have your application. Maybe it's running, maybe it isn't. Your app has your scenes and also the knowledge of the capabilities of each scene. That's going to come in handy.
And finally, the system has this incoming notification. We've talked about why we can't rely on activating your app, and we know that the notification has to somehow trigger an appropriate scene to be activated. So, let's try and pull together a solution, given these constraints.
First, we need to find a way to describe what that notification pertains to. So, let's add some of the notification that lets the system know what it is about.
Then we need to get your scenes to describe somehow something about their capabilities. You know, what kind of content they can show.
Well, if your scenes are describing what kind of content they can work with to the system, and the notification has this hint about what it's about, then we don't really need your app.
The system is informed enough to make a selection of a desired scene to activate in response to this notification.
So, to think about that and think about those capabilities, we need to think about what's, what those capabilities are. And those capabilities are housed within this UIKit class, UI Scene Activation Conditions. This is an object attached to UIScene. And your scene activation conditions are really just a couple of NS predicates that set the course for what specific scene can activate for it.
Let's dig into the API.
So, your activation condition consists of two parts, your canned predicate and your preferred predicate. You should think of the canned predicate as the main predicate of the two. This is expressing to the system what kind of content the scene can display.
Your prefers predicate is a way to express to the system that this scene is especially interested in a particular type of content. You should think of canned as expressing capability and prefer is a way to delineate amongst the capable scenes the content that should be chosen.
I've told you these predicates help you define your capabilities, but I haven't really gone into detail about what these predicates operate on.
These predicates operate on something called target content identifiers. You might be asking yourself what that is.
Target content identifier is a string. It's just the string. But, it's a little bit more complicated than that. A target content identifier is a structured way to represent data within your model. The system's not going to access your model - that's your job. But what we're going to use that for is a way to build off these scene activation conditions.
iOS 13 is going to use that target content identifier and evaluate it against your scene activation conditions for all the scenes your application has and use it that to make the call on what scene the content should be targeted to.
Clown Town is our exciting demo application which answers the age old question - What would it be like to order a clown at any time to my current location? So, let's take a look at what a target content identifier might look like for Clown Town. So, this looks exactly like a URL. In this case, Clown Town is actually using a universal link. Like we were saying, target content identifiers should ideally express in a structured format, just like a universal link or URL. Many of you are already using a universal link and that'll be great here as your target content identifier.
Let's take a look where in the SDK target content identifiers have been added. First, UNNotification Content. New in iOS 13, you can actually augment your JSON payload prior to sending it off to the Apple Push notification server with a new key, Target Content ID.
So, this raises also a very important point. You can actually structure this target content identifier the same on your back-end server and actually pinpoint what scene that notification should open up in.
Next, UI application shortcut item has been extended to allow for using target content identifiers. New in iPad OS this year, you can actually long press on an icon in the homescreen and get the same quick actions you've been using on your iPhone.
And finally, NS user activity. Use this date restoration as well as features like handoff could also be very useful there.
So, let's set up that scene in Clown Town in response to that target content identifier we just talked about.
Up top we have our target content identifier.
It's our URL format and it looks like it's geared towards a clown named Crusty.
On your left, we have a general overview of all clowns we can order in the area.
This is our main scene and where all content in our application lives. The user's really unlikely to associate Crusty with this scene. I think it would be ideal to set this scene's activation conditions up in such a way that it can display anything but doesn't prefer anything specifically. And that makes sense. It's my main scene and where I enter into my application, it has all my content.
Lucky for us, that's actually the default when you create a new scene. Your UIScene Activation conditions will be set up to allow any content, or can allow any content, but not prefer anything specifically.
Alright. On your right, we have a scene set up just for Crusty. This scene can display any specific clown's details but it's likely the user would associate Crusty with this scene specifically. So, we should express that association within our scene activation conditions, as the scene can be activated, and we prefer it to be activated specifically for Crusty. So, let's take these requirements and put together some scene activation conditions for our Detail scene.
Okay, let's break this down.
For this scene, we want to only activate if this scene is about Crusty. And so we're just going to check to see if the target content identifier that's passed in is equal to the one we would expect for Crusty. Cool. Now, you'll note that this is a place where we actually use the same predicate for our can and our prefers. This is a pretty common pattern you'll find yourself using when you want to target a scene for a specific piece of content.
Sure, we could accept any other clown here. It's just a detail scene.
But if I have a notification come in, I want it to be targeted to exactly where Crusty is.
Cool. So, let's talk about what happens when we set these predicates.
When I set the Crusty predicate on our scene activation condition, the system's going to package these predicates up and ship them off to somewhere else in the operating system.
That has a couple repercussions for how NSPredicate is used within scene activation conditions and I'd like to go over them right now. Scene activation conditions have three restrictions with its use of NSPredicate. First, block-based predicates aren't allowed.
Unfortunately, we can't package up code within your running application and ship it out to other parts of the system.
Next, regular expression-based predicates aren't allowed. We can't use them because they could introduce an indeterminate amount of time during the evaluation of your scene predicates.
We encourage you to take a look at the like operator. It's the de facto glob operator to NSPredicate and it should help you do all the kinds of wildcard matching you might want to do. With that being said, if you have a unique thought on how you might use a regular expression predicate, please use the feedback assistant and inform us of what you're thinking. We'd really like to hear about it.
And finally, the only keypath your NSPredicate can reference is self. Which is to say, you're not going to set your scene activation requirement predicates on something along the lines of the length of the string or your target content identifier. We want you to put real content that you could actually use in your model there. Next, let's take a look at another example for what their scene activation conditions might look like for our commonly used app architecture. Let's talk about what a tabbed application might do like Safari.
You'll see that Safari here has two tabs open, each analogous to their own document.
And we should sort of think of each tab, since they're their own document, as having their own target content identifier. But note, if we have two of these target content identifiers up on screen and we want to set it on our scene activation conditions as something we prefer, how would we do that? First, let's examine the canned predicate.
Simple enough. Document-based apps can typically open any kind of documents in your application. So to encode that, we actually use an always true predicate here to describe that any scene can display any content passed to it. What kind of content does it prefer? Because this UI has multiple tabs, it makes sense that we'd use something like a compound predicate in order to gather all the subpredicates within it. And then we'll use that with our scene activation conditions.
Great. Well, for more information, please visit developer.apple.com. We have all of our slides and notes and you can go there and get some more information about that. And really, thank you for coming. It has been a tremendous WWDC and we are so thrilled to see what you guys make with these new APIs. Thank you very much.
[ Applause ]
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.