介绍
自2011年推出Siri以来,iOS开发人员一直在寻求将第三方应用与其集成的可能性。 随着WWDC 2016期间iOS 10的发布,Apple终于向开发人员提供了SiriKit。 哪些类型的应用程序可以利用Siri仍然存在一些限制,但这是朝着正确方向迈出的一步。 让我们来看看Siri可以做什么。
支援网域
要使用SiriKit,您的应用必须位于以下一个或多个域中:
- VoIP通话(例如,Skype)
- 消息传递(WhatsApp)
- 付款(平方,贝宝)
- 照片(照片)
- 锻炼(Runtastic)
- 乘车预订(Uber,Lyft)
- CarPlay(仅限汽车供应商)
- 餐厅预订(需要Apple的额外支持)
如果您的应用不属于上述任何类别,那么很遗憾,您目前无法在应用中使用Siri。 不过,请不要离开,因为SiriKit非常强大,并且将来可能会获得新功能!
扩展架构
实际上,SiriKit扩展由两种类型的扩展组成。 Intents
扩展程序是必需的,它负责处理用户的请求并在您的应用程序中执行特定任务(例如,启动呼叫,发送消息等)。
另一方面, IntentsUI
扩展不是必需的。 仅当您要自定义Siri在显示数据时显示的用户界面时,才应创建一个。 如果您不这样做,则将显示标准Siri界面。 在本教程中,我们将介绍两种扩展类型。
供您参考,Apple在WWDC 2016期间发布了两个非常有趣的有关SiriKit的视频。 您可能需要检查一下它们:
示例项目
我们将构建一个简单的应用程序,通过Siri处理付款。 目标是成功处理句子“通过TutsplusPayments向Patrick寄出20美元”。 句子的格式包括具有特定货币的金额,收款人的姓名以及用于完成交易的应用程序。 稍后我们将更详细地分析付款意图。
最初设定
让我们首先在Swift中创建一个标准的Xcode项目并为其命名。 在编写任何代码以使您的应用程序可以使用Siri的API之前,您必须执行一些强制性步骤。
1. 选择焦油 GET>功能 ,并启用Siri的能力。 确保在您的项目结构中成功创建了权利。
2.打开应用程序的Info.plist
并添加密钥NSSiriUsageDescription
。 该值必须是一个说明您对Siri用法的字符串,当要求初始许可时,该字符串将显示给用户。
3.选择文件>新建>目标 。 在Xcode呈现的新窗口中的“ 应用程序扩展”下 ,选择“ 意图扩展” 。 还选择包含UI扩展的选项。 这样可以避免以后创建另一个单独的扩展名。
在新创建的Intents
目标的Info.plist
文件中,完全展开NSExtension
词典以研究其内容。 该词典更详细地描述了扩展支持的意图,以及是否要允许用户在设备锁定时调用意图。
如果要支持多个目的,请在顶部插入最相关的意图。 Siri使用此顺序来找出用户要使用的模棱两可的情况。
现在,我们需要定义我们要支持的意图。 在此示例中,我们将构建一个支持付款意图的扩展。 修改Info.plist
文件以匹配下图。
在这里,我们指定我们要处理INSendPaymentIntent
并要求设备解锁。 我们不希望陌生人在设备丢失或被盗时发送付款!
iOS目标
下一步实际上涉及在iOS应用中编写一些代码。 我们必须征求用户的许可才能将其声音发送给Apple进行分析。 我们只需要导入Intents
框架并调用适当的方法,如下所示:
import UIKit
import Intents
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Ask permission to access Siri
INPreferences.requestSiriAuthorization { authorizationStatus in
switch authorizationStatus {
case .authorized:
print("Authorized")
default:
print("Not Authorized")
}
}
}
}
在应用程序首次启动期间向用户显示的结果对话框将如下所示。
这就是我们在简单的iOS应用中所要做的全部。 让我们现在进入扩展世界!
意图扩展
切换到我们之前创建的Intents
扩展。 在Xcode项目导航器中展开其内容。 您只会看到一个名为IntentHandler.swift
文件。
该文件是扩展程序的入口,用于处理Siri发送给您的所有意图。 如果您的扩展支持多种类型,Siri会将所有意图转发给handler(for:)
方法。 检查INIntent
对象的类型并适当地处理它是您的工作。
IntentHandler.swift
模板已经包含Messaging目的的示例实现。 用以下空方法替换所有代码,以便我们可以逐步完成每个步骤。
class IntentHandler: INExtension {
override func handler(for intent: INIntent) -> Any? {
// 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.
return self
}
}
每个意图都有一个相关的协议,以确保一个类实现所有必需的方法。 Intents框架中的大多数协议都具有相同的结构。
我们将要实现的协议称为INSendPaymentIntentHandling
。 该协议包含以下必需和可选方法:
- 需要:
handle(sendPayment:completion:)
- 可选的:
confirm(sendPayment:completion:)
resolvePayee(forSendPayment:with:)
resolveCurrencyAmount(forSendPayment:with:)
resolveNote(forSendPayment:with:)
让我们在同一Swift文件中创建IntentHandler
类的扩展,以实现唯一所需的方法。
extension IntentHandler: INSendPaymentIntentHandling {
func handle(sendPayment intent: INSendPaymentIntent, completion: @escaping (INSendPaymentIntentResponse) -> Void) {
// Check that we have valid values for payee and currencyAmount
guard let payee = intent.payee, let amount = intent.currencyAmount else {
return completion(INSendPaymentIntentResponse(code: .unspecified, userActivity: nil))
}
// Make your payment!
print("Sending \(amount) payment to \(payee)!")
completion(INSendPaymentIntentResponse(code: .success, userActivity: nil))
}
}
这是一个非常基本的实现。 我们确保有有效的payee
和currencyAmount
将交易设置为成功。 您可能不相信它,但是它已经起作用了! 从Xcode中选择Intents方案并运行它。 当Xcode显示通常的菜单以选择要运行的应用程序时,请选择Siri。
当Siri启动时,尝试说“通过TutsplusPayments将20美元发送给Patrick”。 现在,享受您用语音完成的首次成功付款!
您也可以尝试测试失败的情况。 尝试说与以前相同的句子,但不指定收款人(即:“通过TutsplusPayments发送$ 20”)。 您会看到Siri失败,并向用户显示一个按钮以继续在您的应用程序中付款。
如果Siri无法理解或未提供其中一个可选参数,但您需要一个有效值,则可以实现resolve方法之一。 这些方法为用户提供了一个选项,以提供有关付款的更多详细信息,例如收款人姓名,确切的货币金额,甚至是便条。 借助此API的智能体系结构,您作为开发人员可以轻松而清晰地以不同方式理解用户的请求。
在真实世界的应用程序中,您将创建一个动态框架,该动态框架将在您的iOS应用程序和扩展之间共享。 通过使用此体系结构,您可以在多个目标中共享相同的业务逻辑。 您无需多次实施它,而只需一次实现所有目标!
意图UI扩展
在本教程的最后一部分,我将向您展示如何自定义Siri显示的用户界面。
首先,请记住要像在上一节中所做的那样,在ExtensionUI
的Info.plist
中设置要处理的正确的意图类。
跳到Intents UI扩展,您将看到Xcode为您创建的模板。 它包含一个IntentViewController
,它是实现INUIHostedViewControlling
协议的UIViewController
的简单子类。 还为您创建了一个情节提要文件。 打开它,以便我们可以开始自定义用户界面。
添加一个UIImageView
作为背景,并在中心添加一个标签。 下载背景图像 ,将其导入Intents UI目标,并将其设置为新创建的UIImageView
的图像。 创建一个UILabel
对象,并将其放置在视图的中心。 您可以轻松使用AutoLayout
在Storyboard中设置约束。
打开助手编辑器,为标签创建一个@IBOutlet
,并将其@IBOutlet
为contentLabel
。 结果应如下所示:
打开IntentViewController
文件,您将看到很多示例代码。 您可以删除除我们现在要实现的configure(with:context:completion:)
方法之外的所有内容。 当准备好配置用户界面时,将调用此方法。 我们要做的是设置UILabel
的内容。
class IntentViewController: UIViewController, INUIHostedViewControlling {
@IBOutlet weak var contentLabel: UILabel!
// MARK: - INUIHostedViewControlling
func configure(with interaction: INInteraction!, context: INUIHostedViewContext, completion: ((CGSize) -> Void)!) {
if let paymentIntent = interaction.intent as? INSendPaymentIntent {
// If any of this properties is not set, use the default UI.
guard let amount = paymentIntent.currencyAmount?.amount, let currency = paymentIntent.currencyAmount?.currencyCode, let name = paymentIntent.payee?.displayName else {
return completion(CGSize.zero)
}
let paymentDescription = "\(amount)\(currency) to \(name)"
contentLabel.text = paymentDescription
}
if let completion = completion {
completion(self.desiredSize)
}
}
var desiredSize: CGSize {
return self.extensionContext!.hostedViewMaximumAllowedSize
}
}
首先,我们检查intent
对象是否为INSendPaymentIntent
类型。 如果是的话,我们还要确保要显示的所有属性都不为nil
,否则我们只需调用大小为零的完成块来隐藏我们的自定义视图。 如果一切都按预期进行,我们将使用要显示给用户的数据创建一个自定义字符串,并将其设置为contentLabel
的文本。
再次运行扩展程序,您将在Siri中看到新视图!
Siri仍显示默认视图。 我们可以通过使我们的视图控制器符合INUIHostedViewSiriProviding
协议来隐藏它。
class IntentViewController: UIViewController, INUIHostedViewControlling, INUIHostedViewSiriProviding {
// Previous code goes here...
var displaysPaymentTransaction: Bool {
return true
}
}
通过在displaysPaymentTransaction
变量中返回true
,我们告诉Siri我们的视图控制器正在照顾向用户显示所有必要的信息,并且可以隐藏默认视图。 结果现在更加干净!
注意:如您在这张照片中看到的,当指定不同于美元的货币时,Siri会正确理解货币代码并将其返回给扩展程序。 不幸的是,文本始终显示美元。 我已将此错误报告给Apple!
结论
希望您喜欢本教程。 即使当前仅限于某些类型的应用程序,Siri也非常强大。 如果您打算在自己的应用程序中实现它,请确保将其很好地推销给您的用户,因为他们可能不知道您的应用程序变得多么酷炫和先进!
翻译自: https://code.tutsplus.com/tutorials/create-sirikit-extensions-in-ios-10--cms-27924