##SiriKit 有關介紹

引言

  • 在6月14日凌晨的WWDC2016大會上,蘋果提出iOS10是一次里程碑并且推出了十個新特性,homekit、messageapp等等,大部分是基于iPhone原生應用的更新。其中最大的亮點之一是Siri的接口開放,在iOS10中提供了SiriKit框架在用戶使用Siri的時候生成INExtension對象來告知我們的應用,我們可以通過SiriKit提供的API展示給用戶更多的內容。
  • Siri通過語言處理系統對用戶發出的對話請求進行解析之后生成一個用來描述對話內容的Intents事件,然后通過SiriKit框架分發給集成框架的應用程序以此來獲取應用的內容,比如通過文字匹配查找應用聊天記錄、聊天對象等功能,此外還支持為用戶使用蘋果地圖時提供應用內置服務等功能。

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
  • 獲取詞匯邏輯


    siri_cihui.png

    從詞匯中可以看到intent(暫且翻譯成意圖?)對應著siri給我們的響應,這是app通過處理intent對應的reslove,confirm,handle來做相關響應。

intents

1.intents說明

  • Action to be performed 定義將要響應的動作,即reslove,confirm,handle
  • Zero-to-many parameters 意圖會有對應的參數來響應某些事件
  • Classified into a domain 意圖劃分的種類

Siri通過Intents extension的擴展方式和我們的應用進行交互,其中INExtension扮演著Intents extension擴展中直接協同Siri共同響應用戶的角色。當我們實現了Intents extension擴展并產生了一個Siri請求事件時,Intents事件的處理過程分Resolve、Confirm和Handle三個步驟。

2.LifeCycle for an intent

一個intent的完整周期如下圖:

siri_life.png
  • Resolve階段。在Siri獲取用戶的語音輸入之后,生成一個INIntent對象,將語音中的關鍵信息提取出來并且填充對應的屬性,該對象會傳遞給我們設置好的INExtension子類對象進行處理,根據子類遵循的不同protocol來選擇不同的解決方案。在上一個階段通過handler(for intent:)返回了處理intent的對象,此階段會依次調用confirm打頭的實例方法來判斷Siri填充的信息是否完成。
    resolve階段用戶大致分為以下說明階段:

助SIri明白用戶的含義
影響Siri的行為

提供resolution response
successWithResolvedPerson:成功找到匹配的人
disambiguationWithPeopleToDisambiguate:還需要挑選
confirmationRequiredWithPersonToConfirm:還需要確認下
needMoreDetailsForPerson:還需要更具體的信息,需要Siri進行詢問
unsupportedWithReason:無法使用指定值
needsValue:需要某些必需值
notRequired:應用并沒有要求某些值

  • Confirm階段。確認信息。檢查必要的狀態等。Siri進行最后的處理階段,生成答復對象,并且向此intent對象確認處理結果。

告訴Siri預期結果
檢查必要的狀態
提供Intent response
Siri提供必要的確認提示,參考如下連圖例

siri3_confirm.png
siri_confirm2.png
  • Handle階段:在Confirm方法執行完成之后,然后顯示結果給用戶看

    執行請求操作
    提供有關結果足夠精確的信息
    如果結果耗時的話還可提供loading

siri_handle.png

實現一個Siri Kit應用

  • 升級到Xcode8,一臺升級到iOS10的測試設備
  • Intents extension : resolve、confirm、handle流程
    新建extension如下圖:


    siri_ex2.png

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


siri_info2.png

上圖中IntentsSupported是指你的擴展支持的intent類型,如果你的代碼想支持某種intent必須在這里配置。
IntentsRestrictedWhileLocked是指在鎖屏狀態下能用siri喚起的intent,如果你想在鎖屏下能喚起siri的擴展功能必須配置。


siri_info.png

創建之后,查看plist文件
  • 1.增加xxxintent
  • 2.NSExtensionPrincipalClass,這里必須在plist聲明,它是INExtension的子類,INIntentHandleProviding,handleForIntent,handleClass must conform to specific intent handling protocol等,詳細說明參見Intents Domains
    主項目plist 增加NSSiriUsageDescription 這個是請求Siri權限時提示的文案
    使用Siri時,用戶必須說出App的名字,也就是Bundle display name
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))
        }
    }

  • Intents UI extension 提供界面自定義等內容
    通常確認界面的UI蘋果會提供默認的樣式,默認的樣式如下圖:
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)
    }

  • Embedded frameworks
    由于你的程序是extension,因此你的siri擴展可能會和你的應用有數據共享,而且可能會有同樣的邏輯代碼,因此apple建議相關業務的邏輯代碼可用framwork的形式,這樣擴展和宿主app都可以使用。

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 關于SiriKit 在6月14日凌晨的WWDC2016大會上,蘋果提出iOS10是一次里程碑并且推出了十個新特性,...
    sindri的小巢閱讀 22,697評論 40 79
  • 概覽 最新的WWDC2016大會上,蘋果提出iOS10并推出了十個新特性,homekit、messageapp等等...
    cuagain閱讀 2,249評論 0 5
  • 介紹SiriKit SiriKit是讓你的內容通過Siri展示的一個框架庫。當用戶向Siri請求特別類型的服務時,...
    孢子菌閱讀 4,358評論 1 6
  • 在這里放出原文鏈接地址 Part 3.1: 分析與操作 Intents Intents Extension 的的入...
    李國安閱讀 1,366評論 0 4
  • 一、SiriKit介紹 Siri是一款蘋果 iOS 系統提供的智能語音助手軟件,它的全名是 Speech Inte...
    火星抄手閱讀 5,645評論 15 19