文章分享至我的个人技术博客: 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
最后
码字很费脑, 看官赏点饭钱可好
