SiriKit 教程 Part 1:在 iOS 10 里集成 Siri

原文鏈接 http://jamesonquave.com/blog/adding-siri-to-ios-10-apps-in-swift-tutorial/
作者 Jameson Quave
原文日期 2016-06-14
譯者 Crystal Sun

這篇教程寫于 2016 年 6 月 13 日,使用 Xcode 8 Beta 1 和 Swift 3.0 toolchain(工具鏈)。

下載 Xcode 8,配置 iOS 10 和 Swift 3

如果你還沒有下載 Xcode 8 Beta 1,請到這里下載。

(可選)命令行編譯

不需要改變什么設(shè)置就能夠加入 Swift 3.0 工具鏈,除非你想用命令行編譯工程。如果你想使用這個(gè)功能,先打開 Xcode beta,然后從頂部菜單欄中選擇 Xcode > Preferences,接著選擇 Location tab,在頁面的底部,你會看到 “Command Line Tool” 這行設(shè)置,請?jiān)谶@里選擇 Xcode 8.0。

現(xiàn)在,在 Terminal 使用命令行找到工程所在的文件夾,調(diào)用 xcodebuild 命令行就可以編譯工程了。

(可選)移植現(xiàn)有的 Swift 2 應(yīng)用

如果你想對一個(gè)已使用 Swift 2.0 開發(fā)的工程引入 Siri 功能,需要點(diǎn)擊工程,選擇 Build Settings,在 Swift Compiler - Version 下面,找到 Use ?Legacy Swift Language Version 選項(xiàng),設(shè)置成 No。這會造成編譯器報(bào)錯,然后你可以根據(jù)這些報(bào)錯信息來修改代碼,推薦你使用這個(gè)設(shè)置來跟進(jìn)更新代碼,以適應(yīng) Swift 不斷進(jìn)化的語義。

開始使用 SiriKit

首先,在你的 App(或者是新建一個(gè) single-view Swift 模板工程),點(diǎn)擊頂部的工程,然后點(diǎn)擊左側(cè)下方的 + 按鈕,在這里

(譯者注:我在這里添加了一張圖片,能夠說的更明白),彈出窗口,選擇 iOS > Application Extension,接著選擇 Intents Extension。

這樣就給工程添加了一個(gè)新的 intent,用于監(jiān)聽 Siri 的命令。其中的 Product Name 應(yīng)該和你的工程文件名字相似,比如,你的 App 名為 MusicMatcher,你可以把這個(gè) intent 的名字命名為 MusicMatcherSiriIntent。一定要選中 Include UI Extension 選項(xiàng),我們之后會用到,這也是添加額外擴(kuò)展的最簡單的方法。


我剛剛創(chuàng)建了兩個(gè)新的 target,你能從工廠的文件層級上看出來。找到 Intent 文件夾下的 IntentHandler.swift 文件,看一下這里面的樣本代碼。默認(rèn)會提供一些示例代碼,允許用戶說一下諸如“使用 MusicMatcher 開始鍛煉”的命令,MusicMatcher 是 App 的名字。

運(yùn)行模板應(yīng)用

這個(gè)時(shí)候最好編譯一下代碼,然后在 iOS 真機(jī)上試一下命令。繼續(xù),編譯應(yīng)用的 target,從 Scheme 下拉菜單里選擇 MusicMatcher,然后選擇真機(jī),點(diǎn)擊 Run。

你看你會看到一個(gè)空白的應(yīng)用出現(xiàn),你使用的擴(kuò)展這時(shí)會在后臺加載到設(shè)備的系統(tǒng)文件里,現(xiàn)在點(diǎn)擊 Stop 按鈕來關(guān)閉應(yīng)用。

接下來,找到你的 scheme,選擇 Intent target,點(diǎn)擊 Run。

這時(shí)會出現(xiàn)一個(gè)彈出框,問你需要連接哪個(gè)應(yīng)用,選擇你剛剛運(yùn)行的應(yīng)用:MusicMatcher。這會讓真機(jī)上再次出現(xiàn)這個(gè)應(yīng)用(還是一個(gè)空白的應(yīng)用),不過這次調(diào)試臺(debugger)中會出現(xiàn)連接的 Intent 擴(kuò)展。

