WWDC 2018:初识Siri Shortcuts

4,502 阅读4分钟

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的贡献方式有两种:NSUerActivityIntent

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还是非常方便的,只需要设置isEligibleForPredictiontrue即可。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操作后,可以根据所新建的IntentCategory出现响应操作。 新建一个Intents Extension的Target,并实现IntentHandler中的confirm(optional)handle。这两个方法都是否则响应用户操作(此时APP并未启动),对应使用IntentResponse,可以设置一些property和成功失败的模板,其中模板可以使用所定义的propertyconfirm用于在handle之前确认操作是否可以被响应,在confirmready后可流转至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可以是NSUserActivityIntent

	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)