Streaming is available in most browsers,
and in the Developer app.
-
Implement App Shortcuts with App Intents
Discover how you can create Shortcuts in your app with zero user setup. We'll show you how App Intents can help you present custom Shortcuts views, and explore how you can add support for parameterized phrases to allow people to quickly express their intent. We'll also share how you can make your App Shortcuts discoverable with a Siri Tip, and Shortcuts links. To get the most out of this session, we recommend a basic familiarity with SwiftUI.
Resources
Related Videos
Tech Talks
WWDC22
-
Download
♪ (Mellow instrumental hip-hop music) ♪ ♪ Hi, my name is Michael Sumner. I'm a software engineer working on Siri and App Intents. In this session, I want to talk to you about creating app shortcuts for your app, using the new App Intents framework. I'll start with an overview of what App Shortcuts are and how they relate to App Intents. Then, I'll walk through creating an app shortcut in Swift, and adding a parameter. Finally, I'll cover how to make your app shortcut discoverable, so users can benefit from your hard work. Let's get started with the App Intents framework and App Shortcuts. People use shortcuts to create multistep workflows with your apps that can be used from the Shortcuts app and from Siri. Until now, someone first had to set up a shortcut via an Add to Siri button or the Shortcuts app before they could use your intent. We're excited to introduce App Shortcuts, which require zero user setup. This makes it easier than ever for people to benefit from your shortcuts. By integrating with App Shortcuts, intents from your app will be available as soon as your app is installed. This makes it easy for someone to discover and use your app's functionality. They no longer need to head to the Shortcuts app or use an Add to Siri button to set anything up. App Shortcuts, like user-built shortcuts, can be run from the Shortcuts app, Spotlight, and Siri. This gives people multiple ways to discover and interact with your application from various places in the system. For example, when searching in Spotlight, your app shortcut will be displayed right in the search results for easy access. By implementing App Shortcuts, your users will be able to interact with your app in quick, lightweight interactions that make it easier for them to complete their task and be on their way. My team is working on an app -- Meditation -- that helps users meditate by guiding them through a set of audio prompts and sounds to help them focus on what matters. Today, to start a meditation, users have to launch the app, log in, and find the meditation session that they want to run. By integrating with App Shortcuts, my users can quickly access these features from anywhere just by asking Siri. And by making it faster to start a session, users can integrate meditation into their daily routine, either in the morning before work or in the evening to help wind down after a long day. Alright, let's dive right in to the code needed to create an App Intent and turn it into an app shortcut. Unlike previous shortcuts, App Shortcuts are built with the new App Intents framework. App Intents is a new, Swift-only framework built from the ground up to make it faster and easier to build great intents. With App Intents, everything is defined right in your Swift source code, instead of a separate metadata file. This removes any code generation steps and allows you to stay focused without switching contexts between the source editor and the metadata editor. They're also easier to code review and solve merge conflicts. To build App Shortcuts, you'll need to write an AppShortcutsProvider that lists the phrases and other metadata needed to turn your App Intent into a full-fledged shortcut. And note that because these are set up without any user interaction, you'll need to include your application's name in the trigger phrase. Intents are defined as Swift structs, that implement the AppIntent protocol. A basic intent has just two requirements -- a title, which is used to display your intent in the Shortcuts app, and a method called perform. The perform method is where you run your intent's logic and return a result. Additionally, you can trigger prompts for the user and await their response. In this intent, I'll start the default meditation session using my app's MeditationService. Because the perform method is async, I can run asynchronous code to start my session. Once the session has started, I'll return a dialog that is shown to the user. And if your app is localized, you'll want to localize this string in all of your locales. So far, with what I've built, the StartMeditationIntent will appear in the Shortcuts app when authoring a shortcut. A motivated user can take this intent and create a shortcut that will kick off a session. In this shortcut, I've also added a second intent to enable a Focus. By default, my App Intent is rendered using the title I specified in my source code. To customize the rendering for your action, be sure to add a parameter summary to your App Intent. Parameter summaries allow you to customize the look of your intent, as well as show values inline. However, this intent works great as a shortcut all by itself. Ideally, someone would be able to run my intent without first having to author a shortcut at all. By creating an app shortcut, I can perform this setup step on behalf of the user, so they can start using my intent as soon as the app is installed. Now that I've written an intent, I'll create an app shortcut for it. Similar to an intent, App Shortcuts are defined in Swift code, by implementing the AppShortcutsProvider protocol. To implement the protocol, I'll simply create a single getter that returns all the app shortcuts I want to set up for the user. Note that in total, your app can have a maximum of 10 app shortcuts. However, most apps only need a few. So I'll create a single AppShortcut for my StartMeditationIntent. To get started, I'll pass an instance of my intent. If my intent's initializer took parameters, I could specify values here. Second, I'll create an array of spoken phrases that will invoke my AppShortcut from Siri. You'll notice that rather than writing my application's name directly in the string, I used a special .applicationName token. This allows Siri to insert not only my application's main name, but also any app name synonyms that I've configured. Because users may say different phrases to start meditation, I'll provide a few more alternative phrases here. If your app is localized, you'll need to localize these phrases as well.
Great. So now when someone wants to mediate, they just stay to Siri, "Start a meditation." Siri will call the StartMeditationIntent and speak the dialog that I returned. Also, if someone searches for my app in Spotlight, they'll see the first App Shortcut I've listed in my code. When the user taps the result, the shortcut will immediately run without launching the application. It's important to note that if your intent does trigger an app launch, it won't be shown in Spotlight. So, with just a very small amount of code, I've now made it much, much simpler for my users to meditate with my app. But right now, Siri shows a default view whenever running my intent. This is OK, but I'd really like to show the user more information when they run my app shortcut. To do this, I'll need to implement a custom view that Siri can show whenever my intent is run. Views in the App Intents framework are built using SwiftUI and leverage the same view technology as widgets. This means you, as a developer, don't need to build a separate UI extension for your custom view. Instead, you can simply return the view when running your intent. It's important to think about the specific constraints this brings for your views. Just like widgets, custom App Intent views can't include things like interactivity or animations. Make sure to take this into account when designing your UI. App Intents supports showing custom UI at three phases: value confirmation, intent confirmation, and after the intent is finished. For my app, I'm going to return a custom view at the end of running my intent. If you're using these other prompts, be sure to think about how you can integrate custom UI at those steps too. Finally, as I mentioned, displaying custom UI is easy. You simply need to return your view from your intent. Alright, time to jump into some code. Adding a custom view is easy. As I mentioned, I'll just return the view alongside my dialog. The App Intents framework will take care of presenting my view inside the Siri snippet. Keep in mind that your views are going to be shown alongside other Siri views, like the snippet title or confirmation buttons. So you'll want your snippet's design to feel at home inside of Siri. Up next, let's check out how I can extend an app shortcut to include parameters. In my previous implementation, I chose to start the default meditation session. But my app includes many great session types, and users will want to start a particular session they have in mind. Ideally, my user would be able to specify the session they want to start when running my intent. To support these use cases, I'll need to extend my intent by adding a parameter that captures the session the user wants to run. To add a parameter, I first need to define the parameter's type. I'll create a MeditationSession struct that has the relevant information for a session. I'll include a name, and I'll give it an identifier field, which can be a UUID. To use this struct as a parameter for my intent, I also need to implement the AppEntity protocol. Implementing the AppEntity protocol tells the App Intents framework about my type and lets me specify additional information, like how the entity is displayed. The entity protocol requires that my type has an identifier, which I've already provided. I could use other types as well, like integers or strings. I also need to provide some information on how to display my entity. This will be used in the Shortcuts app and other places where my entity is shown. Finally, I need to wire up a default query. I'll call my query the MeditationSessionQuery, and I'll implement it next. In order to work with my entity, the App Intents framework needs to be able to look up my entities based on their identifier. To make this possible, the EntityQuery protocol defines just one requirement: a function that takes identifiers and returns matching entities. I'll implement this function by looking up the sessions in my SessionManager. Next, I'll update my StartMeditationIntent to add a parameter. Parameters are straightforward; they are just a normal property on my struct. But to tell App Intents about my parameter, I also need to add the @Parameter property wrapper. This property wrapper lets App Intents know that the session property is part of my intent. I can also specify additional metadata in the Parameter property wrapper, like the display name. Now that I've added a parameter to my intent, I need to ask the user which session they'd like to run. The App Intents framework has robust support for asking users follow-up questions to gather values for my intent's parameters. These prompts will be displayed anywhere my intent is run. When run from Siri, Siri will speak out the questions, and ask the user to speak the answer. In Spotlight and the Shortcuts app, the user will be presented with the same prompt in a touch-driven UI. App Intents supports three types of value prompts. Disambiguations asks the user to select from a fixed list. Disambiguations are great to present the user when you have small fixed set of options for a parameter in your intent. Value prompts allow you to ask the user for an open-ended value. These are great for types like strings or integers, which can take any value. Finally, confirmation asks the user to verify a particular value and can be helpful if you want to double-check with the user that you understand their intent. Prompting for values is a great way to make intents more flexible and allows you to gather more information from the user. But they also slow down the conversation, and can frustrate users if you use them too often. For more insight into designing great intents, check out the session titled "Design App Shortcuts" from Lynn. All right, now that I've added the session parameter to the StartMeditationIntent, I'll go ahead and add logic to my perform method to prompt for this value. In my app, I have a small fixed number of sessions the user can run. If the session isn't already specified, I'll retrieve the list from my SessionManager and present a disambiguation to the user. Using the display representation for each of my sessions, App Intents will format sessions into list items and display them to the user. When the user picks one, the selected item will be returned to me. I'll pass the selected session to my MeditationService, which will start the session. I can then return a dialog to let the user know that the intent has started. Since the user provided a session, it's a good idea to put the name of the session in the dialog so the user knows we understood their request. Great, so now when my users say, "Start a Meditation," my app can prompt the user for the particular session they want to run. However, as I mentioned before, users prefer Siri interactions that are quick and to the point. Ideally, I'd be able to let my users tell Siri the session they'd like to run in the initial phrase, rather than in a follow-up question. Well, I have good news. App Shortcuts has support for extending trigger phrases with predefined parameters. By implementing parameterized phrases, my app can support utterances like "Start a calming meditation" or "Start a walking meditation." Parameters are great when you have a fixed set of well-known parameter values that you can specify to Siri ahead of time. For my app, I'll use my session names. Parameters are not meant for open-ended values. For example, it's not possible to gather an arbitrary string from the user in the initial utterance. So, my app couldn't support a phrase like "Search my diary for X," where X could be any input from the user. Instead, parameter values are specified ahead of time, when your app is running. Let's implement some parameterized phrases. To implement parameterized phrases in my app, I need to make a few changes. First, I'll update the query for my SessionEntity to implement the suggestedResults() method to return the list of entities for my parameterized shortcut. Second, I'll need to notify the App Intents framework when the list of available SessionEntities has changed. This allows the App Intents framework to create new shortcut phrases for use in Siri. I'll do this by updating my app's model layer to notify the App Intents framework whenever my session list changes. Finally, I'll add some new phrases to my App Shortcut that reference the session parameter on my StartMeditationIntent. So first, I'll update the MeditationSessionQuery by implementing the suggestedEntities function. The App Intents framework uses the sessions returned from this function to create parameterized shortcuts. It's important to note that while this method is optional, if I don't implement this method, I won't get any parameterized shortcuts at all. Second, I'll need to update my app's model layer to notify the App Intents framework whenever my list of sessions changes. In my app, I infrequently publish new session types that I fetch from the server in the background. I'll update my SessionModel to call the updateAppShortcutParameters() method any time I receive new sessions. This method is provided by the App Intents framework; you don't need to implement it yourself. When called, App Intents will invoke your entity's query to gather the list of parameters for your shortcut phrases. Finally, I'll add new phrases for my App Shortcut that include the session keypath on my intent. The App Intents framework will combine this phrase with all of the sessions returned from my query. The text used for each value is pulled from the title property on the SessionEntity's display representation. Just like before, I'll want to include a few different ways that users might phrase my App Shortcut. This ensures a smoother experience if the user doesn't remember your preferred phrase. All right, I now have a great, full-featured App Shortcut, and I can't wait for my users to give it a try. But in order for that to happen, I need to do some work to help users discover my new Shortcut. The first thing I want to talk about is picking great phrases. Great phrases for App Shortcuts are short and memorable. Users will have a lot of apps on their phone that support App Shortcuts; and in practice, users can have a hard time remembering exactly how to phrase their shortcuts. So where possible, keep your phrases short and to the point. Along these lines, if your app name can be used as a noun or verb, consider using it that way in your phrase. In my app, I've used Meditation like a noun, so that the phrase can be short and memorable. Finally, app name synonyms can help your users immensely. If users call your app something other than your app's display name, you'll want to consider adding an app name synonym for it. iOS 11 added support for app name synonyms. If you haven't created one, now may be a great time to do so. The next thing I want to talk about is the Siri Tip and the Shortcuts link. Because App Shortcuts don't require any user setup, discoverability is vital for users to find and use your App Shortcuts. With App Shortcuts, users no longer need the Add to Siri button to add your Shortcut. It's already added! However, we don't want to lose the discoverability benefits that the Add to Siri button provided. With that in mind, we've created a new Siri Tip view. This view works great anywhere you may have used the Add To Siri button in the past. The Tip view is available in both SwiftUI and UIKit. And we've provided a number of styles so that the Tip looks great in any application. Siri Tips are best placed contextually, when they're relevant to the content onscreen. If a user just placed an order in your app, consider showing a Tip for your Shortcut that provides the order status. Siri Tips should be placed thoughtfully, when you feel a user is likely to engage with your App Shortcut in the near future. The Siri Tip also supports dismissal. The view includes a dismiss button and will trigger a custom closure in your code when tapped. You'll want to remove the view from your layout, and consider not showing it again until you feel it's relevant. Finally, we've also included a new ShortcutsLink that will launch to a list of Shortcuts from your app. This new element is great if your app has a lot of App Shortcuts and you want to let users explore all of them. Now, the great thing about App Shortcuts is they're available as soon as your app is installed. Even before the app is first launched, users can see and run your Shortcuts from Spotlight, Siri, and the Shortcuts app. You may need to take this into account when building your App Shortcut. For example, if your app requires a log-in flow, the user may not have logged in before running your intent. Your intent should fail gracefully with an error message explaining to the user that they need to log in. Second, parameterized phrases for your App Shortcuts won't be available until your app has been launched and notified the App Intents framework that you have new parameter values. If your App Shortcut doesn't contain any non-parameterized phrases, the user won't see your App Shortcut at all until they first launch your app. You may consider adding a few non-parameterized phrases to avoid this issue. Additionally, Siri has added support for phrases like, "What can I do here?" and "What can I do with Meditation?" Siri will automatically gather and recommend any App Shortcut phrases and present them on your behalf. Your app doesn't need to do anything additional for this functionality to work. Finally, in both Siri and the Shortcuts app, the order your App Shortcuts are displayed is determined by the order that you list your App Shortcuts in your source code. You'll want to consider putting your best and most useful App Shortcuts first, so that they get the most attention. Similarly, the first phrase you list in the phrase array will be considered the primary phrase for that App Shortcut. The primary phrase is used as the label on the Shortcut tile, and it's shown when the user asks Siri for help with your app. OK, we covered a lot about App Intents framework and App Shortcuts. I want to leave you with two key thoughts. First, App Shortcuts make it easy for users to use your app from anywhere in the system, so think about the best use cases in your app that fit this more lightweight model. Second, once you've implemented an App Shortcut, users will not know about it unless you tell them! Think hard about how to make your App Shortcut discoverable. Consider places in your app where you can show the Siri Tip, as well as off-product locations, like a website or a sign in your store. We can't wait to see all the great App Shortcuts that you create with the new App Intents framework. To dig deeper into design, as well as the App Intents framework, be sure to check out other talks this week. Thanks, and have a great WWDC. ♪
-
-
3:43 - Implement an AppIntent
// StartMeditationIntent creates a meditation session. import AppIntents struct StartMeditationIntent: AppIntent { static let title: LocalizedStringResource = "Start Meditation Session" func perform() async throws -> some IntentResult & ProvidesDialog { await MeditationService.startDefaultSession() return .result(dialog: "Okay, starting a meditation session.") } }
-
5:31 - Create an AppShortcutsProvider
// An AppShortcut turns an Intent into a full fledged shortcut // AppShortcuts are returned from a struct that implements the AppShortcuts // protocol import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: ["Start a \(.applicationName)"] ) } }
-
6:35 - Provide multiple phrases
// An AppShortcut turns an Intent into a full fledged shortcut // AppShortcuts are returned from a struct that implements the AppShortcuts // protocol import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: [ "Start a \(.applicationName)", "Begin \(.applicationName)", "Meditate with \(.applicationName)", "Start a session with \(.applicationName)" ] ) } }
-
8:54 - Provide a dialog and snippet view
// Custom views give your intent more personality // and can convey more information func perform() async throws -> some ProvidesDialog & ShowsSnippetView { await MeditationService.startDefaultSession() return .result( dialog: "Okay, starting a meditation session.", view: MeditationSnippetView() ) }
-
10:09 - Implement an AppEntity
// An entity is a type that can be used as a parameter // for an AppIntent. import AppIntents struct MeditationSession: AppEntity { let id: UUID let name: LocalizedStringResource static var typeDisplayName: LocalizedStringResource = "Meditation Session" var displayRepresentation: AppIntents.DisplayRepresentation { DisplayRepresentation(title: name) } static var defaultQuery = MeditationSessionQuery() }
-
10:55 - Query for entities
// Queries allow the App Intents framework to // look up your entities by their identifier struct MeditationSessionQuery: EntityQuery { func entities(for identifiers: [UUID]) async throws -> [MeditationSession] { return identifiers.compactMap { SessionManager.session(for: $0) } } }
-
11:16 - Define a parameter
// Adding a parameter to an intent allows you to prompt the user // to provide a value for the parameter struct StartMeditationIntent: AppIntent { @Parameter(title: "Session Type") var sessionType: SessionType? // ... }
-
13:15 - Prompt for values
// Prompting for values can be done by calling methods // on the property's wrapper type. func perform() async throws -> some ProvidesDialog { let sessionToRun = self.session ?? try await $session.requestDisambiguation( among: SessionManager.allSessions, dialog: IntentDialog("What session would you like?") ) } await MeditationService.start(session: sessionToRun) return .result( dialog: "Okay, starting a \(sessionToRun.name) meditation session." ) }
-
16:11 - Implement suggestedEntities()
// Queries can provide suggested values for your Entity // that serve as parameters for App Shortcuts struct MeditationSessionQuery: EntityQuery { func entities(for identifiers: [UUID]) async throws -> [MeditationSession] { return identifiers.compactMap { SessionManager.session(for: $0) } } func suggestedEntities() async throws -> [MeditationSession] { return SessionManager.allSessions } }
-
16:34 - Update App Shortcut parameters
// Your app must notify App Intents when your values change // This is typically best done in your app’s model layer class SessionModel { @Published var sessions: [MeditationSession] = [] private var cancellable: AnyCancellable? init() { self.cancellable = $sessions.sink { _ in MeditationShortcuts.updateAppShortcutParameters() } } // ... }
-
17:09 - Add parameterized phrases
// Phrases can also contain a single parameter reference import AppIntents struct MeditationShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: StartMeditationIntent(), phrases: [ "Start a \(.applicationName)", "Begin \(.applicationName)", "Meditate with \(.applicationName)", "Start a \(\.$session) session with \(.applicationName)", "Begin a \(\.$session) session with \(.applicationName)", "Meditate on \(\.$session) with \(.applicationName)" ] ) } }
-
-
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.