Streaming is available in most browsers,
and in the Developer app.
-
Migrate custom intents to App Intents
Learn how you can easily convert your existing custom intents to App Intents. We'll take you through the conversion of your intents to Swift and discuss how you can improve discoverability of your app features when you create App Shortcuts. To learn more about App Intents, watch "Implement App Shortcuts with App Intents" and "Dive into App Intents" from WWDC22.
Resources
Related Videos
WWDC22
-
Download
Hi there, my name is Ari, and I'm excited to talk about how to migrate custom intents to App Intents.
In this video, I'm going to cover why you should adopt the new App Intents framework; how migrating works, including backwards compatibility; and how to actually convert to App Intents.
First, let's cover why you should adopt App Intents and how it's different from previous frameworks.
We introduced the SiriKit Intents framework in 2016, which comes with a set of purpose-driven system intents that provide a complete user experience for common use cases like messaging, workouts, phone calls, and more.
Next, we introduced custom intents which lets you define your own intents for any use case, bringing your app's functionality to Siri, shortcuts, and suggestions.
And we added WidgetKit which uses custom intents for widget configuration and prediction.
At WWDC22, we introduced App Intents, a new Swift-native framework to provide intents from your app to the system.
App Intents is a great framework to adopt, because it's modern, powerful, and easy for users.
It's modern because it's designed natively for Swift.
Thanks to the latest language features, you can write dramatically less code to support the same functionality.
We've also eliminated the need to maintain intent-definition files and use code generation.
And you can now provide snippets as lightweight SwiftUI views.
It's powerful because entities and queries enabled deeper use cases.
You can run App Intents directly in your app's process without providing an extension.
And there are new opportunities for customizing the user experience when people set up and run your intents.
It's also easy for people to use.
Intents can be easily exposed as App Shortcuts which are immediately usable with zero setup required.
Plus, there are new ways for people to discover your shortcuts because they'll be shown at the top of Spotlight and in Siri tips that you can include in your app.
To get all the benefits of the new framework, you'll need to upgrade any custom intents that you built for Siri and shortcuts to App Intents.
SiriKit intents are still fully supported.
So if you're building for Siri domains like messaging or media, or if you're using intents with WidgetKit, you should leave them as is.
To learn more about the App Intents framework, check out our session from WWDC22, "Dive into App Intents." And to learn more about App Shortcuts, which makes it super easy for people to use your app's functionality from Siri and Spotlight, check out "Implement App Shortcuts with App Intents." Next, let's cover migration.
With migration, you can convert your existing intent definitions to App Intents with a single click in Xcode.
You can support both iOS 15 and iOS 16 with the same app binary.
And you can enable people's existing shortcuts to continue working with your new App Intents.
To convert your intent definitions to App Intents, all you have to do is navigate to your intent definition file and push the Convert to App Intent button.
Xcode will produce App Intents code that is equivalent to your old intent definition.
Then, you can populate the code by refactoring your old content handler code.
We'll talk about this more in depth in the next section.
In order for people to have a seamless experience when your app upgrades to App Intents, the system automatically takes care of mapping from your old intents to the new ones.
Let's talk about how that works.
Just by adopting the CustomIntentMigratedAppIntent protocol, the system will have enough information to know how to translate between the old and new intents.
When you adopt this protocol, you provide the intent class name property, which is the class name that was used for your old custom intent.
In most cases, you shouldn't have to provide this yourself.
When you use the Convert to App Intent button, the resulting code already adopts this protocol.
Because of the App Intent's migration capability, you don't need to wait until your app targets iOS 16 to upgrade to App Intents.
In fact, you can easily support both newer and older operating systems with the same app binary.
To do this, include both your legacy intent handlers and your App Intents in your app.
To maximize code sharing, factor both sets of intent handlers over a common set of business logic.
Assuming you adopt the migrated App Intent protocol, shortcuts will automatically deduplicate your intents when you include both sets in your app.
So on iOS 15 and earlier, the Shortcuts app will only show the legacy intent implementation; and on iOS 16 and newer, it will only show the App Intent's implementation.
Once you switch your minimum deployment target to iOS 16 or newer, you can safely delete the legacy intent handlers and definitions for intents that you've migrated.
They are no longer necessary.
One thing to think about when migrating is that people have existing shortcuts that rely on your old intents, which they might have made in the Shortcuts app or added using the Add to Siri button in your app.
The good news is those shortcuts will continue working with your new App Intents as long as they adopt the migrated App Intent protocol.
People's shortcuts aren't overwritten to use the new App Intents; they automatically use a common format that works for both the new and old intents.
In order for this to work, the schemas of the legacy intents and the App Intents must be compatible.
In order to be compatible, the parameters of the custom intent and the App Intent must have the same names and equivalent types.
There are some changes that you can make without breaking schema compatibility.
Specifically, you can add or remove parameters or make existing parameters non-optional.
To check schema compatibility in Xcode, check out the old intent definition file where there's a list of parameters.
Each parameter has a name and a type.
In the inspector pane, there's also a field for the intent's class name.
When working on your App Intents code, make sure the intent class name matches what was in the intent definition file, so that the system can consider the new intent to be equivalent to the old intent.
And make sure that the parameter names and types in the App Intents code stay compatible.
Again, the Convert to App Intents button in Xcode will automatically ensure schema compatibility.
So if you use the tool and don't make any changes, you'll be in good shape.
Next, let's talk about how to actually convert your existing intents to App Intents.
There are two steps to migrate an intent.
Step one is to migrate the intent definition file and step two is to migrate your code.
Let's start with the intent definition.
I'm a big fan of soup, and we have an example app called Soup Chef that lets people place orders for soup.
It has an intent for placing orders with parameters for which soup to order and how many, which toppings to add, and pickup or delivery locations.
I'm ready to convert this to App Intents, so I'll navigate to the intent definition file in Xcode and press the convert button.
Next, I choose which intents to convert -- just the one in this case.
Then I'll choose where to save my new intent code and which target to include it in.
That could be my app target or an App Intents extension target if I've added one.
In this case, I'll check the app target and the watch target too.
App Intents cannot be added to framework targets.
Next, I'll see the App Intents code that Xcode generated.
It's broken apart across a few files which represent all of the intents, enums, and custom types that were included in the intent definition file.
I want to call attention to a few particular areas of my old intent definition that have been migrated.
In the new code, there's an orderSoup struct that conforms to the App Intent protocol.
Note that this structure is marked as available in iOS 16 or later.
You'll need to apply that annotation to all code that uses the App Intents framework if you're deploying your app earlier than iOS 16.
Each parameter in my intent definition file, along with its metadata, has been migrated to @Parameter declarations in the App Intent structure.
All of the Shortcuts app parameter summaries have been migrated to this parameterSummary declaration.
What used to be represented as parameter relationships can now be represented using Switch, Case, or When statements in the ParameterSummary.
My Soup and Toppings custom types are now app entities, including some to-dos that I'll need to fill in later.
OrderDetails is now a transient app entity.
It's considered transient because it doesn't have a unique identifier that can be used to look it up later on.
And my OrderType custom enum is now an app enum.
The human-readable names were migrated to case display representations.
Lastly, all of the dialogs in the intent response have been migrated to an extension on IntentDialog.
These dialogs can be used for my perform method.
The migrator may generate more strings than are needed, so if you see ones that aren't actually used in the old intent handler like, "Just to confirm, you wanted \ (soup)?," feel free to remove them.
Now that we migrated our intent definition, let's go ahead and migrate our intent-handling code.
Note that the autogenerated App Intent has a placeholder for the perform() method with a to-do noting that it needs to be filled in.
Let's look at how to do that.
In the old framework, you provided an intent definition file and a set of intent handling code.
In the new framework, everything is represented in code.
The parameters in your old intent definition have already been migrated to the new code.
The resolve, confirm, and handle methods in your old code will need to be combined into a single perform method that gets called when your intent is run.
And custom types and dynamic options will need to be refactored into entities and queries.
So let's take a look at how to migrate each phase of intent handling, starting with resolve.
In the resolve phase, your intent handler validates each parameter of your intent and prompts the user for a value if needed.
When migrating resolve methods, you should take advantage of App Intents' new automatic resolution behavior where possible.
Otherwise you should refactor your resolution logic into the perform method.
Let's take a look at some examples.
Here's our old resolution method for the soup parameter.
This follows a common pattern in the old intents framework.
Try to unwrap the soup parameter.
If it's nil, return a resolution result asking the user to pick a soup using a disambiguation.
If it's set, return a resolution result with success and pass back the same soup that was already specified.
This kind of boilerplate is no longer necessary with App Intents thanks to automatic resolution.
If you have parameters that were resolved this way before, here's how to take advantage of the new functionality.
By default, your migrated parameters will be optional but you can get automatic resolution behavior by changing the type to non-optional.
When you make a parameter non-optional, App Intents will automatically ask the user for a value if it's empty by using the suggested entities from the SoupAppEntity's query.
Then, add a dialog into your parameter declaration so that the user gets asked a specific question when the resolution system prompts for a value like, "Which soup do you want?" Once you do this, you don't need any resolution code for this parameter anymore.
For all other types of resolution, you should move your resolve implementation to the top of your perform() method and change your API usage to use the appropriate new APIs to ask the user for clarification.
For example, let's say your old resolve method for quantity unwraps the quantity and throws a needsValue if it's missing and then checks to see if the quantity is greater than the number of soups that are actually available and returns an error if so.
When we move this code to App Intents, we don't need the first part at all anymore, because we can separately just make the quantity parameter non-optional.
For that second part, we'll want to take the code that caused the completion handler with an unsupported resolution result and replace it with code that throws an error indicating that there aren't enough soups in stock.
We'll need to define the error as an enum, conforming to error and the custom localized string resource convertible protocols.
That way, we can provide the dialog that's spoken or shown to the user when this case is hit.
If you used to have code that returned and needsValue result dynamically like in this example, you can replace that with code that throws a needsValueError.
When you throw a needsValueError, the system will prompt the user for a value with the dialog you provide and then will run your perform method again from the start.
Another option is to use the requestValue method.
When you use requestValue, you can prompt the user for a value and continue running your perform method without starting over.
In addition to the requestValue method, there are also requestDisambiguation and requestConfirmation methods that you can use to replace your previous API usage.
Next let's talk about confirm.
Confirm is an opportunity to do additional validation and supply information for the system to ask the user to confirm that they want to proceed.
For validation, you should move all of the validation logic that was in your confirm method to your perform method.
For asking the user for confirmation, we have a new simple requestConfirmation() API.
The new API is just a single method call.
Using async/await, this method will wait until the user confirms before continuing with your perform method.
If they cancel, an error will be thrown, and execution of your perform method will stop.
The requestConfirmation method includes several arguments that affect the confirmation prompt, including the dialog that is spoken or shown by Siri, the SwiftUI view that's shown in the snippet, the label used for the confirmation button -- in this case, order -- and the showPrompt argument, which controls whether or not the dialog should be shown onscreen as a prompt.
This should be set to false when the dialog and view contain the same information as each other.
So it makes sense for Siri to speak the dialogue but not show it.
Next, let's look at handle.
For refactoring handle, you can simply move your code from your handle method to the perform method.
You should be able to remove some validation code from the old handle method since resolve, confirm, and handle now happen all in one single method.
For example, if you copied your old code from handle, you'll probably end up with code for unwrapping parameters that are no longer optional which can now be deleted.
At the end of your perform method, you should return an intent result.
The result can include a variety of fields like the dialogue for Siri to speak or a snippet view to show.
Each one requires that you annotate your perform method's return type with the appropriate protocols, like ProvidesDialog for dialog and ShowSnippetView for the SwiftUI snippet view.
Lastly, let's look at migrating dynamic options.
You'll need to fill in the Query or DynamicOptionsProvider depending on the parameter type.
Xcode will provide to-dos in these places where you need to fill them in.
For a query, you'll need to implement methods for returning entities by identifier, by string if it's searchable, and the set of suggested entities that will appear when the user taps that parameter in Shortcuts.
For dynamic options, you can just return all of the options in the results method.
And that's it! You're finished migrating to App Intents.
Before you're really done, there are a few more things I'd recommend looking at.
The first is to adopt App Shortcuts.
This will let you make your intents discoverable and let people use them just by saying a few words to Siri.
Add Siri tips into your UI so people can learn what to say to Siri to use your app's functionality.
These should replace any Add to Siri buttons you had before.
Make sure to test the customer upgrade path by creating shortcuts with the previous version of your app and testing that they behave correctly with the new versions of your app.
And if your app works in multiple locales, think about localization.
In order to localize your App Intents, all of the strings included in your App Intent should be provided as localized string resources, and you can localize them by providing a corresponding localizable .strings file with those strings.
If you use pluralized strings, you can also use a .strings dict file.
When localizing App Shortcuts, add the strings into a file called AppShortcuts.strings and replace any variables in those strings with ${ } notation.
To summarize, we'd recommend upgrading your custom intents to App Intents to get all the benefits of iOS 16's new features and the new simpler development model of App Intents.
Make sure to add App Shortcuts so people can easily discover and use your app's functionality.
And to learn more about how to put together a great user experience, check out the "Design App Shortcuts" session from WWDC22.
Thank you.
-
-
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.