SiriKit框架详细解析(八) —— 构建Siri Shortcuts简单示例(二)

版本记录

版本号 时间
V1.0 2018.12.06 星期四

前言

大家都知道随着人工智能的发展,会掀起来另外一个工业革命,而语音识别就是人工智能的初始阶段,但是每个公司做的都不一样,涉及到一系列的语音的采集和算法实现,苹果的Siri就是业界语音识别的代表性的产品。接下来的几篇我们就详细解析一下SiriKit这个框架。感兴趣的可以看下面几篇文章。
1. SiriKit框架详细解析(一)—— 基本概览(一)
2. SiriKit框架详细解析(二)—— 请求授权使用SiriKit和INPreferences类(一)
3. SiriKit框架详细解析(三)—— 创建Intents App扩展(一)
4. SiriKit框架详细解析(四)—— 构建代码以支持App扩展和将意图调度到处理对象(一)
5. SiriKit框架详细解析(五) —— 编程指南之Intents和Intents UI扩展(一)
6. SiriKit框架详细解析(六) —— 编程指南之确认和处理请求、指定自定义词汇表和界面(一)
7. SiriKit框架详细解析(七) —— 构建Siri Shortcuts简单示例(一)

Publishing Articles with Siri

接下来,您希望添加发布直接从Siri编写的文章的功能。 这里的最大区别在于,不是Siri打开你的应用程序,一切都将直接来自Siri UI

对于此快捷方式,您将创建一个自定义Intent来定义Siri,您的用户和您的应用之间的来回。

1. Defining a Custom Writing Intent

在项目导航器中,找到ArticleKit文件夹并单击它以突出显示它。

然后,按Command + N创建一个新文件。

在过滤器搜索框中,键入Intent,您将看到SiriKit Intent Definition File

单击Next,然后将文件命名为ArticleIntents.intentdefinition

现在是时候创建一个发布你写的文章的intent了。

转到读取No Intents的部分的底部,然后单击加号按钮以添加新的intent意图。

将其命名为PostArticle,然后根据这些设置配置您的意图(在图片后面描述):

此屏幕用于配置发布intent需要处理的信息。

Custom Intent部分中的选项定义了它的意图类型,并且可以影响Siri如何处理该操作。 告诉Siri这是一个Post类型动作让系统知道你在某处分享了一些内容:

  • 1) CategoryPost
  • 2) TitlePost Article
  • 3) DescriptionPost the last article
  • 4) Default Image: Select one of the existing images in the project
  • 5) Confirmation: Check this box since you want to ask the user to verify that they’re really ready to publish this article

Parameters部分用于定义TitleSubtitle中使用的任何动态属性,您现在可以使用这些属性。

定义一个名为article的参数,它是一个Custom数据类型,一个是类型为StringpublishDate

然后,在Shortcut Types部分中,单击加号按钮以添加一个包含articlepublishDate参数作为其参数的类型。

接下来,设置快捷方式的TitleSubtitle

将标题设置为Post “${article}”和副标题设置为on ${publishDate}。 如果您不复制和粘贴,请确保让Xcode自动完成articlepublishDate

最后,确保选中Supports background execution,这样您就不会被迫离开Siri UI

2. Setting Up Siri’s Responses

单击Response,您可以定义Siri将如何响应用户。

再次,配置您的响应,如下所示:

Properties下,您可以再次定义Siri所说的动态部分。 添加titlepublishDatefailureReason的属性;把它们都定义为字符串。

然后,在Response Templates下,为failure添加此模板:

Sorry, but I couldn't post your article. ${failureReason}

为成功添加以下模板

Your article "${title}" was successfully posted on ${publishDate}. Nice work!

3. Adding a Siri Extension

为了能够在不启动应用程序的情况下继续使用Siri的UI,您需要使用可以管理交互的代码创建Intents Extension

单击左上角的项目文件,然后找到允许您添加新目标的加号。

现在,找到Intents Extension目标;您可以在过滤搜索栏中搜索它。

然后,将您的意图扩展名为WritingIntents,将Starting Point设置为None,并取消选中Include UI Extension选项。

最后,单击Finish按钮以创建扩展。 构建并运行以确保事情仍然有效。

