SiriKit 初探 —— WWDC 2016 技术赏析

2016 年 9 月 23 - 24 日,由 CSDN 和创新工场联合主办的“MDCC 2016 移动开发者大会• 中国”(Mobile Developer Conference China)将在北京• 国家会议中心召开,来自 iOS、Android、跨平台开发、产品设计、VR 开发、移动直播、人工智能、物联网、硬件开发、信息无障碍10个领域的技术专家将分享他们在各自行业的真知灼见。

目前,MDCC 大会门票正处于 8 折优惠票价阶段,五人以上团购更有每人减免 300元特惠,限量供应(票务详情链接,8 折优惠,欲购从速!


作者简介: 于天航,知乎 iOS 团队负责人。毕业于北京交通大学,今日头条创始员工,后就职于百度。一直在 iOS 领域从事技术研发工作。

写在前面

1983 年,一小部分开发者来到美国加州蒙特瑞(Monterey)见证了第一款苹果公司设计的个人电脑的诞生。有趣的是这场会议并不对外开放,甚至是完全保密的,苹果刻意避开了媒体和公众的视线,与会者甚至要签署严格的保密协议。官方意义上的 WWDC 开始于 1990 年,而对于国内早期的 iOS 开发者来说,对 WWDC 最早的记忆应该是从 2007 年第一代 iPhone 横空出世开始的,到今天已经走过了 9 个年头,iOS 系统的版本号也已经到了两位数。相比于 iOS 7 开始每个 iOS 版本大刀阔斧的革新,今年的 iOS 10 更加专注于对现有功能的改进,最大的亮点无疑是 SiriKit 对开发者开放,本文也着重介绍一下 SiriKit 的设计理念和实践。

SiriKit简介

Siri 是一款苹果 iOS 系统提供的智能语音助手软件,它的全名是 Speech Interpretation and Recognition Interface。用语音和 Siri 交互可以让你实现传送信息、安排会议、拨打电话、查看附近餐厅等功能,并且全程都是 Hand Free 的;你还可以让 Siri 学习你的声纹,然后通过“嘿 Siri”来激活它。

从 2011 年 Siri 第一次以 iOS 内置软件的形式随 iPhone 4s 一同问世之后,苹果一直致力于更新改进以使它更加智能,iOS 的开发者们一直期盼有一天自己的 App 也可以利用到 Siri 带来的好处和便利。终于在 WWDC 2016 上,苹果开放了 Siri 的 API,开发者们可以利用SiriKit将自己的服务提供给用户。苹果为了保护iOS的用户体验,在API的开放上一向非常谨慎,SiriKit也不例外。利用SiriKit开发者目前只能做如下六件事情:

  • 语音和视频通话;
  • 发送消息;
  • 发送或者接收付款;
  • 照片搜索;
  • 打车;
  • 管理健身。

SiriKit 将上述六种行为描述为六种类型的意图(Intents),提供对应的Intent.framework和用于UI展示的IntentUI.framework两个工具包方便开发者实现上述功能。

如果你的应用刚好在这些领域之内,那么恭喜你,可以使用 SiriKit 为应用增加系统级的入口、提升用户体验,并且能够在地图这样的系统应用中使用你的服务(WWDC 两个 Siri 的 Session 中也都提到了这一点),无论你的应用进程是在后台运行,还是已经被 Kill。

为便于描述,本文以一款名为“知了”的 SiriKitDemo 为例进行讲解,“知了”App 是一款发送消息意图类型的 SiriKit App。

SiriKit设计初探

先来看下面一段对话:

你:用知了给 Jon Snow 发一条消息。
Siri:消息的内容是?
你:Winter is coming。

这是 Siri 消息类型意图的典型使用场景。然而用户的行为总是不可确定的,在发送一条消息给 Snow 的时候你也可能会这样说:

你:用知了发送一条消息。
Siri:给谁发?
你:Jon Snow。
Siri:发送的内容是?
你:Winter is coming。

Intent 处理流程

当然还有支付、打车等场景,为了适应各种复杂的交互场景,SiriKit 将每种意图的处理总结为图 1 描述的过程。

SiriKit 初探 —— WWDC 2016 技术赏析_第1张图片

图1 SiriKit 下意图处理过程

从图1中不难看出以下特点。

  • Speech:用户对 Siri 说了一句话,Siri 通过人工智能技术识别用户的意图(Intent);
  • Intent:如果 Siri 发现用户的意图属于已支持的六种行为之一,并且信息内容中包含你的 App,就会把当前的信息内容转发给 App;
  • Action:App 在后台收到这个 Intent 之后开始针对这个 Intent、通过 Siri 向用户进行必要的信息采集、加工、处理,并完成用户的意图。每种意图下采集的信息不尽相同,发送消息需要采集的信息如下:

    • Domain:Messages;
    • Intent:sendMessage;
    • App:ZhiChat;
    • Recipient:Jon Snow;
    • Content:Winter is coming。
  • Response:用户意图处理完成后,Siri 将处理结果(成功或失败)展现给用户。

Intent 的生命周期

SiriKit 将底层的深度学习、CNN(卷积神经网络)等技术封装起来,开发者只需要关注自己如何提供服务,如何满足用户需求。因此 SiriKit 的实现代码大部分是围绕用户意图(Intent)来完成的,在前文所述的过程中,每个意图的生命周期可分成图 2 描述的三个阶段。

SiriKit 初探 —— WWDC 2016 技术赏析_第2张图片

图2 用户意图生命周期的三个阶段

从图2中,我们可以看出以下特点。

  • Resolve:App 处理 Siri 收集到的用户信息并反馈给 Siri。开发者需要针对不同意图实现不同的 Resolve 方法,在 Intent 的生命周期中 Resolve 动作可能发生多次。每个 Resolve 方法执行后都需要反馈处理结果给 Siri。
  • Confirm:这一阶段主要实现以下两件事情。

    • 反馈给 Siri 当前意图期望的结果;
    • 检查完成意图所需要的必要状态,比如:

      1. 云端服务是否可用;
      2. 当前用户是否已登录;
      3. 付款时当前账户是否有足够的余额。
  • Siri 会根据当前信息决定是否展示给用户一个确认窗口,比如付款时的确认窗口或者消息的发送窗口。Confirm 阶段也会出现多次,根据实际经验经验每次Resolve方法调用后都会调用一次 Confirm 方法。

  • Handle:在收集到足够信息之后,处理用户的意图并展示结果。通常情况下, handle 方法只会调用一次。如果这个处理过程中有网络请求,则需要提供处理状态的 UI,并在尽可能短的时间内完成处理并将结果反馈给 Siri。

SiriKit实战

引入SiriKit

和通知中心插件、Watch 扩展一样,SiriKit 也是通过 Extensions 的方式与主 App 结合起来。SiriKit 提供了两个新的扩展:

  • Intents Extension;
  • Intents UI Extension。

同时,为了让 App 更好地支持特定意图的语义识别,App 可以在自定义词表中提供一些 App 相关的术语和短句,这一点在后面的小节会有详细说明。

在 Xcode 8 中点击 TARGETS 界面左下角的加号新建一个 Target,可以看到新版本的 Xcode 中苹果为我们提供了很多新的 extension 模板,选择 Intents
Extension(如图 3 所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第3张图片

图3 选择Intents Extension

点击下一步,填写 Product Name,选择语言版本。注意,这里有个“Include UI Extension”的选项,勾选之后会自动创建一个“Intents UI Extension”的 Target 用于 Siri 中的界面展示(如图4所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第4张图片

图4 勾选Include UI Extension选项

点击完成。Xcode 8 会生成两个 Target 和对应文件夹(如图5所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第5张图片

图5 Xcode 8 生成两个 Target 对应文件夹

在主 App 支持 Siri

在 Capabilities 中打开 Siri 的开关,如果使用 Xcode 8 并且 App 已经设置为自动管理 App Signing(Xcode 8 的又一重大革新),Xcode 会自动更新相应的证书文件,完成后如图 6 所示。

SiriKit 初探 —— WWDC 2016 技术赏析_第6张图片

图6 Xcode 自动更新相应的证书文件完成图

图7显示了修改.entitlements文件添加Siri支持。

SiriKit 初探 —— WWDC 2016 技术赏析_第7张图片

图7 修改.entitlements文件添加Siri支持

指定Intents Extension支持的一种或多种Intents

Intents Extension Target 创建后默认生成了两个文件:

  • IntentHandler.swift;
  • Info.plist。

编辑 Intents Extension 的 Info.plist 文件,在 NSExtension 字典中指定 App 支持的意图类型。以消息类型意图为例 Intents Extension 的 Info.plist 如图 8 所示。

SiriKit 初探 —— WWDC 2016 技术赏析_第8张图片

图8 Intents Extension 的 Info.plist

这里解释一下 plist 中的关键字。

  • IntentsSupported:支持的 Intents 类型列表;
  • IntentsRestrictedWhileLocked:限制使用该 Intents 前必须解锁,也是一个列表;
  • NSExtensionPointIdentifier:必须为com.apple.intents-service
  • NSExtensionPrincipalClass:Intents扩展的入口文件,默认为$(PRODUCT_MODULE_NAME).IntentHandler

打开 IntentHandler.swift 文件,部分默认实现如图 9 所示。

图9

我们先来运行测试一下。

在 return self 一行打上断点,然后选择 Intents Extension 对应的 Target,在 iOS 10 设备上运行。此时会弹出一个 iPhone App 列表,选择 Siri,编译运行后会自动打开Siri(如图10所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第9张图片

图10 SiriKit 试运行

测试 Demo 中主 App 的名字为“知了”,在 iPhone 上打开的 Siri 界面输入语音“使用知了发送一条消息”,Siri 会在这条语音中识别出用户意图为使用“知了”发送消息,将语音信息转换为文本转发给 Demo App,程序会停留在我们刚才设置的断点上。

SiriKit 对中文的支持效果并不理想,例如语音输入“用知了发送一条消息”,会将“一条消息”识别为发送的内容;再比如输入“用知了发消息给宏昌”,会将“发消息给宏昌”识别为发送的内容。

经过多次测试,官方 Session 中示例中动词化应用名字的方式识别效果最好。因此在 SiriKit 的中文语音测试中推荐下面形式。

你:知了发信息给宏昌。
Siri:你想对宏昌说什么。
你:看《冰与火之歌》了吗。
Siri:好的。可以发送了吗?
你:发送。

Intents Lifecycle 编码实现

停止运行,接下来来看一下具体的编码实现。为了当支持多重 Intents 时的代码看起来简洁,我们把不同类型的 Intent 转发到不同的类。新建SendMessageIntentHandler类。

class SendMessageIntentHandler: NSObject,INSendMessageIntentHandling

IntentHandler.swift中更新handler(for intent:)方法,在Intent为INSendMessageIntent时返回它。

override func handler(for intent: INIntent) -> AnyObject {
    // This is the default implementation.  If you want different objects to handle different intents,
    // you can override this and return the handler you want for that particular intent.
    if intent is INSendMessageIntent {
        return SendMessageIntentHandler()
    }

    return self
}

具体的业务逻辑在SendMessageIntentHandler类实现。

resolve

resolve 是 Intent 处理逻辑的第一个阶段。消息发送类型的意图处理过程中,需要 resolve 的信息有下面两个。

  • 消息接收者(Recipients),对应 resolve 方法是:resolveRecipients(forSendMessage intent:,with completion:)。
  • 消息内容(Content),对应 resolve 方法是:
    resolveContent(forSendMessage intent:, with completion:)
    可以看到,resolve 方法的参数主要有下面两个。
  • INSendMessageIntent类型的实例intent,通过它可以访问到所有Siri解析出的用户意图相关信息,例如,消息接受者的信息intent.recipients、消息内容intent.content等。
  • completion方法,用于返回当前的处理结果。根据处理结果的不同 SiriKit 设计了7个回调方法:

    • success(with:) // 已完成必要信息的收集,可以进入下一阶段
    • confirmationRequired(with:) // 需要 Siri 提示用户确认某些信息,如:消息接收者
    • disambiguation(with:) // 有歧义的信息,如:命中了多个消息接收者
    • needsMoreDetails(for:) // 目前的信息不足以完成 Intent 对应的操作,需要Siri继续收集,如:希望提供消息接受者更多的信息
    • needsValue() // 需要一个完成操作必要的值,如:付款的金额
    • notRequired() // 告知 Siri 无论用户是否对当前参数传值都可以继续执行
    • unsupported() // 告知用户当前值不支持,如:找不到消息接收者

如何合理的使用上述回调方法呢?举例来说,消息接受者的 resolve 过程中可能发生的情况有三种:

  • 与消息接受者匹配的联系人被找到且只有一个,匹配成功,返回.success(with:recipientMatched)
  • 可能与消息接受者匹配的联系人有多个,匹配具有不确定性,返回.disambiguation(with:disambiguationOptions)
  • 未找到与消息接受者匹配的联系人,返回.unsupported()

注意: 一条消息的接收者可能有多个,因此消息接受者处理中completion方法的参数是一个内容类型为INPersonResolutionResult的数组,而不是单一结果。

消息内容的处理则比较简单,判断输入内容是否合法后在completion方法中输入INStringResolutionResult类型的结果并调用。

以下是 resolve 阶段完整的代码实现:

// 1.1 Resolve: 处理联系人信息
func resolveRecipients(forSendMessage intent: INSendMessageIntent, with completion: ([INPersonResolutionResult]) -> Void) {

   if let recipients = intent.recipients {
       var resolutionResults = [INPersonResolutionResult]()

       for recipient in recipients {
           let matchingContacts = contacts(personName: recipient.displayName)

           switch matchingContacts.count {
           case 2 ... Int.max:
               let disambiguationOptions: [INPerson] = matchingContacts.map { contact in
                   return contact
               }

               resolutionResults += [.disambiguation(with: disambiguationOptions)]

           case 1:
               let recipientMatched = matchingContacts[0]
               resolutionResults += [.success(with: recipientMatched)]

           case 0:
               resolutionResults += [.unsupported()]

           default:
               break
           }
       }

       completion(resolutionResults)

   } else {
       completion([INPersonResolutionResult.needsValue()])
   }
}

// 1.2 Resovle: 处理消息内容信息
func resolveContent(forSendMessage intent: INSendMessageIntent, with completion: (INStringResolutionResult) -> Void) {
   if let text = intent.content where !text.isEmpty {
       completion(INStringResolutionResult.success(with: text))
   } else {
       completion(INStringResolutionResult.needsValue())
   }
}

confirm

每个 resolve 方法调用后都会调用 confirm 方法,Demo 中只检查了当前的登录状态,当然你也可以在 confirm 中检查更多的状态,如下所示:

// 2. Confirm:
func confirm(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Void) {

   // 登录后才能发消息
   if hasValidAuthentication() {
       completion(INSendMessageIntentResponse(code: .success, userActivity: nil))
   } else {
       let userActivity = NSUserActivity(activityType: String(INSendMessageIntent.self))
       userActivity.userInfo = [NSString(string: "error"):NSString(string: "UserLoggedOut")]

       completion(INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity))
   }
}

confirm 的参数仍然是intentcompletioncompletion方法的参数类型为INSendMessageIntentResponse。在应用逻辑中,检查到用户未登录时,response 的 code 会传入failureRequiringAppLaunch,即需要启动 Demo 应用完成后续的登录操作。SiriKit 提供了如下 code:

  • unspecified
  • ready
  • inProgress
  • success
  • failure
  • failureRequiringAppLaunch

值得注意的是除了 code 外,response 还接受另一个参数userActivity,它是一个NSUserActivity类型的对象,主要用于在主 App 启动时将当前环境上下文传递给主 App。

handle

多次交互确认发送消息所需要的信息之后,Siri 会询问我们“要发送吗?”。语音输入“好的”、“发送”或“确定”都可以触发发送。此时 SiriKit 会调用handle(sendMessage intent:, completion:)方法,消息发送的处理逻辑都应该在这个回调方法中完成。

// 3. Handle:
func handle(sendMessage intent: INSendMessageIntent, completion: (INSendMessageIntentResponse) -> Void) {
   if intent.recipients != nil && intent.content != nil {
       let success = sendMessage(target: intent.recipients, content: intent.content)
       completion(INSendMessageIntentResponse(code: success ? .success : .failure, userActivity: nil))
   } else {
       completion(INSendMessageIntentResponse(code: .failure, userActivity: nil))
   }
}

处理的结果通过INSendMessageIntentResponse返回给 SiriKit。

至此,SiriKit 的接入工作就完成了,但用户看到的是 SiriKit 提供的默认 UI,为了提供更好的用户体验,使界面风格契合 App 的特点,SiriKit 提供了自定义UI界面的扩展——Intents UI Extension。

Intents UI Extension

一个 Intents UI Extension 的完整生命周期如图 11 所示。

SiriKit 初探 —— WWDC 2016 技术赏析_第10张图片

图11 Intents UI Extension 的完整生命周期

在上面的小节中我们已经创建过 Intents UI Extension 的 Target,默认包含三个文件:

  • IntentViewController.swift;
  • MainInterface.storyboard;
  • Info.plist。

基础视图的实现

和 Intents Extension 一样,我们需要修改 Intents UI Extension 的 Info.plist 中NSExtension部分以支持INSendMessageIntent(如图12所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第11张图片

图12 修改 Intents UI Extension 的 Info.plist 中 NSExtension部分

下面解释一下 plist 中的 key。

  • IntentsSupported:支持的 Intents 类型列表;
  • NSExtensionMainStoryboard:Extension 视图的 Storyboard;
  • NSExtensionPointIdentifier:必须为com.apple.intents-ui-service

我们还是先来运行一次看看效果。在 Storyboard 中添加一个文本内容为“Winter is coming”的 UILabel,再次运行,效果如图 13 所示。

SiriKit 初探 —— WWDC 2016 技术赏析_第12张图片

图13 添加文本内容后的运行效果

Intents UI的实现

视图的逻辑编码在IntentViewController类中,IntentViewControllerUIViewController的子类,因此你可以使用所有 UIKit 的 API。也就是说,在这个类中编写界面和我们之前开发过的ViewController编写方式基本一致。

那么 Intents Extension 在处理 Intent 过程中所发生的状态变化是如何传递给 Intents UI 的呢?先来看一下IntentViewController类的基本实现:

class IntentViewController: UIViewController, INUIHostedViewControlling, INUIHostedViewSiriProviding {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - INUIHostedViewControlling

    // Prepare your view controller for the interaction to handle.
    func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
        // Do configuration here, including preparing views and calculating a desired size for presentation.

        if let completion = completion {
            completion(self.desiredSize)
        }
    }

    var desiredSize: CGSize {
        return self.extensionContext!.hostedViewMaximumAllowedSize
    }

    var displaysMessage: Bool {
        return true
    }
}

IntentViewController类继承于UIViewController之外,还实现了INUIHostedViewControlling协议的configure方法。

configure(with interaction:, context:,
completion:

这个方法的第一个参数是当前这次 Siri 交互上下文信息,包括 intent 和 intentResponse 等属性,UI 层可以根据上下文信息完成本次视图的更新展现(如:展示加载动画),并返回一个 CGSize 给 Siri 来指明目前视图的大小。NSExtensionContext中给出了视图大小的最小和最大允许值,返回的 CGSize 只能在两者之间。

var desiredSize: CGSize {
return self.extensionContext!.
hostedViewMaximumAllowedSize
}

每次 Siri 和 App 交互后都会顺序调用viewDidLoad()方法和configure()方法。另外,值得注意的是 Intents UI Extension 的界面区域内是不支持手势交互操作的。

INUIHostedViewSiriProviding

从上文的截图可以看到,除了你的自定义 UI 区域,Siri 还提供了一个默认区域展示消息的接收者和内容,如果我们在自定义区域已经展示了这些信息,这个默认区域会导致信息重复。SiriKit 为此提供了INUIHostedViewSiriProviding这个协议,通过实现代理方法可以隐藏这个区域:

var displaysMessage: Bool {
return true
}

隐藏后效果如下:

SiriKit 初探 —— WWDC 2016 技术赏析_第13张图片

图14 隐藏UI默认区域后的效果

语义识别优化

官方的 Session 中简单介绍了 Siri 识别当前的语义的一些依据:

  • 用户必须说出你的应用名称(即 Bundle Display Name);
  • 你的 App 名称可以出现在一句话的任意位置,前提是不会引起歧义;
  • Siri 可以动词化你的 App 名称,例如,知了 Jon Snow 一条消息。

SiriKit 处理的四个过程里面,App 的处理逻辑主要是从 Intent 过程开始的。Speech 过程由 Siri 独立完成,考虑到每个 App 都有自己独特的方式和用户交流,因此在语义识别的过程中,Siri 允许应用提供自定义的词表(User Vocabulary)用来帮助 Siri 更好地识别和 App 相关的语境(如图15所示)。

SiriKit 初探 —— WWDC 2016 技术赏析_第14张图片

图15 语义识别中的自定义词表

通过 App 相关的自定义词表(术语或短句)提供给 Siri,让 Siri 可以识别出和 App 相关的独特信息可以优化使用体验。这样的关键词表分为两类:

  • 和 App 相关的关键词表(App-Specific Vocabulary);
  • 和某个用户相关的关键词表(User-Specific Vocabulary)。

App-Specific Vocabulary

提供 App-Specific Vocabulary 的方式是在主 App 内集成 App vocabulary plist 文件。在主 App(注意不是 Extension)的 Bundle 中创建AppIntentVocabulary.plist文件来帮助 Siri 了解和 App 有关的术语,甚至可以提供该术语的发音信息和使用例句。

AppIntentVocabulary.plist文件是支持本地化的,可以为 App 的每种语言版本提供不同的词表信息。

这个 plist 文件的根字典可以包含两个 Key,如表1所示。

表1

Key 类型 简介
ParameterVocabularies 字典列表 (必填)符合 App 目前支持的 Intents 某个特定属性的术语列表
IntentPhrases 字典列表 (选填)在 Siri 的引导中展示并提供给 Siri 做深度学习的短句。

ParameterVocabularies

ParameterVocabularies列表中的字典可以包含两个Key,如表2所示。

Key 类型 简介
ParameterNames 字符串列表 (必填)术语可以应用于的 Intent 属性,用.的形式表示
ParameterVocabulary 字典列表 (必填)术语的同义词列表,包括发音和例句

ParameterNames 中目前只能为打车和健身类型的意图设置 App 级别的关键词表。

ParameterVocabulary 列表中的字典包含以下两个 Key。

  • VocabularyItemIdentifier:必填,自定义术语的标识。当 Siri 通过语音识别出当前的术语后,会把这个标识赋值给 ParameterNames 中的 Intent 属性上,这个标识不会被用户看到,并且在AppIntentVocabulary.plist的所有本地化版本中应该是一致的。
  • VocabularyItemSynonyms:一组同义词的字典列表。该字典可以包含三个Key:

    • VocabularyItemPhrase:用于Siri识别和展示的短语,如iTunes;
    • VocabularyItemPronunciation:在本地化语言中该短语的近似发音,Siri 会根据这个发音来识别短句。如iTunes对应的发音读作 “eyetoons”。除英语外,SiriKit针对三种语言提供了发音的描述方法,分别是:zh_CN、zh_TW、zh_HK;
    • VocabularyItemExamples:一个在常见使用场景中的例句列表。

IntentPhrases

IntentPhrase 列表中的每个字典都包含两个 key,如表 3 所示。

Key 类型 简介
IntentName 字符串 (必填) 例句所对应的 Intent 类(6种)
IntentExamples 字符串列表 (必填) 当前 Intent 语境中用户可能的表达方式

以“呼呼打车”中打车场景为例,IntentExamples 可能的表达方式有:

  • “用呼呼打一辆跑车到林大北路”;
  • “帮我在呼呼上预订一辆明早 8 点的卡车”;
  • “查找呼呼明天下午 6 点从公司回家的顺风车”。

AppIntentVocabulary.plist 示例

图16展示了一个支持 SiriKit 的健身应用中 AppIntentVocabulary.plist 的完整示例。

SiriKit 初探 —— WWDC 2016 技术赏析_第15张图片

图16 支持 SiriKit 的健身应用中的AppIntentVocabulary.plist 的完整示例

User-Specific Vocabulary

另一种向 Siri 提供自定义词表的方式是在运行时由 App 提供一个用户特定的、以OrderedSet类型返回的关键词表,比如通讯录中的收藏、最近联系人。

在提供自定义词表时应注意以下几点:

  • 只提供必要的信息,比如iOS的通讯录已经被Siri收录,不需要重新提供;
  • 数据变化的时及时更新;
  • 适时删除这部分信息,如当前用户退出登录时删除当前用户相关的联系人信息。

使用INVocabulary对象为一个独立用户注册一个指定Intent类型的词表。通过调用 SiritKit 提供的 API:-setVocabularyStrings:ofType:方法来实现。

以提供最近联系为例,代码实现如下:

//SiriKit
NSOrderedSet *tStrings = [self recentlyContacts];

INVocabulary *voc = [INVocabulary sharedVocabulary];
[voc setVocabularyStrings:tStrings ofType:INVocabularyStringTypeContactName];
// --SiriKit

对于注册方法的使用有以下几点提示。

  • 上述代码需要编码在主 App 中,而不是在 Intent Extensions。
  • INVocabulary 中的词表只支持如下四种类型:
    • 联系人(Contacts framework 提供之外的);
    • 照片标签;
    • 相册名称;
    • 健身运动名称。
  • 针对每种 Intent 类型只能保存一组词表,下次调用会覆盖当前词表,因此要保证将词表信息一次性的注册进去。
  • 词表的内容数量是有限的,尽量只注册用户收藏、最常用或最近使用过的词表信息。

总结

到这里你已经了解了利用 SiriKit 开发 App 和 Extensions 的全部过程和相关知识。当然,和地理位置、通知一样,使用 SiriKit 也需要请求系统权限,并且在弹窗中解释用户的哪些信息可能被发送到Siri。

Siri 从问世开始,开发者们就一直在等待 API 开放,SiriKit 如今总算是“千呼万唤始出来”。SiriKit 不仅为 App 带来了“人工智能”,同时也为每个应用提供了新的系统级入口,用户无需进入 App,也不需要任何点击操作就可以完成想要的操作,消息发送、拨打视频电话、转账、打车、健身变得更加即时方便。

当然,SiriKit 和所有首次开放的 API 一样,目前仍然不够成熟,有两个方面需要提高:一是更智能丰富的中文语意识别;二是由于 Siri 的输入存在非常多的可能性,在实际应用的过程中会出现令人困惑,或API调用结果不符合我们预期的情况。

无论如何,通过 WWDC 2016 可以看到,iOS、macOS、watchOS和tvOS这四个产品线上的布局已经完成,苹果生态整合又前进了一步。各个平台的交互体验、一致性、安全性都得到了进一步的提升。正如 SiriKit 的开放一样,苹果开发者们面临新的挑战的同时,也应该看到许多新的机会。随着 Siri 的发展,用户与智能设备的交互方式不仅仅停留在视觉和触觉,越来越多的人会开始使用 Siri,感受 Siri 给这个世界带来的不同。


关于移动开发新技术,更多精彩尽在MDCC 2016,详情请查看大会官网:MDCC 2016移动开发者大会。

你可能感兴趣的:(SiriKit 初探 —— WWDC 2016 技术赏析)