文章分享至我的个人技术博客: 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*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
的一些思路.
工程地址
项目地址: https://github.com/CainRun/iOS-10-Characteristic/tree/master/9.Siri%20Intents