文章分享至我的個人技術部落格: https://cainluo.github.io/14977885999456.html
Siri
眾所周知Siri
是蘋果爸爸內建在iOS
系統的一個語音助手, 自從在2011年的iPhone 4s
問世之後, Siri
就一直受關注.
但好景不長, 隨著Siri
的功能和許可權太弱了, 慢慢就被人遺忘, 起碼我身邊用iPhone
的小夥伴都會把Siri
給關掉, 按照他們的說法就是可以省電...我也是醉了.
幾年過去後, Siri
終於迎接來了春天, 隨著iOS 10
的推出, 終於給開發者們開放了Siri Kit
, 也開放了Siri Intents Extension
, 國內用的最快的App
依然還是BAT
巨頭的產品, 比如QQ
.
這裡的工程是Objective-C
版本, 想看Swift
版本的, 可以到這裡去檢視.
Siri的服務型別
這裡我簡單的舉一下Siri
目前支援的一些種類, 更加詳細的文件請看官方文件.
Siri服務型別 | Intent種類 |
---|---|
VoIP語音 - VoIP calling | INStartVideoCallIntent、INStartAudioCallIntent |
訊息 - Messaging | INSendMessageIntent |
支付 - Payments | INSendPaymentIntent、INRequestPaymentIntent |
圖片 - Photos | INSearchForPhotosIntent |
健身 - Workouts | INEndWorkoutIntent、INPauseWorkoutIntent 、INStartWorkoutIntent 、 INResumeWorkoutIntent 、INCancelWorkoutIntent |
騎行預約 - Ride booking | INRequestRideIntent、INGetRideStatusIntent、 INListRideOptionsIntent、 INGetRideStatusIntent |
汽車狀態 - Car commands | INSetCarLockStatusIntent、INGetCarPowerLevelStatusIntent、INActivateCarSignalIntent |
車載系統 - CarPlay | INSetAudioSourceInCarIntent、INSetClimateSettingsInCarIntent |
預定餐廳 - Restaurant reservations | INBookRestaurantReservationIntent |
New Project
建立新工程的專案這裡我就忽略了, 直接來看新增Siri Intents Extension
:
這裡注意一下, 我們要把Include UI Extension
也要勾上, 但這個東西會專門開一篇文章去講解.
建立好之後, 我們可以看到Siri Intents Extension
和之前我們遇到的Extension
不太一樣:
還有就是, 我們開啟Siri Intents Extension
的Info.plist
檔案看到IntentsSupported
和IntentsRestrictedWhileLocked
, 那有什麼用呢?
-
IntentsSupported: 我們專案需要支援的
Siri Intents
就放到這裡, 比如我們在工程裡看到的INSendMessageIntent
,INSearchForMessagesIntent
,INSetMessageAttributeIntent
. -
IntentsRestrictedWhileLocked: 在鎖屏狀態下需要鎖定的
Siri Intents
就放到這裡, 比如我們在工程裡看到的INSendMessageIntent
.
SiriKit的流程
關於SiriKit
的流程這裡我就拷貝一下官方的說法:
Siri
和Maps
通過Intents extension
的擴充套件方式和我們的應用進行互動,其中,型別為INExtension
的物件扮演著Intents extension
擴充套件中直接協同Siri
物件共同響應使用者請求的關鍵角色。當我們實現了Intents extension
擴充套件併產生了一個Siri
請求事件時,一個典型的Intent
事件的處理過程中總共有這三個步驟Resolve
、Confirm
和Handle
:
Resolve
階段。在Siri
獲取到使用者的語音輸入之後,生成一個INIntent
物件,將語音中的關鍵資訊提取出來並且填充對應的屬性。這個物件在稍後會傳遞給我們設定好的INExtension
子類物件進行處理,根據子類遵循的不同服務protocol
來選擇不同的解決方案。Confirm
階段。在上一個階段通過handler(for intent:)
返回了處理intent
的物件,此階段會依次呼叫confirm
打頭的例項方法來判斷Siri
填充的資訊是否完成。匹配的判斷結果包括Exactly one match
、Two or more matches
以及No match
三種情況。這個過程中可以讓Siri
向使用者徵求更具體的引數資訊。- 在
confirm
方法執行完成之後,Siri
進行最後的處理階段,生成答覆物件,並且向此intent
物件確認處理結果然後執顯示結果給使用者看。
互動名單
這裡我們首先要建立一個名單, 用來模擬一下傳送訊息的場景:
這裡還有一個NSString
的類別, 用來轉換拼音的:
精確匹配和模糊匹配
回到我們的IntentHandler.m
檔案, 這裡我們要開始寫程式碼了, 我們需要些一個精確的使用者名稱稱匹配和一個模糊的使用者名稱稱匹配:
// 遍歷待匹配選項
for (INPerson *recipient in recipients) {
// Implement your contact matching logic here to create an array of matching contacts
NSMutableArray<INPerson *> *matchingContacts = [NSMutableArray array];
// 待匹配的名稱
NSString *recipientName = recipient.displayName;
NSString *recipientNamePinYin = [recipientName cl_PinYin];
// 精確的匹配到列表裡的使用者
UserList *user = [UserList checkUserWithName:recipientName];
if (user) {
NSLog(@"匹配到精確使用者:%@", user);
// 建立一個匹配成功的使用者
INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userAddress
type:INPersonHandleTypeEmailAddress];
INImage *iconImage = [INImage imageNamed:user.userIcon];
INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle
nameComponents:nil
displayName:recipientName
image:iconImage
contactIdentifier:nil
customIdentifier:nil
aliases:nil
suggestionType:INPersonSuggestionTypeSocialProfile];
// 把匹配成功的使用者記錄下來
[matchingContacts addObject:person];
}
// 如果沒有精確匹配到使用者, 則用模糊匹配
if (matchingContacts.count == 0) {
NSLog(@"沒有匹配到精確使用者:%@", user);
for (UserList *user in [UserList userList]) {
// 匹配使用者的名稱
NSString *userName = user.userName;
NSString *userNamePinYin = [userName cl_PinYin];
if ([recipientName containsString:userName] || [recipientNamePinYin containsString:userNamePinYin]) {
// 建立一個匹配成功的使用者
INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userAddress
type:INPersonHandleTypeEmailAddress];
INImage *iconImage = [INImage imageNamed:user.userIcon];
INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle
nameComponents:nil
displayName:userName
image:iconImage
contactIdentifier:nil
customIdentifier:nil
aliases:nil
suggestionType:INPersonSuggestionTypeSocialProfile];
// 記錄匹配的使用者
[matchingContacts addObject:person];
}
}
}
複製程式碼
注意
注意一下, 雖然我們程式碼寫好了, 但我們還是需要看看工程裡有沒有新增-ObjC
還有就是Siri Intents Extension
和Siri Intents Extension UI
裡有沒有連結好NSString+PinYin.m
和UserList.m
:
不然就會發生"_OBJC_CLASS_$_UserList", referenced from:
錯誤了.
在執行之前一定要到設定 -> Siri -> 開啟Siri
才可以使用, 這裡我是用模擬器, 所以沒法試著發郵件出去:
但是發訊息還是ok
得, 效果:
總結
最後我們來看看額外的一篇文章, 就是企鵝公司是腫麼給QQ適配SiriKit
的一些思路QQ適配 SiriKit.
工程地址
專案地址: https://github.com/CainRun/iOS-10-Characteristic/tree/master/9.Siri%20Intents