Session 211 Introduction to Siri Shortcuts
Session 214 Building for Voice with Siri Shortcuts
在iOS 12中,Siri可以在应用外调用应用功能,有三种途径:Siri建议、个性化短语和苹果官方Shortcuts应用(还未上架),以此来使得Siri变得更智能。
前言
APP可以通过贡献Siri Shortcuts来将APP的能力贡献给Siri,Siri会通过学习来在一定时刻展示此刻相关的shortcut。 展现内容包括:
- 主标题
- 副标题
- 图片
- suggestedInvocationPhrase
展现区域包括:
- Lock Screen Siri Suggestions
- Spotlight Siri Suggestions
- Siri Watch Face
另外,用户也可以通过Siri Voice主动触发shortcut。
同时,创建的shortcut应当满足:
- 方便用户使用APP的核心功能
- 用户感兴趣的内容
- 任何时候都可以响应
贡献Shortcut
Siri Shortcuts的贡献方式有两种:NSUerActivity
和Intent
NSUserActivity
通过NSUserActivity
贡献的shortcut是用户的操作行为,与Core Spotlight中的索引和Handoff相关。 首先需要在Info.plist
中声明NSUserActivityTypes
<key>NSUserActivityTypes</key>
<array>
<string>com.myapp.name.my-activity-type</string>
</array>
复制代码
之后即可根据操作生成对应的NSUserActivity
let userActivity = NSUserActivity(activityType: "com.myapp.name.my-activity-type")
userActivity.isEligibleForSearch = true // 贡献的userActivity必须可检索的内容
userActivity.isEligibleForPrediction = true // 如果之前实现过Spotlight或Handoff,设置此属性即可贡献userActivity给Siri
userActivity.title = "Activity"
userActivity.userInfo = ["key": "value"]
userActivity.suggestedInvocationPhrase = "Let's do it"
let attributes = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
let image = UIImage(named: "myImage")!
attributes.thumbnailData = image.pngData()
attributes.contentDescription = "Subtitle"
userActivity.contentAttributeSet = attributes
viewController.userActivity = userActivity
复制代码
可以看到,如果之前实现过Spotlight或Handoff,贡献NSUserActivity
给Siri还是非常方便的,只需要设置isEligibleForPrediction
为true
即可。Siri会在合适的时机将shortcut显示在锁屏界面和Spotlight界面的Siri Suggestions中。可以在系统设置的开发者选项中打开测试选项。 用户点击shortcut的处理和Spotlight和Handoff的处理方式相同:
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.activityType == "com.myapp.name.my-activity-type" {
// 与Spotlight和Handoff处理入口相同
}
}
复制代码
Intent
通过Intent
贡献的shortcut是不启动APP不通过交互行为即可以直接运行的功能,并且可以对运行的结果给出响应反馈。Intent
还可以对特定的运行功能所需参数进行行为预测。 在工程中新建一个SiriKit Intent Definition File
,点击‘+’新建一个自定义的Intent
,然后添加参数。之后在Shortcut Type中添加需要用的参数,并且定义在shortcut中的显示内容。注意每一个shortcut type中使用的参数组合不同,Siri预测使用的组合也不同,合理使用参数组合可以提高Siri展示的命中率。 Xcode会自动为定义的Intent
生成对应的类,然后通过INInteraction
来贡献给Siri。应当注意,如果Intent
是在framework中使用时(推荐使用),只在该framework中生成即可,否则需要在每个target中都生成对用的类。具体可以在Intent
文件的Inspector
中设置。
let intent = GreetingIntent()
intent.fullname = "Alex"
intent.age = 26
let interaction = INInteraction(intent: intent, response: nil)
interaction.identifier = "com.myapp.shortcuts.greeting.alex"
interaction.groupIdentifier = "com.myapp.shortcuts.greeting"
interaction.donate { (error) in
// 错误处理
}
复制代码
用户点击shortcut的处理入口与NSUserActivity
方式相同
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if userActivity.activityType == "GreetingIntent",
let intent = userActivity.interaction?.intent as? GreetingIntent {
// 此时intent中有传递的参数可以处理
}
}
复制代码
Extension
在出现的shortcut上进行3D-touch操作后,可以根据所新建的Intent
的Category
出现响应操作。 新建一个Intents Extension的Target,并实现IntentHandler中的confirm(optional)
和handle
。这两个方法都是否则响应用户操作(此时APP并未启动),对应使用Intent
中Response
,可以设置一些property
和成功失败的模板,其中模板可以使用所定义的property
。confirm
用于在handle
之前确认操作是否可以被响应,在confirm
中ready
后可流转至handle
。
func confirm(intent: GreetingIntent, completion: @escaping (GreetingIntentResponse) -> Void) {
if intent.fullname == "Alex" {
completion(GreetingIntentResponse(code: .ready, userActivity: nil))
} else {
completion(GreetingIntentResponse.wrong(name: intent.fullname!))
}
}
func handle(intent: GreetingIntent, completion: @escaping (GreetingIntentResponse) -> Void) {
if (intent.age?.intValue)! > 25 {
completion(GreetingIntentResponse.success(name: intent.fullname!))
} else {
completion(GreetingIntentResponse(code: .failure, userActivity: nil))
}
}
复制代码
删除贡献
所贡献的内容已经被用户废弃,为了更好的保护用户的隐私,需要从系统中删除贡献。同时,当shortcut对应的操作不再支持后,也需要删除贡献。
###NSUserActivity
NSUserActivity
贡献的shortcut有两类:持久化Activity和Spotlight索引Activity。
- 持久化Activity可以使用
deleteSavedUserActivities(withPersistentIdentifiers:completionHandler:)
和deleteAllSavedUserActivities(completionHandler:)
来删除 - Spotlight索引Activity则需要通过删除索引的方式实现。具体可调用
deleteSearchableItems(withIdentifiers:completionHandler:)
、deleteSearchableItems(withDomainIdentifiers:completionHandler:)
和deleteAllSearchableItems(completionHandler:)
Intent
Intent
贡献的shortcut可以通过INInteraction
的类方法来删除,具体包括:
class func delete(with identifiers: [String], completion: ((Error?) -> Void)? = nil)
class func delete(with groupIdentifier: String, completion: ((Error?) -> Void)? = nil)
class func deleteAll(completion: ((Error?) -> Void)? = nil)
添加到Siri Voice
可以不贡献shortcut到系统而直接录入个性化短语,录入的shortcut可以是NSUserActivity
和Intent
let userActivity = NSUserActivity(activityType: "com.baidu.shortcuts.activity")
userActivity.suggestedInvocationPhrase = "个性化短语"
let shortcut = INShortcut(userActivity: userActivity)
// let intent = GreetingIntent()
// let shortcut = INShortcut(intent: intent)
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.delegate = self
present(viewController, animated: true)
复制代码