iOS进阶程序员iOS Developer

##SiriKit 有关介绍

2016-06-24  本文已影响1347人  青花瓷的平方

引言

SiriKit六类服务

sirikit 服务 对应的INintent
语音和视频通话 VoIP calling INStartVideoCallIntent、INStartAudioCallIntent
发送消息 Messaging INSendMessageIntent
收款或者付款 Payments INSendPaymentIntent、INRequestPaymentIntent
图片搜索 Photo search INSearchForPhotosIntent
管理锻炼 Workouts INEndWorkoutIntent、INPauseWorkoutIntent 、INStartWorkoutIntent 、 INResumeWorkoutIntent 、INCancelWorkoutIntent
行程预约 Ride booking INRequestRideIntent、INGetRideStatusIntent、 INListRideOptionsIntent、 INGetRideStatusIntent

更加详细的说明参见Intents Domains
也就是说当我们使用sirikit的时候,可以使用以上列表对应的六种服务,比如说你的应用是联系人可以发送消息,这时候你就可以使用INSendMessageIntent服务,在锁屏或者主屏幕唤起siri,然后比方说说出“嘿,siri,在xxx应用上发送一条消息给剑剑”,然后siri就能响应并同时提供回调给你的应用siri extension。具体的流程我们会在下一节举例说明。

Siri执行流程

siri1.png siri2.png

intents

1.intents说明

Siri通过Intents extension的扩展方式和我们的应用进行交互,其中INExtension扮演着Intents extension扩展中直接协同Siri共同响应用户的角色。当我们实现了Intents extension扩展并产生了一个Siri请求事件时,Intents事件的处理过程分Resolve、Confirm和Handle三个步骤。

2.LifeCycle for an intent

一个intent的完整周期如下图:

siri_life.png

助SIri明白用户的含义
影响Siri的行为

提供resolution response
successWithResolvedPerson:成功找到匹配的人
disambiguationWithPeopleToDisambiguate:还需要挑选
confirmationRequiredWithPersonToConfirm:还需要确认下
needMoreDetailsForPerson:还需要更具体的信息,需要Siri进行询问
unsupportedWithReason:无法使用指定值
needsValue:需要某些必需值
notRequired:应用并没有要求某些值

告诉Siri预期结果
检查必要的状态
提供Intent response
Siri提供必要的确认提示,参考如下连图例

siri3_confirm.png siri_confirm2.png siri_handle.png

实现一个Siri Kit应用

通常SiriUI也会配置一起创建,入后配置info.plist文件


siri_info2.png

上图中IntentsSupported是指你的扩展支持的intent类型,如果你的代码想支持某种intent必须在这里配置。
IntentsRestrictedWhileLocked是指在锁屏状态下能用siri唤起的intent,如果你想在锁屏下能唤起siri的扩展功能必须配置。


siri_info.png
创建之后,查看plist文件 sendmessage.png

以发送消息为例:当siri第一次确认的时候,需要应用授权,授权代码和提示如下图:

siri_auth.png

具体intent的声明周期代码参考苹果官方demo,代码示例如下:

// MARK: 1. Resolve
    func resolveRecipients(forSendMessage intent: INSendMessageIntent, with completion: ([INPersonResolutionResult]) -> Swift.Void) {
        
        
        if let recipients = intent.recipients {
            var resolutionResults = [INPersonResolutionResult]()
            
            for recipient in recipients {
                let matchingContacts = UCAddressBookManager().contacts(matchingName: recipient.displayName)
                
                switch matchingContacts.count {
                    case 2 ... Int.max:
                        // We need Siri's help to ask user to pick one from the matches.
                        let disambiguationOptions: [INPerson] = matchingContacts.map { contact in
                            return contact.inPerson()
                        }

                        resolutionResults += [INPersonResolutionResult.disambiguation(with: disambiguationOptions)]
                        
                    case 1:
                        let recipientMatched = matchingContacts[0].inPerson()
                        resolutionResults += [INPersonResolutionResult.success(with: recipientMatched)]
                        
                    case 0:
                        resolutionResults += [INPersonResolutionResult.unsupported(with: INIntentResolutionResultUnsupportedReason.none)]
                    
                    default:
                        break
                }
            }
            
            completion(resolutionResults)
            
        } else {
            // No recipients are provided. We need to prompt for a value.
            completion([INPersonResolutionResult.needsValue()])
        }
    }
        
    func resolveContent(forSendMessage intent: INSendMessageIntent, with completion: (INStringResolutionResult) -> Swift.Void) {
        if let text = intent.content where !text.isEmpty {
            completion(INStringResolutionResult.success(with: text))
        }
        else {
            completion(INStringResolutionResult.needsValue())
        }
    }
    
    // MARK: 2. Confirm
    func confirm(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Swift.Void) {
        
        if UCAccount.shared().hasValidAuthentication {
            completion(INSendMessageIntentResponse.init(code: INSendMessageIntentResponseCode.success, userActivity: nil))
        }
        else {
            // Creating our own user activity to include error information.
            let userActivity = NSUserActivity.init(activityType: String(INSendMessageIntent))
            userActivity.userInfo = [NSString(string: "error"):NSString(string: "UserLoggedOut")]
            
            completion(INSendMessageIntentResponse.init(code: INSendMessageIntentResponseCode.failureRequiringAppLaunch, userActivity: userActivity))
        }
    }
    
    // MARK: 3. Handle
    func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Swift.Void) {
        if intent.recipients != nil && intent.content != nil {
            // Send the message.
            let success = UCAccount.shared().sendMessage(intent.content, toRecipients: intent.recipients)
            completion(INSendMessageIntentResponse.init(code: success ? .success : .failure, userActivity: nil))
        }
        else {
            completion(INSendMessageIntentResponse.init(code: INSendMessageIntentResponseCode.failure, userActivity: nil))
        }
    }

style_default.png

但是如果你想自定义UI,如下图所示,你就必须配置Intents UI extension,在MainInterface.storyboard配置相关UI,然后在对应的控制器中配置config函数。

style_custom.png

参考configs函数如下:

func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
        var size: CGSize
        
        // Check if the interaction describes a SendMessageIntent.
        if interaction.representsSendMessageIntent {
            // If it is, let's set up a view controller.
            let chatViewController = UCChatViewController()
            chatViewController.messageContent = interaction.messageContent

            let contact = UCContact()
            contact.name = interaction.recipientName
            chatViewController.recipient = contact
            
            switch interaction.intentHandlingStatus {
                case INIntentHandlingStatus.unspecified, INIntentHandlingStatus.inProgress,INIntentHandlingStatus.ready:
                    chatViewController.isSent = false
                case INIntentHandlingStatus.done:
                    chatViewController.isSent = true
            }
            
            present(chatViewController, animated: false, completion: nil)
            
            size = desiredSize
        }
        else {
            // Otherwise, we'll tell the host to draw us at zero size.
            size = CGSize.zero
        }
        
        completion(size)
    }

参考

上一篇 下一篇

猜你喜欢

热点阅读