Streaming is available in most browsers,
and in the Developer app.
-
Adopt Quick Note
Learn how you can link your app to Quick Note and help people quickly connect your content to their notes — and their notes to your content. Discover how Quick Note recognizes and links to app content through NSUserActivity, and find out how you can adopt this API in your app. We'll take you through the requirements, benefits, and features of supporting Quick Note. We'll also provide guidance and best practices for NSUserActivity to help your app get all of its benefits.
Resources
Related Videos
WWDC18
-
Download
Hi, I'm Nicki Brower. I'm an engineer on the Pencil and Paper team. And today, I'm gonna show you how to adopt Quick Note.
Quick Note is a brand-new, system-wide note-taking experience aimed to not only streamline the ability to take notes on iOS and macOS, but to connect content from multiple apps and the web in one location.
This feature enables people to easily bring up a Note anywhere, and the best part is, it uses an API that already exists: NSUserActivity. If that sounds familiar, it's because it's used for other features, like Handoff.
Today, I'll show you Quick Note live and in action. I'll talk about the how it works on the system and how to adopt NSUserActivity. Finally, I'll go over some best practices so you can create the best experience.
To show you the new Quick Note feature, I'm going to step through my plan of action to get into shape using Apple Fitness+.
I haven't signed up yet, and I don't want to without an action plan. Instead of having to switch to the Notes app, I'm now able to use my pencil to swipe up from the bottom right corner of the screen to create a brand-new Quick Note to remember that when I'm ready to start, the Apple website has all the information I need to know.
There's also a new add link menu at the top of the Quick Note, where I'll add a link to the website to make it easy to navigate back to this content.
Similar to picture-in-picture, the Quick Note window is able to freely move around to any corner of the device. I can also pinch to scale the window from the default size, to the smallest size, all the way up the largest size.
If I'm finished with my note, I can press the Done button in top left corner. but I still have some stuff I need to add, so I'll swipe the UI to the right to tuck it away on the side of the screen.
In addition to websites, of course, it also works with apps. Using Maps, I was able to find a great spot to practice my HIIT workouts. I'll pull out my note that I tucked away and add this location to my note, too.
For more room to draw, tap the Notes icon from the Quick Note toolbar to get to the note in the Notes app.
Here, I'll take advantage of the ability to draw over images and links.
The links I've added here aren't just any old links. Sure, tapping on them will take me to Safari or Maps, but now I can get back to my note from these apps with Quick Note Suggestions. When I go to the site about Apple Fitness+, the Quick Note Suggestions UI will show up in the bottom right-hand corner. Tapping on this will bring me right back to where I was, and I'll add a note that my goal is to do a HIIT workout 4 to 5 times a week.
I've created a note here on an iPad, but it also works cross-platform with the Mac.
When I visit the link about Apple Fitness+, the Quick Note Suggestions UI will also appear here on my Mac. When I click on it, I'll be directed to the note in the Notes app.
Now that you've met Quick Note, let's talk about how it works. An NSUserActivity object provides a way to capture the state of an app and put it to use later. User activity objects are created about what is happening, such as viewing a web page or viewing app content, and each app will register its current activity with the system.
The system then gets these activities and sends them out out to features like Handoff.
Quick Note linking piggybacks on this system.
In addition to going to Handoff, Spotlight, and Reminders, registered activities are also sent to Quick Note. This is how the link shows up in the add link menu and what triggers Quick Note Suggestions.
NSUserActivity already has three properties that serve as durable identifiers for linking app content with Quick Note. To be part of this ecosystem, you must set one or more of these properties: targetContentIdentifier, persistentIdentifier, and webpageURL. Which ones you choose depends on what other features you want to support.
targetContentIdentifier is also used during state restoration. This property creates a great multitasking experience for apps that run on iPad.
persistentIdentifier is also used to identify app content in the system's Spotlight index, and webpageURL is also used for web fallback during Handoff. In order for Quick Note links to work, there are a few properties the identifiers need to have. They should be unique for that piece of content, be global so they work across all devices, and be stable enough to work for that content over time. Having a unique, global, and stable identifier for an activity enables Quick Note Suggestions. When I come back to the website about Apple Fitness+, the reason the Quick Note Suggestions UI shows up is because the identifier in the link, created an hour ago or six months ago, still matches the identifier on the website.
There are three main steps to adopt NSUserActivity: declare supported activities in your app's Info.plist, create and register user activities describing what's on screen at different points in time, and handle incoming requests to continue an activity.
This could be coming from a link in Quick Note or from another device.
Declare the activity types that your app supports under the NSUserActivityTypes key in its Info.plist file.
The system uses the information in that key to determine whether your app is capable of handling a given user activity object. To create an NSUserActivity object, use one of your plist-registered activity type strings, and set the title. Set one or more of the three identifiers mentioned earlier. Any one of these identifiers can be used for Quick Note. For this example, let's say your app is an iPad app that is also interested in supporting state restoration. Set targetContentIdentifier. Set the userInfo property with any app-specific state information needed to continue the activity.
Then, attach it to a responder.
Instead of having to register the activity by manually managing the current app activity, let the system take care of it for you. By setting the activity on a responder, the object becomes managed by UIKit and AppKit.
Because NSUserActivity is cross-platform, this code works on both iOS and macOS.
The final step is to handle receiving incoming activities and restoring its state in your app. When a link is tapped, Quick Note launches your app and calls the scene (willContinueUserActivityWithType) method of UIWindowSceneDelegate. This is where you can give some feedback that your app is receiving the activity.
Quick Note then provides the activity to your app in scene(continue userActivity:). This is where you set up any view controllers, views, and use the userInfo dictionary to restore and continue the activity. In the case of Handoff, if devices can't connect, the system calls scene (didFailToContinueUserActivityWithType) where you can present an error message. This method will not be invoked for Quick Note, but is good to implement for a well-rounded adoption of NSUserActivity.
For macOS apps, implement the equivalent application (willContinueUserActivityWithType), application(continue userActivity), and application (didFailToContinueUserActivityWithType) in the app delegate. For more information about adopting NSUserActivity, check out the WWDC 2014 video, "Adopting Handoff on iOS 8 and OS X." NSUserActivity is a gateway because it's the foundation for many other features.
By adopting it for Quick Note, this is everything else that you could get. Handoff is on by default, while the others are opt-in. Your app could be even more powerful because people could create a reminder about a document in your app, or have a blog post from your app show up in spotlight, or improved multi-window handling.
Check out the latest documentation and related WWDC videos for more information.
Last, but certainly not least, let's go over some best practices for adopting NSUserActivity for Quick Note. I'm going to go over four behaviors, and for each of these, I'll talk about why and how to implement them in your app.
The title property is a human-readable string for the activity.
This is the string that shows up in the add link menu. That said, the title should provide a good, descriptive representation of the content. In general, it's better to use the title of the document or item directly.
There are a few tips to help identifiers be unique, global, and stable.
Avoid using device-specific data. If the identifier for this photo is its local file path, the link is only guaranteed to work on the device it was created on. Avoid any transient information, like a session ID or specific viewing properties. The title of the photo might be implicitly unique, but if it can be modified, there's no guarantee it will exist when trying to navigate back to this content.
Thinking long term, like using the app's saved UUID for the photo, will allow your app to restore Quick Note links, even if the content has been moved around.
Although URLs can be unique identifiers for app content, they often contain transient state information, breaking the identifier guidelines covered earlier.
Quick Note prefers targetContentIdentifier or persistentIdentifier over webpageURL. webpageURL is perfectly fine to use, as long as it follows the guidelines. If your app uses NSUserActivity for both state restoration and Spotlight, use the same value for targetContentIdentifier and persistentIdentifier. If you have a website that compliments your app, add a URL as a second, fallback identifier. This way, if the app isn't installed, opening a link redirects to your website.
Another important practice is making sure the app's current NSUserActivity is up to date. This means keeping up with what is happening.
Best practice is to keep the title and identifier properties accurate when detecting any activity change, like selecting to view a different photo.
It's not recommended to reuse activity instances. When there's new content, like the new photo, create a new activity.
Let UIKit and AppKit handle the current app activity by attaching activities to responders like viewControllers or views, like I showed in the example code. If attaching to a responder doesn't work for your app, the current app activity can be manually managed by calling becomeCurrent() and resignCurrent() at the appropriate times. For example, when finished viewing the photo, the app will call resignCurrent() on the current activity, and when a new photo is picked, the app will call becomeCurrent() on the new activity.
For better performance, take advantage of the activity's "needsSave" property. An activity might need specific view properties to properly restore the activity in the app. For example, the position and zoom when viewing a map. These properties can be passed along with the activity, but there's overhead when updating after every gesture. Instead of updating the activity, set needsSave to true. When the system needs to send the activity out to Quick Note linking or Handoff, the delegate callback userActivityWillSave is invoked, so that the app can update all the properties on demand.
This callback is where the userInfo dictionary can be updated to include any properties that help with restoring the activity.
There are a couple compatibility issues to prepare for. What if the app has been updated? Take this note with two links from an app. The links could be from an older or newer version of the app than is on the device. Perfectly fine, but the links still need to work. To prepare for compatibility handling, have support to handle receiving activities from earlier versions of your app, and fail gracefully when receiving activities from newer versions.
This could be supported from versioning your activities, or using a dictionary of keys, and being tolerant of keys being missing or having some that you don't understand. What if the content doesn't exist anymore? The content the activity linked to could have been deleted or moved. When navigating back to the app, show an error message if deleted or redirect if the content was moved.
Adopting Quick Note plugs your app into this new system of note taking. A system designed to improve the connection between people, content, and your app.
Make sure you've adopted NSUserActivity. Now's a great opportunity to revisit and polish up any existing code.
Have unique, global, and stable identifiers. And set your activities on responders to let the system manage the app's current NSUserActivity. Thank you for watching, and I look forward to seeing your app in Quick Note and beyond. [percussive music]
-
-
16:57 - How to adopt NSUserActivity to support Quick Note
// Create the NSUserActivity and describe the content or user activity let activity = NSUserActivity(activityType: "com.myapp.MyActivityType") activity.title = document.title // Set one or more of: // .targetContentIdentifier // .persistentIdentifier // .webpageURL activity.targetContentIdentifier = "uniqueGlobalStableIdentifier" // Set userInfo to save app-specific state information activity.userInfo = ["myKey": …] // Attach it to a view controller, window, or other responder; let the system make it current when needed viewController.userActivity = activity
-
17:02 - Handle NSUserActivity continuation in your window scene delegate or app delegate - iOS
class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willContinueUserActivityWithType userActivityType: String) { // show user feedback while waiting for the NSUserActivity to arrive } func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { // set up view controllers and views to continue the activity } func scene(_ scene: UIScene, didFailToContinueUserActivityWithType userActivityType: String, error: Error) { // show error about failing to continue an activity } … }
-
17:06 - Handle NSUserActivity continuation in your window scene delegate or app delegate - macOS
class AppDelegate: NSObject, NSApplicationDelegate { func application(_ application: NSApplication, willContinueUserActivityWithType userActivityType: String) -> Bool { // show user feedback while waiting for the NSUserActivity to arrive return true } func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool { // set up view controllers or documents to continue the activity return true } func application(_ application: NSApplication, didFailToContinueUserActivityWithType userActivityType: String, error: Error) { // show error about failing to continue an activity, if appropriate } … }
-
17:26 - Improve performance with needsSave
activity.needsSave = true … func userActivityWillSave(_ userActivity: NSUserActivity) { userActivity.userInfo = [ "center" : visibleFrame.middle "zoomScale" : scrollView.zoomScale ] }
-
-
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.