注意:当Xcode提供激活WritingIntents方案时,单击Cancel

没什么新鲜的,但现在你已经准备好使用你的custom intents了!

在继续之前,您需要做两件快速的事情。

首先,确保扩展名中可以看到ArticleIntents.intentdefinition

打开文件,然后查看File inspector。 确保其Target Membership包括应用程序,框架和扩展。 此外,请确保将应用程序和扩展目标的代码生成选项更改为No Generated Classes,因为此代码应存在于框架中。

接下来,您的扩展程序和主应用程序需要共享一个应用程序组。 由于文章保存到磁盘并从磁盘加载,因此这是两个目标在文件系统上共享同一区域的唯一方法。

单击Project导航器中的项目文件,确保选择了TheBurgeoningWriter并转到Capabilities选项卡。

App Groups功能切换为ON,并命名组为group.<your-bundle-id>

接下来,选择WritingIntents扩展并执行相同的操作。 这一次,该组应该存在,因此您可以只检查该框。

最后,打开ArticleManager.swift并找到groupIdentifier的声明。 更改其值以匹配新定义的应用程序组名称。

注意:此更改后,您输入的先前文章将不再显示在应用中。 这是预期的,因为它们存储在文件系统中的不同位置。

4. Donating Post Article Intents

现在您已经定义了发布文章的intent,现在是时候在适当的时候创建和提交一个。

再一次,前往Article.swift,这样你就可以添加一种方法来为新文章生成“post”intents

newArticleShortcut(thumbnail :)的定义下方,添加以下方法定义:

public func donatePublishIntent() {

}

此方法一次创建并提供intent,因为您不需要处理向视图控制器添加intents

现在,创建intent对象并分配article and publish date

let intent = PostArticleIntent()
intent.article = INObject(identifier: self.title, display: self.title)
intent.publishDate = formattedDate()

当使用自定义intent时,您最终提交给系统的事情就是这样的交互。

最后,通过在交互上调用donate(_ :)来提交:

interaction.donate(completion: nil)

在这里,您将提交您的互动,而不必担心completion块。 当然,您可以将错误处理或其他任何内容添加到此完成块中。

您必须完成最后一次“secret handshake”步骤:您必须告诉iOS确切的应用程序支持的intents。 为此,请单击Project导航器中的项目文件。 选择WritingIntents目标,然后单击Info选项卡。 按住Option键并单击NSExtension键旁边的显示三角形以打开整个键。 将鼠标悬停在IntentsSupported上以显示加号按钮并单击一次。 将新添加的项的值设置为PostArticleIntent

这就是向系统提交intent-based的快捷方式的全部内容。

现在您已经定义了方法,转到NewArticleViewController.swift并找到saveWasTapped()。 由于您希望系统提示用户发布他们以后保存的文章,因此您可以在这里实现。

添加此行以在该方法中的注释下方提交intent

article.donatePublishIntent()

现在您正在提交,构建和运行应用程序。 然后,创建并保存新文章。 完成后,转到Spotlight搜索,您应该会看到一个类似于此的新提交。

5. Handling Intents-Based Shortcuts

像以前一样,您现在必须考虑在用户使用它时处理此快捷方式。

这一次,您创建的扩展将负责处理事物。

首先,在名为PostArticleIntentHandler.swiftWritingIntents文件夹中添加一个新的Swift文件。

用以下内容替换import Foundation

import UIKit
import ArticleKit

class PostArticleIntentHandler: NSObject, PostArticleIntentHandling {
  func confirm(intent: PostArticleIntent, 
               completion: @escaping (PostArticleIntentResponse) -> Void) {

  }

  func handle(intent: PostArticleIntent, 
              completion: @escaping (PostArticleIntentResponse) -> Void) {

  }
}

在这里,您将创建一个类来处理涉及您的发布article intent的交互。

符合PostArticleIntentHandling协议意味着您需要实现一个涉及确认步骤的方法和一个用户在确认后处理意图的方法。

接下来,添加以下代码到confirm(intent:completion:)

completion(PostArticleIntentResponse(code: PostArticleIntentResponseCode.ready,
                                     userActivity: nil))