現(xiàn)在點(diǎn)擊 home 按鈕回到首屏,或者應(yīng)用可能自己就退出了,因?yàn)槟阏谶\(yùn)行的是 Intent,不是應(yīng)用本身(這不是崩潰?。。。?。

啟用擴(kuò)展

擴(kuò)展都已安裝就位了,但是作為一個(gè) iOS 用戶,仍然需要進(jìn)行 Siri 設(shè)置才能使用擴(kuò)展。點(diǎn)擊測試設(shè)備里的設(shè)置,選擇 Siri 菜單,你會看到 MusicMatcher 出現(xiàn)在清單里,激活允許 MusicMatcher 使用 Siri。

測試我們第一個(gè) Siri 命令

嘗試一下 Siri 命令,長按 Home 鍵或者說出“Hey Siri”來激活Siri。(當(dāng)然需要你已經(jīng)激活“Hey Siri”功能)

試一下命令,比如“使用 MusicMatcher 開始鍛煉”。

“對不起,你需要在應(yīng)用里繼續(xù)”

如果你像我一樣遇到了這樣的錯誤信息:“Sorry, you'll need to continue in the app.”(不知道什么原因,偶爾地這不算是一個(gè)問題,什么鬼?)

在 console 你可能會看到類似的信息:(這原文里的代碼還有各種顏色,請校對定稿的時(shí)候留意一下)

dyld: Library not loaded: @rpath/libswiftCoreLocation.dylib
  Referenced from: /private/var/containers/Bundle/Application/CC815FA3-EB04-4322-B2BB-8E3F960681A0/LockScreenWidgets.app/PlugIns/JQIntentWithUI.appex/JQIntentWithUI
  Reason: image not found
Program ended with exit code: 1

我們還需要在工程里添加 CoreLocation 庫,確保能夠復(fù)制我們編譯過 Swift 代碼。(復(fù)制編譯的代碼?感覺翻譯的不對)

再次選擇工程根目錄,選擇 MusicMatcher target。在 General 底下找到 Linked Frameworks and Libraries。點(diǎn)擊 + 按鈕,添加 CoreLocation.framework?,F(xiàn)在可以再次編譯在真機(jī)上運(yùn)行,接著照著上面相同的步驟再次編譯運(yùn)行 intent target。

最后,從手機(jī)桌面激活 Siri。

“Hey Siri!”
“Start my workout using MusicMathcer”(這應(yīng)該是固定的命令,換成中文就不能用了吧)

Siri 這時(shí)候應(yīng)該會回應(yīng):“OK.exercise started on MusicMathcer”(OK,開始用 MusicMathcer 鍛煉身體),會出現(xiàn)一個(gè) UI 界面說 “Workout Started”(鍛煉開始)

它是如何工作的呢?

模板中的 IntentHandler 類使用了一長串的協(xié)議:

首先最主要的就是 INExtension,允許我們一開始就把類當(dāng)作一個(gè) intent extension 來用。剩下的協(xié)議都是 intent handler 類型,在類里能夠回調(diào):

INStartWorkoutIntentHandling
INPauseWorkoutIntentHandling
INResumeWorkoutIntentHandling
INCancelWorkoutIntentHandling
INEndWorkoutIntentHandling

第一個(gè)就是我們剛剛測試過的,INStartWorkoutIntentHandling。

按住 Command 鍵鼠標(biāo)點(diǎn)擊這些協(xié)議的名字,會看到蘋果文檔:

/*!
 @brief Protocol to declare support for handling an INStartWorkoutIntent 
 @abstract By implementing this protocol, a class can provide logic for resolving, confirming and handling the intent.
 @discussion The minimum requirement for an implementing class is that it should be able to handle the intent. The resolution and confirmation methods are optional. The handling method is always called last, after resolving and confirming the intent.
 */

換句話說,這協(xié)議告訴 SiriKit 我們準(zhǔn)備處理英文句子 “Start my workout with AppName Here.”

根據(jù)用戶使用的不同語言,這句話翻譯成對應(yīng)的語言,不過最終的目的都是開始鍛煉。INStartWorkoutIntentHandling 協(xié)議調(diào)用幾個(gè)方法,在示例代碼里執(zhí)行這些方法。如果你想創(chuàng)建一個(gè)鍛煉應(yīng)用,我會讓你更多地了解他們,不過我更愿意做的是,在本教程的剩余部分,添加一個(gè)新的 intent handler,來處理發(fā)送消息。

加一個(gè)新的信息 Intent

現(xiàn)在我們確信剛剛的設(shè)置工作完成了,讓我們繼續(xù)往下走,添加一個(gè)新的 intent 類型,用于發(fā)送消息,這里的文檔說明了下列信息:

Send a message
Handler:INSendMessageIntentHandling protocol
Intent:INSendMessageIntent
Response:INSendMessageIntentResponse

在類里添加 INSendMessageIntentHandling 協(xié)議,首先要明確,我們把它添加到類協(xié)議清單里,也就是在 IntentHandler.swift 文件里。由于實(shí)際上我不想使用這些 intent,所以我會刪除它們,只留下這一個(gè):

class IntentHandler: INExtension, INSendMessageIntentHandling {
    ...

如果這時(shí)候編譯,是不會通過編譯的,因?yàn)槲覀冞€需要實(shí)現(xiàn)一些遵守 INSendMessageIntentHandling 協(xié)議所必需的方法。

另外,如果你需要核對具體是哪些方法,只需要按住 Command 鍵然后鼠標(biāo)點(diǎn)擊 INSendMessageIntentHandling,然后看一下哪些方法前面沒有 optional 關(guān)鍵詞即可。

在這里,我們發(fā)現(xiàn)只有一個(gè)必需要有的方法:

/*!
 @brief handling method
 
 @abstract Execute the task represented by the INSendMessageIntent that's passed in
 @discussion This method is called to actually execute the intent. The app must return a response for this intent.
 
 @param  sendMessageIntent The input intent
 @param  completion The response handling block takes a INSendMessageIntentResponse containing the details of the result of having executed the intent
 
 @see  INSendMessageIntentResponse
 */
public func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Swift.Void)

