After you've made sure that everything you need to eventually handle the intent is in place, you must confirm this to Siri. Every intent handler has a confirm method. The signature might vary, but there is always some form of confirmation in place. Refer to the documentation for the intent you're handling to confirm which method you're expected to implement. When you're sending messages, the confirmation method is confirm(sendMessage:completion:).
We can make this confirmation step as complex as we desire. For example, we could check whether a message is too long, contains forbidden content, or virtually anything else. Most commonly, you'll want to make sure that the user is authenticated and allowed to send a message to the recipient.
Again, it's completely up to your best judgment to determine which preconditions apply to your extension. The important takeaway for the confirm method is that you're expected to make sure that everything is in place to smoothly perform the action later.
Let's look at an example of a confirmation implementation to see some of the possible outcomes of the confirmation step:
func confirm(sendMessage intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
guard let user = User.current(), user.isLoggedIn else {
completion(INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: nil))
return
}
guard MessagingApi.isAvailable else {
completion(INSendMessageIntentResponse(code: .failureMessageServiceNotAvailable, userActivity: nil))
return
}
completion(INSendMessageIntentResponse(code: .ready, userActivity: nil))
}
The preceding implementation checks whether a current user is available, and whether they are logged in or not. Also, the availability of the API that will eventually handle the message sending is checked. Note that these two classes don't exist in the example project and they should be defined by you if you decide to go with this confirmation approach. These classes simply serve as placeholder examples to demonstrate how confirmation of an intent works.
If we don't have a logged in user, we launch the app. If we don't have a messaging API available, we return an error message that reflects the fact that the service is not available. Every intent has their own set of response codes. Refer to the documentation for the intent you're handling to find the relevant response code and decide which ones are appropriate to handle in your extension.
If a user must be taken to your app in order to log in, for example, Siri will automatically create a user activity that's passed to AppDelegate in your application. You must implement application(_:continue:restorationHandler:) to catch and continue the user activity. Just as when we used user activities with Spotlight, it's important that you take the shortest path possible to resume and handle the user activity.
A user activity that's created by Siri has its interaction property set. This property contains an INInteraction object that reflects the action the user attempts to complete using Siri. A good implementation will fulfill this interaction as soon as possible inside of the app. It's also possible to create your own user activity if you want to add custom information that Siri doesn't pass on. If you want to do this, you should pass your custom user activity to the INSendMessageIntentResponse initializer.
After confirming that everything is in place, it's time to perform the action for the user.