这表示如果用户点击确认,则扩展已准备好接受意图。

接下来,您将实现handle(intent:completion:)

这是真正的选择发挥作用的地方。 由于用户试图发布文章,因此只应在成功消息的情况下响应。

首先,在找不到他们选择的文章时添加此保护声明:

guard let title = intent.article?.identifier,
    let article = ArticleManager.findArticle(with: title) else {
        completion(PostArticleIntentResponse
          .failure(failureReason: "Your article was not found."))
        return
}

这会使用failure意图响应调用completion块。 它唯一的参数叫做failureReason,因为你之前创建的失败响应模板在模板中有failReason变量。

接下来,为本文已发布时添加一个guard

guard !article.published else {
    completion(PostArticleIntentResponse
      .failure(failureReason: "This article has already been published."))
    return
}

最后,对于成功情况,您将发布文章并使用成功响应调用completion块。 这包括文章的标题和发布日期:

ArticleManager.publish(article)
completion(PostArticleIntentResponse
  .success(title: article.title, publishDate: article.formattedDate()))

现在您已经设置了intent处理程序,您必须确保它已被使用。

打开IntentHandler.swift并用以下内容替换现有的handler(for:),告诉系统使用刚写的处理程序:

override func handler(for intent: INIntent) -> Any {
  return PostArticleIntentHandler()
}

接下来,打开AppDelegate.swift并找到application(_:continue:restorationHandler:)

您可能没有想到的是,即使您有自己的处理程序来处理此快捷方式,仍会调用应用程序委托中的continue user activity callback

要阻止该方法将用户从Siri中删除并进入new article view,请添加以下guard

guard userActivity.interaction == nil else  {
    ArticleManager.loadArticles()
    rootVC.viewWillAppear(false)

    return false
}

如果活动附加了交互,则表示其为“publish”快捷方式,您需要加载文章并确保重新加载feed view controller

构建并运行,然后编写新文章以提交其中一个快捷方式。

注意:您可以放心地忽略有关链接到dylib的警告,该dylib在应用程序扩展中不安全。

接下来,进入Settings并使用标题为其创建快捷方式;像“Post my last article”有效的工作。

之后,启动Siri并使用您的快捷方式;Siri将为您发布该文章,并回复一个自定义回复,通知您标题和发布日期。

6. Wrapping Up

您需要担心的最后一件事是从系统中删除intents。 假设用户删除了他们编写的唯一文章。 如果Siri提示他们发布这篇文章,那意味着系统会记住他们想要删除的信息。

由于这违反了Apple对用户隐私的严格尊重,因此删除已删除的活动和意图是您的职责。

转到ArticleFeedViewController.swift并滚动到文件的底部。

然后,将以下方法调用添加到remove(article:indexPath:)的底部:

INInteraction.delete(with: article.title) { _ in
}

completion块允许您对您认为合适的删除错误做出反应。

由于新文章快捷方式不包含任何用户数据,因此不一定要删除它。

最后,打开Layouts.swift并找到ArticleFeedViewControllerUITableViewDataSource扩展。 在扩展名末尾添加以下内容以启用删除文章:

func tableView(_ tableView: UITableView,
                 commit editingStyle: UITableViewCell.EditingStyle,
                 forRowAt indexPath: IndexPath) {
  if editingStyle == .delete {
    let article = articles[indexPath.row]
    remove(article: article, at: indexPath)
    if articles.count == 0 {
      NSUserActivity.deleteSavedUserActivities(withPersistentIdentifiers: 
        [NSUserActivityPersistentIdentifier(kNewArticleActivityType)]) {
          print("Successfully deleted 'New Article' activity.")
      }
    }
  }
}

如果需要,可以使用NSUserActivity的类方法deleteSavedUserActivities(withPersistentIdentifiers:completionHandler :)来删除使用单个标识符提交的所有活动。

如果您想了解有关Shortcuts的更多信息,请查看2018年的两个WWDC视频。第一个first presentation涵盖了许多与本教程相同的材料,并且是一个很好的复习,以巩固您在这里学到的重要想法。 第二部分 second更多地涉及最佳实践。

后记

本篇主要介绍了构建Siri Shortcuts简单示例,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容