連接新的協(xié)議

回到 IntentHandler.swift 文件,添加一行分隔符(借助 jump bar,在導(dǎo)航查找代碼時(shí)這個(gè)分隔符會非常有用)

// MARK: - INSendMessageIntentHandling

在 MARK 底下,我們實(shí)現(xiàn)方法。我發(fā)現(xiàn) Xcode 8 非常有幫助,主要敲擊方法名字的開頭,剩下的都交給自動補(bǔ)全來完成了,選擇對應(yīng)的方法。

在 handerl 里,我們需要創(chuàng)建一個(gè) INSendMessageIntentResponse,來回調(diào)閉包。先假設(shè)所有的信息發(fā)送都很成功,在 INSendMessageIntentResponse 里返回一個(gè)用戶活動的成功值,和模板中如何實(shí)現(xiàn)的非常類似。還需要添加一個(gè) print 方法,當(dāng) handler 方法被 Siri 事件觸發(fā)后我們就能知曉啦:

func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Void) {
    print("Message intent is being handled.")
    let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent))
    let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
    completion(response)
}

把這個(gè) intent 類型添加到 Info.plist

在具備處理 INSendMessageIntent 方法之前,我們需要在 Info.plist 文件里添加一些值,就當(dāng)作是應(yīng)用的授權(quán)吧。

intent 的 Info.plist 文件里,找到并擴(kuò)展 NSExtension 鍵。接著擴(kuò)展 NSExtensionAttributes,然后是 IntentsSupported,我們需要給 INSendMessageIntent 新添加一行,允許應(yīng)用處理信息 intents。

測試新的 intent

現(xiàn)在我們已經(jīng)設(shè)置好了新的 intent,來測試一下。記住,你必須先編譯 App,在真機(jī)上運(yùn)行,接著運(yùn)行擴(kuò)展進(jìn)行調(diào)試,如果你不這樣做,擴(kuò)展要么不會工作,要么不會在 Xcode 的控制臺中打印日志。

調(diào)用 Siri 的intent,你現(xiàn)在可以看到會出現(xiàn)一個(gè)新的信息窗口,這個(gè)窗口目前還是空的,畢竟我們還沒有給應(yīng)用編寫什么邏輯,我們需要實(shí)現(xiàn)剩下的調(diào)用,還要添加一些信息的邏輯,實(shí)現(xiàn)更好的用戶體驗(yàn)。我們會在 Part 2 (Part 2 已經(jīng)發(fā)布了)里解決這些事情。

本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容