简体   繁体   English

Siri 集成:使用 Siri 进行音频通话?

[英]Siri Integration: Audio call using Siri?

I need to integrate Siri to make a calls using my app.我需要集成 Siri 才能使用我的应用程序拨打电话。 Siri recognises my app on App Support on Settings. Siri 在“设置”上的“应用支持”上识别出我的应用。 But when Im trying to call some contact saying "call ContactName on MyApp" it just shows me button "open MyApp".但是当我试图打电话给一些联系人说“在 MyApp 上调用 ContactName”时,它只显示我按钮“打开 MyApp”。 IntentHandler.swift contains this function: IntentHandler.swift 包含这个函数:

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: "sarah@example.com", 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.为扩展目标中的 IntentsSupported 设置 INStartAudioCallIntent。

在此处输入图片说明

Confirm INStartAudioCallIntentHandling protocol in IntentHandler class provided by default and implement the following methods:确认 IntentHandler 类默认提供的 INStartAudioCallIntentHandling 协议,实现如下方法:

-(void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent
                          withCompletion:(void (^)(NSArray<INPersonResolutionResult *> *resolutionResults))completion{
    NSArray<INPerson *> *recipients = intent.contacts;
    NSMutableArray<INPersonResolutionResult *> *resolutionResults = [NSMutableArray array];
    if (recipients.count == 0) {
        completion(@[[INPersonResolutionResult needsValue]]);
        return;
    }else if(recipients.count==1){
        if ([self contactExist:recipients.firstObject.displayName]) {// check if person contains in contact or not
            [resolutionResults addObject:[INPersonResolutionResult successWithResolvedPerson:recipients.firstObject]];
        }else [resolutionResults addObject:[INPersonResolutionResult unsupported]];
    }else if(recipients.count>1){
        [resolutionResults addObject:[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:recipients]];
    }else{
        [resolutionResults addObject:[INPersonResolutionResult unsupported]];
    }
    completion(resolutionResults);
}

-(void)confirmStartAudioCall:(INStartAudioCallIntent *)intent
                   completion:(void (^)(INStartAudioCallIntentResponse *response))completion{
    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INStartAudioCallIntent class])];
    INStartAudioCallIntentResponse *response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity];
    completion(response);
}

-(void)handleStartAudioCall:(INStartAudioCallIntent *)intent
                  completion:(void (^)(INStartAudioCallIntentResponse *response))completion{
    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INStartAudioCallIntent class])];
    INStartAudioCallIntentResponse *response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp userActivity:userActivity];
    completion(response);
}

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.确保扩展目标支持您的设备操作系统。

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM