作者:Jameson Quave,原文鏈接,原文日期:2016-06-14
譯者:Crystal Sun;校對(duì):Cee;定稿:Channe
這篇教程寫于 2016 年 6 月 13 日,使用 Xcode 8 Beta 1 和 Swift 3.0 toolchain(工具鏈)。
下載 Xcode 8,配置 iOS 10 和 Swift 3
如果你還沒有下載 Xcode 8 Beta 1,請(qǐng)到這里下載。
(可選)通過命令行編譯
除非你想使用命令行編譯,使用 Swift 3.0 的工具鏈并不需要對(duì)項(xiàng)目做任何改變。如果你想的話,打開 Xcode-beta,然后從頂部菜單欄中選擇 Xcode > Preferences,接著選擇 Location,在頁(yè)面的底部,你會(huì)看到「Command Line Tool」這行設(shè)置,請(qǐng)?jiān)谶@里選擇 Xcode 8.0。
現(xiàn)在,在 Terminal 使用命令行找到工程所在的文件夾,調(diào)用 xcodebuild 命令就可以編譯工程了。
(可選)移植現(xiàn)有的 Swift 2 應(yīng)用
如果你想對(duì)一個(gè)已使用 Swift 2.0 開發(fā)的工程引入 Siri 功能,需要點(diǎn)擊工程,選擇 Build Settings,在 Swift Compiler - Version 下面,找到 Use Legacy Swift Language Version 選項(xiàng),設(shè)置成 No。這會(huì)造成編譯器報(bào)錯(cuò),然后你可以根據(jù)這些報(bào)錯(cuò)信息來(lái)修改代碼,推薦你使用這個(gè)設(shè)置來(lái)更新代碼,以適應(yīng) Swift 不斷進(jìn)化的語(yǔ)義。
開始使用 SiriKit
首先,在你的 App(或者是新建一個(gè)單視圖的 Swift 模板工程),點(diǎn)擊頂部的工程,然后點(diǎn)擊左側(cè)下方的 + 按鈕,在這里(譯者注:我在這里添加了一張圖片,能夠說(shuō)的更明白)點(diǎn)擊。

彈出的窗口中,選擇 iOS > Application Extension,接著選擇 Intents Extension。

這樣就給工程添加了一個(gè)新的 intent,用于監(jiān)聽 Siri 的命令。其中的 Product Name 應(yīng)該和你的工程文件名字相似,比如,你的 App 名為 MusicMatcher,你可以把這個(gè) intent 的名字命名為 MusicMatcherSiriIntent。一定要選中 Include UI Extension 選項(xiàng),我們之后會(huì)用到,這也是添加額外擴(kuò)展的最簡(jiǎn)單的方法。
我剛剛創(chuàng)建的兩個(gè)新 target 可以從項(xiàng)目的文件層級(jí)上找到。找到 Intent 文件夾下的 IntentHandler.swift 文件,看一下這里面的樣本代碼。默認(rèn)會(huì)提供一些示例代碼,允許用戶說(shuō)一下諸如「用 MusicMatcher 開始鍛煉」的命令,MusicMatcher 是 App 的名字。
像這樣運(yùn)行示例應(yīng)用
這個(gè)時(shí)候最好編譯一下代碼,然后在 iOS 真機(jī)上試一下命令。繼續(xù),編譯應(yīng)用的 target,從 Scheme 下拉菜單里選擇 MusicMatcher,然后選擇真機(jī),點(diǎn)擊 Run。
你看你會(huì)看到一個(gè)空白的應(yīng)用出現(xiàn),你使用的擴(kuò)展這時(shí)會(huì)在后臺(tái)加載到設(shè)備的系統(tǒng)文件里,現(xiàn)在點(diǎn)擊 Stop 按鈕來(lái)關(guān)閉應(yīng)用。
接下來(lái),找到你的 scheme,選擇 Intent target,點(diǎn)擊 Run。
這時(shí)會(huì)出現(xiàn)一個(gè)彈出框,問你需要連接哪個(gè)應(yīng)用,選擇你剛剛運(yùn)行的應(yīng)用:MusicMatcher。這會(huì)讓真機(jī)上再次出現(xiàn)這個(gè)應(yīng)用(還是一個(gè)空白的應(yīng)用),不過這次調(diào)試臺(tái)(debugger)中會(huì)出現(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)擊測(cè)試設(shè)備里的 Settings,選擇 Siri 菜單,你會(huì)看到 MusicMatcher 出現(xiàn)在清單里,激活允許使用 Siri。
測(cè)試我們第一個(gè) Siri 命令
嘗試一下 Siri 命令,長(zhǎng)按 Home 鍵或者說(shuō)出「Hey Siri」來(lái)激活 Siri(當(dāng)然需要你已經(jīng)激活「Hey Siri」功能)。
試一下命令,比如「使用 MusicMatcher 開始鍛煉」。
「對(duì)不起,你需要在應(yīng)用里繼續(xù)。」
如果你像我一樣遇到了這樣的錯(cuò)誤信息:「Sorry, you'll need to continue in the app.」(不知道什么原因,偶爾會(huì)出現(xiàn)這么一個(gè)問題,什么鬼?)
在控制臺(tái)中你可能會(huì)看到類似的信息:
bash
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 庫(kù),確保能添加到我們編譯過的 Swift 工程中。
再次選擇工程根目錄,選擇 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 MusicMatcher(使用 MusicMatcher 開始鍛煉)」
Siri 這時(shí)候應(yīng)該會(huì)回應(yīng):「OK. exercise started on MusicMatcher(OK,開始用 MusicMatcher 鍛煉身體)」,然后會(huì)出現(xiàn)一個(gè) UI 界面寫著「Workout Started(鍛煉開始)」。
它是如何工作的呢?
模板中的 IntentHandler 類使用了一長(zhǎng)串的協(xié)議:
首先最主要的就是 INExtension,允許我們一開始就把類當(dāng)作一個(gè) intent extension 來(lái)用。剩下的協(xié)議都是 intent handler 類型,在類里能夠回調(diào):
INStartWorkoutIntentHandling
INPauseWorkoutIntentHandling
INResumeWorkoutIntentHandling
INCancelWorkoutIntentHandling
INEndWorkoutIntentHandling
第一個(gè)就是我們剛剛測(cè)試過的,INStartWorkoutIntentHandling。
按住 Command 鍵點(diǎn)擊這些協(xié)議的名字,會(huì)看到蘋果提供的文檔:
/*!
@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.
*/
換句話說(shuō),這協(xié)議告訴 SiriKit 我們準(zhǔn)備處理英文句子「Start my workout with AppName Here.」
這會(huì)根據(jù)用戶使用語(yǔ)言的不同而不同,不過最終的目的都是開始一次鍛煉。INStartWorkoutIntentHandling 協(xié)議調(diào)用的幾個(gè)方法都在示例代碼里實(shí)現(xiàn)了。如果你想創(chuàng)建一個(gè)鍛煉應(yīng)用,你可以自行了解其他的內(nèi)容。不過在這篇教程的剩余部分,我會(huì)添加一個(gè)新的 intent handler,來(lái)處理發(fā)送消息。
添加一個(gè)新的消息 Intent
確認(rèn)應(yīng)用可以完美運(yùn)行后,讓我們繼續(xù),添加一個(gè)新的 intent 類型,用于發(fā)送消息,這里的文檔說(shuō)明了下列信息:
Send a message
Handler:INSendMessageIntentHandling protocol
Intent:INSendMessageIntent
Response:INSendMessageIntentResponse
在類里添加 INSendMessageIntentHandling 協(xié)議。首先要明確,我們把它添加到類協(xié)議清單里,也就是在 IntentHandler.swift 文件里。由于實(shí)際上我不想使用這些 intent,所以我會(huì)刪除它們,只留下這一個(gè):
class IntentHandler: INExtension, INSendMessageIntentHandling {
...
如果這時(shí)候編譯,是不會(huì)通過編譯的,因?yàn)槲覀冞€需要實(shí)現(xiàn)一些遵守 INSendMessageIntentHandling 協(xié)議所必需的方法。
另外,如果你需要核對(duì)具體是哪些方法,只需要按住 Command 鍵然后鼠標(biāo)點(diǎn)擊 INSendMessageIntentHandling,然后看一下哪些方法前面沒有 optional 關(guān)鍵詞即可。
在這里,我們發(fā)現(xiàn)只有一個(gè)必須實(shí)現(xiàn)的方法:
/*!
@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è)分隔符會(huì)非常有用)
// MARK: - INSendMessageIntentHandling
在 MARK 底下,我們來(lái)實(shí)現(xiàn)方法。我發(fā)現(xiàn) Xcode 8 非常有用,通過敲擊方法名字的開始部分,剩下的都能交給自動(dòng)補(bǔ)全來(lái)完成了,然后選擇對(duì)應(yīng)的方法。
在 handler 里,我們需要?jiǎng)?chuàng)建一個(gè) INSendMessageIntentResponse,來(lái)回調(diào)閉包。先假設(shè)所有的信息發(fā)送都很成功,在 INSendMessageIntentResponse 里返回一個(gè)用戶活動(dòng)的成功值,和默認(rèn)模板中的實(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 文件里,找到并點(diǎn)開 NSExtension 鍵。接著點(diǎn)開 NSExtensionAttributes,然后是 IntentsSupported,我們需要給 INSendMessageIntent 新添加一行,允許應(yīng)用處理信息 intents。
測(cè)試新的 intent
現(xiàn)在我們已經(jīng)設(shè)置好了新的 intent,來(lái)測(cè)試一下。記住,你必須先編譯 App,在真機(jī)上運(yùn)行,接著運(yùn)行擴(kuò)展進(jìn)行調(diào)試,如果你不這樣做,擴(kuò)展要么不會(huì)工作,要么不會(huì)在 Xcode 的控制臺(tái)中打印日志。
調(diào)用 Siri 的 intent,你現(xiàn)在可以看到會(huì)出現(xiàn)一個(gè)新的信息窗口,這個(gè)窗口目前還是空的,畢竟我們還沒有給應(yīng)用編寫什么邏輯,我們需要實(shí)現(xiàn)剩下的調(diào)用,還要添加一些信息的邏輯,實(shí)現(xiàn)更好的用戶體驗(yàn)。我們會(huì)在 已經(jīng)發(fā)布的 Part 2 里解決這些事情。
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請(qǐng)?jiān)L問 http://swift.gg。