I need to integrate Siri to make a calls using my app. Siri recognises my app on App Support on Settings. But when Im trying to call some contact saying "call ContactName on MyApp" it just shows me button "open MyApp". IntentHandler.swift contains this function:
class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling {
override func handler(for intent: INIntent) -> Any {
// This is the default implementation. If you want different objects to handle different intents,
// you can override this and return the handler you want for that particular intent.
return self
}
func handle(startAudioCall intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Swift.Void) {
let response: INStartAudioCallIntentResponse
defer {
completion(response)
}
let contacts = (intent.contacts ?? []).filter({ (contact) -> Bool in
return contact.personHandle?.type == .phoneNumber && contact.personHandle?.value != nil
})
// Ensure there is a contact and a handle
guard contacts.count > 0 else {
response = INStartAudioCallIntentResponse(code: .failure, userActivity: nil)
return
}
let userActivity = NSUserActivity(activityType: "INStartAudioCallIntent")
response = INStartAudioCallIntentResponse(code: .continueInApp, userActivity: userActivity)
completion(response)
}
func resolveContacts(forStartAudioCall intent: INStartAudioCallIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
var resolutionResults = [INPersonResolutionResult]()
if let recipients = intent.contacts {
if recipients.count == 0 {
let response = [INPersonResolutionResult.needsValue()]
completion(response)
return
} else if recipients.count == 1 {
if let recipient = recipients.first {
if self.containContact(displayName: (recipient.displayName)) {
resolutionResults.append(INPersonResolutionResult.success(with: recipient))
} else {
resolutionResults.append(INPersonResolutionResult.unsupported())
}
}
} else if recipients.count > 1 {
resolutionResults.append(INPersonResolutionResult.disambiguation(with: recipients))
} else {
resolutionResults.append(INPersonResolutionResult.unsupported())
}
}
completion(resolutionResults)
}
func confirm(startAudioCall intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Swift.Void) {
let userActivity = NSUserActivity(activityType: "INStartAudioCallIntent")
let response = INStartAudioCallIntentResponse(code: .ready, userActivity: userActivity)
completion(response)
}
// MARK: - INSendMessageIntentHandling
// Implement resolution methods to provide additional information about your intent (optional).
func resolveRecipients(forSendMessage intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
if let recipients = intent.recipients {
// If no recipients were provided we'll need to prompt for a value.
if recipients.count == 0 {
completion([INPersonResolutionResult.needsValue()])
return
}
var resolutionResults = [INPersonResolutionResult]()
for recipient in recipients {
let matchingContacts = [recipient] // Implement your contact matching logic here to create an array of matching contacts
switch matchingContacts.count {
case 2 ... Int.max:
// We need Siri's help to ask user to pick one from the matches.
resolutionResults += [INPersonResolutionResult.disambiguation(with: matchingContacts)]
case 1:
// We have exactly one matching contact
resolutionResults += [INPersonResolutionResult.success(with: recipient)]
case 0:
// We have no contacts matching the description provided
resolutionResults += [INPersonResolutionResult.unsupported()]
default:
break
}
}
completion(resolutionResults)
}
}
func resolveContent(forSendMessage intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
if let text = intent.content, !text.isEmpty {
completion(INStringResolutionResult.success(with: text))
} else {
completion(INStringResolutionResult.needsValue())
}
}
// Once resolution is completed, perform validation on the intent and provide confirmation (optional).
func confirm(sendMessage intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
// Verify user is authenticated and your app is ready to send a message.
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
let response = INSendMessageIntentResponse(code: .ready, userActivity: userActivity)
completion(response)
}
// Handle the completed intent (required).
func handle(sendMessage intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
// Implement your application logic to send a message here.
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
completion(response)
}
// Implement handlers for each intent you wish to handle. As an example for messages, you may wish to also handle searchForMessages and setMessageAttributes.
// MARK: - INSearchForMessagesIntentHandling
func handle(searchForMessages intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) {
// Implement your application logic to find a message that matches the information in the intent.
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity)
// Initialize with found message's attributes
response.messages = [INMessage(
identifier: "identifier",
content: "I am so excited about SiriKit!",
dateSent: Date(),
sender: INPerson(personHandle: INPersonHandle(value: "[email protected]", type: .emailAddress), nameComponents: nil, displayName: "Sarah", image: nil, contactIdentifier: nil, customIdentifier: nil),
recipients: [INPerson(personHandle: INPersonHandle(value: "+1-415-555-5555", type: .phoneNumber), nameComponents: nil, displayName: "John", image: nil, contactIdentifier: nil, customIdentifier: nil)]
)]
completion(response)
}
// MARK: - INSetMessageAttributeIntentHandling
func handle(setMessageAttribute intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) {
// Implement your application logic to set the message attribute here.
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self))
let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity)
completion(response)
}
func containContact(displayName: String) -> Bool {
//fetch contacts and check, if exist retun YES else NO
return true
}
}
}
let contacts = (intent.contacts ?? []).filter({ (contact) -> Bool in
return contact.personHandle?.type == .phoneNumber && contact.personHandle?.value != nil
})
// Ensure there is a contact and a handle
guard contacts.count > 0 else {
response = INStartAudioCallIntentResponse(code: .failure, userActivity: nil)
return
}
let userActivity = NSUserActivity(activityType: "INStartAudioCallIntent")
response = INStartAudioCallIntentResponse(code: .continueInApp, userActivity: userActivity)
}
What I'm doing wrong? what I'm missing?
Please check the followings:
Set INStartAudioCallIntent for IntentsSupported in Extension's target.
Confirm INStartAudioCallIntentHandling protocol in IntentHandler class provided by default and implement the following methods:
You may need to share contacts of main applciaiton with extension, use App Grouping. Follow apple document for more information.
Make sure extension target is supporting your device OS.