大多数浏览器和
Developer App 均支持流媒体播放。
-
Siri 快捷指令简介
“Siri 快捷指令”是 iOS 12 中一项强大的新增功能,它的作用是让您的 app 将自己的功能通过 Siri 来曝光。这样,Siri 就能根据不同的情境在适当的时机为您提供快捷指令建议。快捷指令还可以添加到 Siri,以便在 iOS、HomePod 和 watchOS 上通过语音口令运行。了解如何使用 NSUserActivity 在 app 中公开快捷指令,并探索使用 SiriKit 创建自定意图来提供更丰富用户体验的好处。
资源
- Deleting Donated Shortcuts
- Donating Shortcuts
- Learn more about SiriKit
- SiriKit
- Soup Chef: Accelerating App Interactions with Shortcuts
- 演示幻灯片 (PDF)
相关视频
WWDC21
-
下载
大家好 我的名字是 Ari Weinstein 很高兴来到这里 与 Willem Mattelaer 一起 向大家介绍 Siri 的捷径 两年前 我们发布了第一版 SiriKit 让你的 App 能 使用 Siri 的功能 它当时已经具备了 如发送信息 叫车 交易支付等 诸多细化功能 但我们知道 你想用 SiriKit 做更多的事情 这也是为什么今年我们会 如此兴奋地向大家介绍捷径
捷径的核心思路 是让你可以把自己的 App 中 最关键的功能 与 Siri 接通 这样真的很好 因为这让人们可以 在新的场景以新的方式 来使用你的 App 这是一种 吸引用户的好方法
接通捷径 为用户使用你的 App 开启了无数种可能性 让我们一起看看可以使用 捷径的典型场景吧 捷径通过 展示你接下来想要做什么 把 “Siri 建议”带到了一个新的层次 不仅仅是打开你的 App 更能延伸到 App 内部的功能 并且 Siri 会在恰当的时机 在搜索界面中提供建议
Siri 还可以在 Apple Watch 上 建议捷径 你可以在你手腕上的 Siri 表盘 上直接使用它们
当 Siri 认为 应该使用某个捷径时 它就会在锁定屏幕上 显示建议 当你轻点一个捷径时 你直接在 锁定屏幕上的定制 UI 上 来使用它 你还可以把捷径添加到 Siri 这样你就可以 通过询问 Siri 来使用这些捷径 在 Siri 中 你会看到 与锁定屏幕和搜索界面中 相同的定制 UI
App 可以在 Siri 中提供 很好的语音体验 App 提供自定义的响应对话 而 Siri 会将其大声读出来 来告诉你一些事情 比如咖啡还有多久做好 当用户给 Siri 添加捷径时 他们要先选择一个 自定义的个人短语 这样用户就可以选择 对 Siri 说什么来启动捷径 作为一个开发者 你应该建议使用的短语 在这种情况下 建议是“咖啡时间” 一旦对 Siri 添加了一个捷径 这将在你所有 iOS 设备上 在 Apple Watch 上 甚至在 HomePod 上都适用 我们也有新的 捷径 App 通过这个新的捷径 App 每个人都可以打造自己的捷径 需要做的只是拖拽和放下 一系列的步骤 这些步骤还包括 你 App 所接通的捷径 我们今天将讨论 如何在你的 App 中 使用捷径 以及如何优化你的捷径 以提供更好的建议 我们会讲到一些 要特别注意的 隐私考虑 我们还会讲到 如何为媒体播放 制作出色的捷径
首先 我们来讨论一下 如何采用新的捷径 API
创建捷径 有 3 个步骤 第 1 步是 定义捷径 这意味着你需要决定 为哪个功能接通捷径 同时定义每个捷径 这样 Siri 就可以知道你的 App 能做些什么
第 2 步 你需要递交(Donate)自己新的捷径 这意味着每次用户 在你的 App 中使用 接通了捷径的功能时 你都需要告诉系统 这样 Siri 才会习得 建议你的捷径的 正确时机和场景 第 3 步是处理你的捷径 这意味着 当用户想要 在 Siri 中 在锁定屏幕上 或是在搜索界面使用你的捷径时 你需要准备好 让你的 App 和 App 扩展 可以被唤醒 并将其传递至句柄
在你定义捷径之前 你需要决定 你具体想要接通的功能是什么 你需要考虑 什么是用户 在使用你的 App 时 会做的最重要的事 因为这些事情 可能就是你需要 接通捷径的东西 你接通的每一个捷径 都应该让用户在使用 你的 App 的核心功能时 能有更快的速度 这意味着你应该采用一些 用户想用你的 App 所做的事情 并让他们能更快地做这些事情 速度的提升应该 是实质性的 你不能只是接通一个 正常地打开你的 App 的捷径 如果你接通的捷径 并没有让用户 在使用 App 时有很大的速度提升 那么它就不会被推荐为经常使用 其次 每一个 你接通的捷径 都应该能长期调动用户的兴趣 这意味着 这应该是用户想要 多次使用的功能 如果只是用户 想要使用一次或两次的功能 那么为它们创建捷径 不是什么好主意 你还应该只接通 可以随时使用的捷径 因为在你的捷径准备好前 你不能指望 用户处于某些 特定状态
一旦你决定要 接通什么捷径时 你就应该准备好查看 捷径的 API
我们有两种 API 来支持捷径的使用 第一种是 NSUserActivity NSUserActivity 是一种代表你 App 状态的轻量级方式 它集成了一些 其他的 Apple 功能 如“聚焦”和“接力” 第二种是 Intents Intents 是 一种展示你的 App 能实现的功能的方式 Siri 内置了 一系列很好的 Intents 它们支持一系列 App 可以用来 与 Siri 协作的功能 今年我们将 介绍一个非常酷的特性 你现在可以 自定义 Intents 来与捷径协作了
因此 对于每一个你接通的捷径 你都需要决定它 是一个 NSUserActivity 还是一个 Intent 那么我们来谈论一下如何 做出这个决定 目前 NSUserActivity 是 构建捷径很好的选择 如果你只是要构建一个 想要打开某些你 App 内的 功能的简单捷径 或者你想要 为某些你已经内置在“聚焦”搜索内 或者已经在 NSUserActivity 中 提供的(比如“接力”)功能 接通捷径 建议你选择 NSUserActivity 但是如果想要最优的 捷径体验 你应该采用 Intents 以 Intents 为基础的捷径 真的非常酷 因为它们不需要启动你的 App 就可以内联运行 它们能包含一些自定义的 语音回复和定制化的 UI 像我们刚刚看到的那样 它们还会包含一些 颗粒参数预测 这些 Willem 稍后 会和你们讨论
一旦你决定要采用哪种 API 你就准备好 要开始实现了
那我们现在就开始 首先 我们来看看 怎么用 NSUserActivity 来接通捷径 第 1 步是定义你的捷径 对于 NSUserActivity 来说 这意味着你需要 在你 App 内的 Info.plist 文件中 声明一个 UserActivityType 来将你的 Activity 类型登记到系统中
接下来 你需要递交捷径 对于 NSUserActivity 这意味着每当用户处于 你的 App 中你想提供 捷径的界面时 你都应该让你一个 NSUserActivity 对象可用 这里有一个关键的新内容 就是 isEligibleForPrediction Flag 在任何 userActivity 上 把这个 Flag 设置为 “true” 都会把它变成一个捷径 真正酷的是 如果你的 App 已经有了一个 userActivity 你可以直接将这个 Flag 设置为 “true” 这个 userActivity 就会 自动变成一个捷径
请注意 isEligibleForSearch Flag 需要 设置为 “true” 这样 isEligibleForPrediction 才能生效 另外 你可能要考虑到 isEligibleForHandoff Flag 它的默认情况就是 “true” 所以在默认情况下 你的所有 userActivity 都可以在不同设备间“接力” 当你创建自己的 userActivity 时 你要确保 包含所有 userInfo 词典中的信息 以便之后 可以还原在这个 Activity
接着就是通过 把 userActivity 与当前屏幕上的 UIViewController 或 UIResponder 连接 来标记你 当前的 Activity 最后一步就是 在定义 且递交了捷径之后 处理它们 每次当用户从你的 App 使用 NSUserActivity 时 它都会在你的 App 中打开 你需要通过执行 App 中用来处理 NSUserActivity 的委托方法 即 continueUserActivity 来对其进行处理 你要做的就是 执行这个方法 确认这种 Activity 类型是否 与你所登记的类型匹配 如果匹配的话 你可以将 App 还原成 userActivity 保存时的状态
以上就是为了让 Siri 通过 NSUserActivity 为你的 App 建议捷径 00:09:33.386 --> 00:09:34.836 A:middle 你需要做的事情
现在 让我们来谈论一下 如何通过 Intents 接通捷径
第 1 步还是 定义你的捷径 你可能需要 从决定采用 哪种类型的 Intents 开始 大家都知道 Siri 包含了 很多内嵌很棒的 Intents 比如信息 健身 清单等等 现在我们将介绍 如何在 Xcode 中 为捷径定义自定 Intents
如果你想要创建的捷径 正好与默认情况下的 内嵌式 SiriKit Intents 一致 那你应该采用它 不过你也可以定义自己的捷径 不管你是想定义自己的 Intents 还是采用现有的 并对其进行定制 你都需要在 Xcode 中创建 一个 Intents 定义文件 在我的空闲时间 我一直在与几个朋友 一起研发一个新的 App 这是一个送汤的 App 名字叫《Soup Chef》 要想订汤 使用这个 App 再方便不过了 它与 Siri 关联的潜力让我十分期待 我们来看看怎样使用 新的 Intent Editor 来为《Soup Chef》创建一个 Intent 首先我将打开 Xcode 中的 “File(文件)”-“New File(新文件)” 选择 “SiriKit Intent Definition File (SiriKit Intent 定义文件)” 然后我们就能看到全新的 Intent Editor 首先我们需要 点击左下角的加号按钮 接下来 我想给我的 Intent 取个名字 因为我要为订汤 制作一个 Intent 所以我要称之为 “OrderSoup(订汤)”
接着我要填写 Intent 的元数据 让我们一步一步来看 第一个元数据是 “Category(类别)” 定义 Category 可以帮助 Siri 知道 如何讲述你的 Intent 以及 如何在 UI 上展示它 比如说 在这种情况下 我选择了 “Order(预定)”这个种类 如果我选择 “Order” 当我使用到这个 Intent 的时候 Siri 会说如 “好的 我预定了”这样的话 接着它会展示一个 如 “Order(预定)”的确认按钮 我们提供 几种不同的类别 你应该选择最适合 你 Intent 目的 的那一个类别
接着你要填写 Intent 的 “Title(标题)” 和 “Description(描述)” 这将会在各类场景中帮助用户发现 你的 App 支持什么捷径
然后就是 “User confirmation required (需要用户确认)”复选框 这将决定我们是否 在用户使用你的捷径前 询问他们是否确认使用 所以 Siri 可能会说 如“你准备好使用《Soup Chef》 来订汤了吗?”之类的话 这对于我的 App 来说真的特别棒 因为我想要确保用户 并不是偶然地订汤
你可以在这里看到 Intent 的 “Parameter(参数)” 这里将会定义 传递给你的捷径的所有参数 比如说 在我的例子里 我有两个参数 分别是被预定的汤品清单以及配送地址 目前 “Parameters” 支持一个 简短的类型列表 这些类型包括如字符串 数字 人物和位置等 不过如果你想构建一个 能够代表你 App 中的对象 但是却不在 类型列表中的参数 那你可以
选择 “Custom(自定义)”类型 当你已经定义好你的参数 你可能会想要看一下 “捷径类型” 这里会定义 你想要建议给用户的 所有捷径的类型
每种类型都包含 一种特定的 会被预测的 参数组合 每一个类型 都标题和副标题的形式展示 其中会填上你的 参数数值 如果因为你的捷径需要 启动你的 App 才能运行 而导致的它不能在后台运行 那么你可以不选 “Supports background execution(支持后台执行)” 复选框 在某些情况下 一个 Intent 可能拥有很多个捷径类型 它们中有的支持 后台执行 有的则不支持 在《Soup Chef》的例子中 这尤其重要 因为当预知了菜单和 配送位置后 我们可以支持后台执行 因为我们拥有了 下订单所需要的一切 不过如果我们增加了一个 只包含配送位置的捷径类型 Siri 会知道 我们可能不会有 足够的信息来下订单 所以我们需要启动 App 来询问用户他们需要配送到 什么地址 在这种情况下 我们希望这种 捷径类型不要在 后台执行 你应该列出 你认为有助于 Siri 做出最佳预测的 捷径的每种变体的 捷径类型 为了最佳体验 你应该尽可能 让所有的捷径类型 都支持后台执行 支持后台执行的 捷径类型让用户 体验速度更快 这样它们会更频繁地被建议
你可以为每个 Intent 提供最多 16 种你定义的捷径类型
一旦你定义了你的 Intent Xcode 将 自动生成一个 Intent 类 和一个 Intent 处理协议 在我的例子中 我们生成了 OrderSoupIntent 类 还有一个 OrderSoupIntentHandling 协议 这个协议中有着与我刚刚 在我的 Intent 定义文件中 所定义的条目相一致的属性 由于 Xcode 会自动生成代码 很重要的一件事是需要考虑 Xcode 在生成这段代码的时候 Target 是什么 因为你不想要 在最后呈现相同类当中 互相冲突的 完全一样的实例
让我们一起 在 Inspector 面板中 看看我的 Intent 定义文件中的 “Target Membership(目标成员)”部分
你的 Intent 所使用的 每个 Target 都应该 包含你的 Intent 定义文件 你应该选中 “Target Membership” 下面的复选框 不过你需要确定 如果你拥有一个框架 你不会在互相包含的 多个 Target 中生成代码 如果你有一个框架 你应该通过在每个 Target 中 只选择 Intent 类 而不选择生成的类 来将 “Target Membership” 设定为 只为该框架生成 Intent 类 不过如果在你的 App 里 没有任何框架 因为你还没有将你的 App 分离成框架 你应该为每一个 Target 检查 Target 这就是如何在 Xcode 中定义 自定 Intent
当你定义好了自定 Intent 想要递交就非常容易了 你所需要做的只是 将你的 Intent 对象实例化 然后填入参数 再创建并递交一个 INInteraction 对象 需要确保每次用户 在你的 App 中执行与你的捷径 相同的任务时能做到这一点 在这种情况下 每次当 用户预订汤时 我就会递交这个 Intent 因为这将帮助 Siri 习得预测 Intent 的最佳时期
我们已经定义了自定 Intent 现在要讨论的就是 如何处理它 和 NSUserActivity 一样 你应该在你的 App 委托里 执行 continueUserActivity 方法 以此来处理 你的 Intent 当一个 Intent 在你的 App 中 被打开时 它将以 NSUserActivity 对象的形式 进入它的 Activity 类型就是之前你生成的 Intent 类的名字 在我的例子中 就是 OrderSoupIntent
不过如果你只执行 continueUserActivity 你的捷径每次都会打开你的 App 它不会在后台运行 或者与 Siri 内联运行 也不会支持如自定声音 回复之类的功能 为了拥有最佳的体验 你想要创建一个在后台 处理你的捷径的拓展包 要想实现这个目的 首先要在 Xcode 项目中创建一个新目标 然后选择 “Intents Extension (Intent 扩展)”模板 确保你的 Intent Handler 遵循 Intent 处理协议 在我的例子中 就是 OrderSoupIntent 这个处理方式 然后再执行这些方法 也就是 confirm() 和 handle() 需要注意的是 和传统的 SiriKit 不同的是 你不需要执行 resolve() 方法 因为你的 Intent 不需要任何 用户定制或 用户的任何后续动作 所以 你应该检查 你 Intent 的属性的 所有数值以保证 它们是有效的 如果不是 在你认为你不能处理 这个 Intent 的情况下 你应该返回一个错误代码 然后处理 准确地说是 执行你的捷径 在我的例子中 这意味着为汤下订单 接着你要返回一个 能够指明结果 如 “Success(成功)”的响应对象
你应该为每一个 Target 在后台运行的捷径 执行一个 Intent 拓展包 因为它们会 与 Siri 内部 在锁定屏幕上 在搜索界面中 在捷径 App 中 或者是在 Siri 表盘中自动运行 而不需要启动你的 App 最有价值的捷径 一定是在后台运行的 不过你也可以创建 很多其他很好的捷径 需要记住的是 即便你执行了一个 Intent 拓展包 你也应该一直 执行 continueUserActivity 因为用户可能会 通过 Siri 在你的 App 中 打开捷径 比如通过点击 Siri 上的卡片 来展示你 App 的 自定 UI 还有一件我想要 告诉你的事情 那就是 INRelevantShortcut INRelevantShortcut 是一种 向 Siri 表盘展示 捷径的方式 你只需要提供 包含 Intent 或者 userActivity 的 INRelevantShortcut 对象即可 你可以随意地 在你相关的捷径中 包含相关信息 这可以提示 Siri 表盘 何时你的捷径是相关的 以及什么时候是 展示你的捷径的最佳时期
关于 INRelevantShortcut 最酷的事情就是 即便你没有 Watch App 它也能起作用 你可以从你的 iOS App 接通相关的捷径 如果它们在后台运行 就会直接出现在 Siri 表盘上 好了 我们现在已经讲到了 所有捷径的使用方法 以及采用 API 的方法 接下来的时间交给 我的同事 Willem 他将为你演示 如何在 Xcode 中使用捷径 Willem 谢谢 Ari
我很兴奋能够成为演示 如何使用捷径的第一个人 在我们深入 Xcode 之前 先让我向大家展示一下 我们一直在研发的一款 App 正如 Ari 提到的 我们在研发一款名为《Soup Chef》的 订汤的 App 让我来向你们展示一下
这就是《Soup Chef》 当我启动这个 App 时 这里会展示我的订单记录 因为我还没有订过任何东西 所以这里还是空的 我可以通过点击加号 来发出一个新的订单 这为我展示了汤品的菜单 在这里你可以看到 我能点的所有汤品 我们来点一个番茄汤 接下来 我可以选择 汤的数量和加料的种类 我要点一个有红辣椒的番茄汤 当我准备好下单时 我就轻点一下 “Place Order(下单)”按钮
现在回到 “Order History(历史订单)” 你就能看到我刚刚下的 那个订单了 我可以轻点订单去看 关于一个特定的订单的更多细节 这一视图与 userActivity 相关联 我认为将这个建议给用户 是非常好的 因为我们的用户喜欢 回味他们曾经点过的 美味的汤 如果能把这些建议给她们 那将非常棒 让我们去 Xcode 看看 如何实现这个设想 现在我在观看 订单细节视图的 viewController
我创建了一个 userActivity 同时我也设定了一个 requiredUserInfoKeys 我还要确保 isEligibleForSearch 为真
为了它能够被建议 我还需要让 isEligibleForPrediction 为真
这样就行了 我们来试一下
首先我需要保证我 递交了 userActivity 我现在返回视图 这样就够了 现在我想确保 Donation 已经发生了 为了确认 我们增加 两项开发者设置 能让它在搜索界面和 锁定屏幕上很容易地看到 最近的 Donation 为了启用这个 我们来到“设置” 滑动到“开发者”这一栏
在最底端有两个新的开关 展示最近的捷径 和在锁定屏幕上展示 Donation 我们打开两个开关
现在我们可以回到主页面 下滑到搜索栏进行搜索 我们可以看到 刚刚完成的 Donation 很好 我可以轻点它 然后 App 就与 userActivity 一起启动了 并且回到了我刚刚递交的 订单页面 很好 这样很赞 但是我认为我们还能做得更好 因为我们 App 的主要功能 就是订汤 如果它能够把订汤建议给用户 那真是再好不过了 我希望用户可以 不用启动我们的 App 就能达到这个效果 我会使用一个 Intent 来实现 现在还没有内置的订单 Intent 但是在 iOS 12 中 我可以创建一个自定 Intent 我们来试试
首先我们要创建一个 Intent 的定义文件 先选择 “File(文件)” 然后进入 “New(新建)”-“File...” 选择 “SiriKit Definition File"
然后 “Next(继续)”
现在我可以为它命名 我会保留 “Intents” 这个名字 然后放在 “Resources(资源)”文件夹里 好了 现在我准备好了 点按 “Create(创建)” 这里展示的就是 我们的 Intents 定义文件 以及我们的全新 Intents 编辑器 在我添加 Intent 之前 我需要确保 在正确的 Targets 内 包含 Intents 定义文件 正如 Ari 所说 我们需要 在使用 Intent 的所有地方添加 Target 所以我要把它添加在 我们的共享框架中 因为我们使用的是共享框架 我不想让它为 App Target 生成 在下拉菜单中 在 App Target 旁边 我会选择 “No Generated Classes
(无生成类)” 好了 我们可以添加 Intent 了 在左下角点击加号 同时选择 “New Intent(新建 Intent)” 将其命名为 “OrderSoup”
接下来我要选择类别 在这个例子中 这是一个 “Order”Intent 填写标题 “Order Soup” 然后是描述 “在 Soup Chef 点一碗汤”
因为这涉及到真实世界的交易 我想在提交 订单前确认一下 所以我会选择 要求用户确认
接下来让我们定义参数 我将定义三个参数 一个针对汤 一个针对数量 还有一个针对用户选择的加料选项 首先是汤 我点击 “Parameter” 部分的加号 然后填写名字 “soup(汤)” 因为汤是我们 App 中的定制对象 我将会选择 “Custom(自定义)”类型 接下来 我要添加 “quantity(数量)” 我再次点击加号 填写名字 这次将是一个 “Interger(整数)”类型
接下来是 “options(选项)”
选项是我们的 App 的自定对象 所以我会使用 “Custom” 类型
因为用户可以选择 多个选项 我还会选中 “Array(数组)”复选框
最后 我们需要定义捷径类型 此时 我将定义一个 包含了所有参数的单一的捷径类型 我会在“捷径类型” 中 点击加号 然后选择我想要包含在 捷径类型中的参数 这样我就能选择汤数量选项了 当我准备好时 点按“添加 捷径 类型”按钮
填写标题订单 然后再插入 “quantity” 以及 “soup” 和 “options” 然后我把副标题留白 因为在标题中 我已经包含了需要的所有信息 我还会选中 “Supports background execution(支持后台执行)” 因为我想让用户在后台 执行这个 Intent 我们已经定义了我们第一个 Intent 现在让我们来试试 首先我会为我们的 Order 对象 增加两个辅助方法 让它能更简单地 在它和 Intent 之间转换 我现在来到 Order 类 在最底端 我会增加一个 Order 扩展 它包含一个 可以返回 Intent 的系统变量 我在这里创建 Intent 设定汤的数量和 选项 然后返回到 orderSoupIntent
扩展同样也定义了 一个新的源于 Intent 的 初始化程序 在这里 我抽取汤 数量 和选项 然后我用这些数值 初始化订单 很好 这会非常有用
接下来 我需要确保 每次用户下订单的时候 我们都递交了 Intent 所以我来到订汤的 数据管理器 在 placeOrder() 方法中 我会添加 我们的 Donation 逻辑
我声明了一个 INInteraction 它包含了订单的 Intent 然后递交 interaction 就好了
最后 我们需要处理 Intent 首先我需要在 App 中 增加支持 我们打开 AppDelegat.swift 在 continueUserActivity 中 我会为其增加支持 我想要确认 userActivity 的 activityType 是否与我想 处理的 Intent 的类名称一致 如果一致 我会从 userActivity 中提取 Intent 同时生成 一个 Intent 最后 我会展示订单视图 既然我们打开了 App 我假设用户并不想 立刻下订单 而是想在下订单之前 做一些定制 这就是我展示订单视图的原因 最后 让我们增加对 Intent 扩展的支持 这样用户就可以在后台 运行 Intent 了 首先我需要增加一个 Intent 扩展 选择 “File”-“New”“-Target” 然后选择 “Intents Extention
(Intents 扩展)” 我要为它起个名字 SoupChefIntents 然后点按 “Finish(完成)” 因为我增加了一个我可以使用 Intent 的新 Target 我需要确保 Intent 定义文件 被包含在 Target 中 回到 Intent 定义文件 然后将其增加到 Target 中 我还是不想在 Target 中 生成代码 在下拉菜单中 我选择 “No Generated Classes” 我还希望扩展 Target 能 接入 App 的相同数据 所以我会将其增加到 相同的 App 群组 在项目设定中 我选择 Intents Target 在 “Capability” 页中 我会将其添加到 相同的 App 群组 很好 现在我们就可以 执行与这个 Target 相匹配的 IntentHandler 了
首先 我要引入我们共享的 框架 SoupKit
因为我们将处理 OrderSoupIntent 这个 IntentHandler 需要 与 OrderSoupIntentHandling 协议相一致
它是作为我们 Intent 的一部分生成的
这个协议有一个必要的方法 也就是 handle() 方法 让我们实现它 在 handle() 方法中 我得到了一个 Intent 我通过那个 Intent 创造了一个订单 如果成功了 我就下了订单 我就会调用 completion() 其中会有 Intent 的响应码 “.success” 如果我不能从 Intent 中 创造一个订单 我也会调用 completion() 但是其中的 Intent 响应码会变成 “.failure” 就是这样 我刚刚在我的 App 里 为一个新 Intent 添加了支持 让我们尝试一下
首先 我需要递交 Intent 我会下另一个订单 点击加号 这次我要订一个有面包丁的 蛤蜊浓汤 我要下单了
现在 如果我重新回到主屏幕并下滑 我可以看到我递交的 Intent 很好 我可以点击它 现在展示的是一个捷径视图 以及 “Order(点餐)”按钮 如果我点击它 就会直接在后台下单 这样订单就完成了 我可以回到 App 看看它是否预订上了 是的 在我的 App 里有一个新订单 很好 很简单 除了轻点“点餐”按钮 我还可以点击 捷径视图本身 这将会通过捷径启动 App 由于我实现的方法 它将会展示订单视图 这里我可以自定义订单 我还可以加上奶酪 谁知道呢 我要下单了
很好 最后 让我们给 Siri 加上捷径
我们来到设置 向上滑到 “Siri 与搜索” 搜索 这里我可以选择我想要添加到 Siri 的捷径 在这个例子中 我要添加 预定一份带面包丁的蛤蜊浓汤
当我选择录音按钮时 我可以说出我想与这个捷径 相关联的短语 “Soup time(喝汤时间)”
这样就好了
让我们回顾一下 我们刚刚所做的 我们首先让一个 已经在我们 App 中实现的 NSUserActivity 中的 isEligibleForPrediction 为真 这让其可以被建议 同时也是一个接通你 App 内容的 简单的方法
接下来 我们定义一个自定 Intent 这真的是展示 你的 App 的核心功能的 最好方法 在这个例子中 就是点一碗汤 定义好 Intent 之后 我们要确保每次用户在 App 内下单时 我们都递交了 Intent 最后 我们处理 Intent 不仅是在支持后台运行的 扩展 Target 中的 还有在 App 内的 这样用户就可以 通过捷径 启动 App
现在我们看了如何 采用捷径 接下来我们看看这些捷径 是如何 被建议的以及你可以做些什么 让你的用户看到 可能的最佳建议 每次当一个用户在你的 App 内 完成一个动作并且 你的 App 递交了这个动作 在这个例子中 就是和其他信息
对于时间 我们认为 应该记录一天中的时间 或一周中的一天 至于位置 我们会看看用户的 整体位置 然后确定 这是否对于用户来说是一个重要的位置 接下来看看系统如何 利用这些来做出建议
在这里 我们只考虑时间 周一 午饭时间 我预定了一份 加面包丁的番茄汤
晚上的时候我不喜欢面包丁 所以我预定了一份 加红辣椒的番茄汤 第二天的午饭 我再次 预定了加面包丁的番茄汤 我一整周都这样操作 在周五午饭的时候 Siri 可能会尝试给我建议 它会观察我过去的行为 尝试在里面找到规律 如果现在是午餐时间 由于我经常在中午预定 加面包丁的番茄汤 Siri 可能会注意到这点并向我建议 这样很好 这就是我想的 00:33:54.546 --> 00:33:56.196 A:middle 这些都是很高层级的东西
我们来看看 它是如何工作的 我们先从 NSUserActivity 开始 我们假设一个在《Soup Chef》中 下单界面的 userActivity 用户信息字典可能包含三个 Key “soup” “quantity” 和 “scrollPosition (滚动位置)” 由于最后一个的存在 在“接力”中 你可以将用户 带回到他最后所浏览的那个位置
我们看看这要怎么 建议给用户 首先我们递交一个 NSUserActivity 其中汤是 “tomato” 数量是 “1” 滚动位置是 “79.0” 接下来我们递交一个相似的 NSUserActivity 但是滚动位置 却变成了 “110.0”
我们继续操作 在某一时刻 Siri 可能会再次试着寻找一个建议 它会查看过去的行为 然后寻找相同的 NSUserActivity 的规律 由于滚动位置每次都不一致 它可能不会找到合适的建议
那我们要如何修复呢
我们可以使用 requiredUserInfoKeys
requiredUserInfoKeys 是一种 NSUserActivity 的现有属性 它代表了为了复原 App 到 userActivity 展示的状态 所需的最少的信息数量 至于建议 它会被用来指定 用户信息字典中哪些关键信号 会在寻找规律时用来进行对比
让我们将其应用在 刚刚的例子中
现在我们可以注明 requiredUserInfoKeys 是汤和数量 我们再次递交 汤是 “tomato” 数量是 “1” 滚动位置是 “79.0” 的 userActivity 不过这次滚动位置将被忽略
接下来 我们递交一些 相似的东西 这些滚动位置 也被忽略了 我们一直重复 在某些时刻 Siri 会再次尝试推荐
现在 Siri 会回顾 然后试着为相似的 userActivity 寻找一个规律 因为不再考虑 滚动位置 她可能会想 “一个汤是 ‘tomato’ 数量是 ‘1’ 的 NSUserActivity 可能对这个用户来说 是一个不错的建议”
如你所见 根据需求标明 正确的关键元素很重要 否则你的用户可能 不能获得任何建议 这就是它如何与 userActivity 协作的
Intent 的工作原理与这个相似 但是却更加灵活 Intent 的主要信号是 你定义的捷径类型
每一种捷径类型 都定义了 对于建议来说有效的参数组合 这与 requiredUserInfoKey 有点相似 但是与其只有一个组相比 我们在这里可以定义多个 让我们在《Soup Chef》App 中 应用一下 早些时候 我通过三个参数 即 “soup” “quantity” 和 “options” 定义了一个 OrderSoupIntent 当时 我只定义了 一个包含所有这些参数的单一的捷径类型 但是 理想地说 你可以定义更多捷径类型 因为这能为系统 寻找用户行为的规律提供了更多选择 现在我要定义三个
一个捷径类型结合了 “soup” 和 “quantity” 一个结合了 “soup” 和 “options” 还有一个结合了三个参数
让我们在另一个例子中看一看
我再次从周一开始 在午餐时间 点一个加面包丁的番茄汤 《Soup Chef》将这个递交给系统 然后系统将会 根据我刚刚定义的 捷径类型 将把它分成 所有可能的组合 当天晚上 我点了一份 加红辣椒的番茄汤 它再次被递交 也被分解成所有 有可能的组合
第二天的午饭 我点了一份 加面包丁的番茄汤 它被递交并分解 我整周都重复这个操作 在周五的午餐时间 Siri 可能会尝试对我建议
它可能会看到 我经常点番茄汤
不过因为是午餐时间 它也能看到在午餐时间 我通常会在番茄汤里加面包丁
这是一个更具体的捷径 它最后会 这样建议 所以我可能会被建议 点一份加面包丁的番茄汤 很好 这就是如何 完成建议 现在让我们看看 如何确保这些推荐是好的 首先需要做的是 有一个好的 Donation 一个好的 Donation 应该是一些很大概率重复的东西 对于 userActivity 来说 应该是一些用户经常查看的内容 或者对于 Intents 来说 应该是一些用户会规律做出的动作 你应该确保 你递交的载荷 与你所有的 Donation 都是相一致的 因为这是 系统在寻找规律时 对比的东西 一个好的 Donation 应该不仅包括 时间标记 因为当这个 Donation 被推荐时 它可能不会再与 特定时间相关
比如说 一个展示 某个特定日期的会议的 捷径可能没那么有用 因为 如果你第二天 或者之后看到这个提醒 你可能对这个 特定的一天的会面 不再感兴趣了
一个有着相对时间的捷径 却更加有用 你应该确保 你为每一个用户行动 进行一次递交 即便那个用户行动包括 在你 App 内多次的行动 最后 为你的 Intent 选择正确的参数也是非常重要的 所以我们来看一下 两种可能的类型 首先是枚举 你可以在 Intent 旁边的 Intent 定义文件中 定义枚举 并将其作为你参数的类型 我们建议每当 参数的数值有界时 你都使用枚举 比如说 如果你想为 OrderSoupIntent 添加一个 规格参数 那么将其 做成枚举可能会比较有意义 因为可能的规格一般是 小份 中份 大份
使用枚举可以为你的用户提供 更好的建议和 更清晰的标题和副标题 想要学习更多关于 如何用枚举生成标题和 副标题的内容 我建议大家观看本地化讲座 另一个你可以使用的类型是 “Custom(自定)”类型
使用自定类型最终会 得到一个 INObject 并生成 Intent 代码
INObject 结合了 一个标识符和一个显示字符串 这个标识符可以用来 指代你的 App 中的 一个内部对象 显示字符串则包含 一个标识符和一个代表形式 这样你的用户和 App 都可以知道 这个参数的数值是多少
最后 使用一个 INObjec 也会防止参数之间 可能出现的依赖性 让我来示范一下 总共有两种办法来 代表拥有一个字符串的 标识符的融合 你可以为你的 Intent 增加两个参数 一个是给标识符 一个是给显示字符串 或者你还可以使用 INObject 来增加单个 如果用第一种方法 你会有一个依赖 因为显示字符串依赖于 被标识符引用的对象 我们不鼓励这类 依赖的产生 因为在我们之后建议 Intent 时 这些依赖可能会引发问题 一个好的捷径还应该 拥有一个可以理解的标题 副标题 还有图像 它应该展现当用户 点击捷径时会发生什么 因为这是用户在 与其互动前 看到的唯一的东西 当然了 你应该测试你的捷径 来保证它们 看起来是正确的 而且他们会像预期的 那样工作 有一些方法来做到这点 正如我早些时候展示给你的 我们增加了两个新的开发者设置 可以让你在搜索界面 和锁定屏幕上 看到你最近的 Donation 而不是你常规的 Siri 推荐
打开这个你就可以看到 当这些 Donation 被建议时 你的用户会看到的东西 你可以试着与其互动 这样就能保证 它能按预期工作 另外一个测试你的 捷径的方法 就是将其添加到 Siri 一个测试它们的简单方法就是 通过编辑 Xcode Scheme 在不需要重复短语 的情况下 来自动唤醒 Siri
在 Intent 扩展的 Scheme 编辑器中 有一个 Siri Intent Query 栏 你可以用它来提供 唤醒 Siri 的语音 最后 你可以在捷径 App 中 创建一个自定捷径 来使用你的捷径
这允许你测试 当你的捷径与从捷径 App 中的其他捷径 或者步骤捆绑在一起的 你的捷径的表现 我们已经看到了 什么是好的 Donation 以及如何向用户建议这个 Donation 我们再来看看一些 关于隐私的考虑 以及如何确保 你的用户 不对给他们的建议感到失望
你的用户希望当他们 从你的 App 中删除一些东西时 这个删除是永久的 这一点很重要 这样你就可以获得你用户的信任 他们也不会 再收到与他们想要的 毫不相关的信息了
如果你的捷径 包含一些用户可以删除的 信息 你应该 在合适的时间 删除它们 我们来看看 如何删除 从 NSUserActivity 开始
有两种方法来删除一个 已递交的 userActivity
如果你使用“聚焦”索引 你可以设定 relatedUniqueIdentifier 然后从“聚焦”删除的内容 就会自动 删除递交的 userActivity
只需要在 contentAttributeSet 里 将 relatedUniqueIdentifier 设定为与可搜索的对象 相匹配的标识符 接着 当可搜寻对象被删除时 它会自动删除 userActivity 如果你不使用“聚焦”索引 你可以使用 NSUserActivity 中的 持续标识符属性 这是一个你可以设置的新属性 这样你就可以追踪你的 userActivity 并在合适的时间 删除它们 要想使用它 只需要在递交 userActivity 前 设定 persistentIdentifier 属性 如果你想要将其删除 你可以调用 deleteSavedUserActivities 并填入你想要删除的标识符 你还可以删除所有 递交的 userActivity
比如说 当你的用户 退出登录时 你可以调用 deleteAllSavedUserActivities
Intents 拥有现成的 API 与新的 userActivity API 相似 因为你通过 INInteraction 主导 Intent 的 Donation 删除 Intent 也会通过 INInteraction 发生 一个 INInteraction 拥有一个 标识符和一组 你可以设置的标识符性能 然后用它来删除 一个或多个已经递交的 interaction 在递交 interaction 前 设定标识符或组识别符
当你想要删除时 你可以调用 delete 并填入你想删除的标识符阵列 你还可以通过调用delete 并填入组标识符 删除所有拥有 同样组标识符的已递交 Intent 最后 就如 NSUserActivity 一样 有一种可以删除 所有你递交的 Intent 的方法 即在 INInteraction 调用 deleteAll
请确保在合适的时机 并填入你想删除的 Donation 这会给你的用户 最好的建议 也不会让他们思考 为什么会给他们建议 与他们毫无关联的信息
我们已经观看了 在创造和递交捷径时 应该考虑的事情 让我们最后简单地 看一下怎么创造 最好的媒体捷径 我们创建了一个与捷径 配合很好的新 Intent 这个 Intent 被称作 INPlayMediaIntent 它可以允许你创建和递交 可以播放音频或视频内容的捷径
处理扩展中的 Intent 时 你可以选择 在你的 App 后台处理它 这可以让你直接从你的 App 开始音频播放
除了在搜索界面 或者锁定屏幕上被建议 拥有这个 Intent 的捷径 也应该在用户 连接耳机时 在锁定屏幕上被播放控制所推荐 这样用户可以 更容易地 听到你的内容
最后 拥有这个 Intent 的捷径 在 HomePod 上 也运行得很好
只需要在你的 iPhone 上 对 Siri 增加一个播放媒体的捷径 然后在你的 HomePod 上唤醒它 这个音频就会在你的手机上 通过 HomePod 播放
我们还创建了一个新 API 来让你能告诉系统 它可能会感兴趣的内容
这对于周期性的内容来说 非常棒 因为你想要建议给用户的 是他们之前没有听过或看过的内容
这里有一些我们为了 制作好的媒体捷径 而增加的东西 现在 让我们总结一下 刚刚说的内容
捷径可以让你的 App 有着强有力的 全新的体验 它通过将你的 App 在不同的地方连通 从而为吸引用户提供了 一个新方法 比如在搜索界面上 在锁定屏幕上 在 Apple Watch 上的 Siri 表盘上 以及通过 Siri 自身搜索 你可以在新的捷径 App 中使用它 你可以通过使用 NSUserActivity 来采用捷径 这是一种展示 App 内容的 简单方法 你还可以采用与系统 有更深的融合的 Intent 从而为你的用户 解锁一个 全新的体验 如果想要了解更多的信息 我们的会议号码是 211 你可以在 developer.Apple.com 上找到我们的页面 你还可以在这周内 去我们的实验室找我们 感谢你的聆听 我们迫不及待地想要看到 你创建的捷径 祝你在接下来的会议愉快 [ 掌声 ]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。