sirikit
In this tutorial, we’ll be discussing how to use Siri capabilities in iOS Apps. We’ll be creating our own ios application shortcut through which Siri would tell us the Latest tutorial released on Journaldev.
在本教程中,我们将讨论如何在iOS应用中使用Siri功能。 我们将创建自己的ios应用程序快捷方式,Siri可以通过它告诉我们Journaldev上发布的最新教程。
Siri is the popular personal assistant found in Apple devices. It helps us and communicates our requirements with the applications. If the applications support the feature they execute it.
This is in layman terms.
Siri是Apple设备中流行的个人助理。 它可以帮助我们并将需求与应用程序进行通信。 如果应用程序支持该功能,则将其执行。
这是外行的说法。
For developers, Apple has introduced Sirikit toolkit to allow implementing your app features with Siri.
Sirikit for developers was introduced with iOS 10 with the following Domains/Categories allowed:
对于开发人员,Apple引入了Sirikit工具包,以允许使用Siri实现您的应用程序功能。
iOS 10引入了针对开发人员的Sirikit,其中允许以下域/类别:
With the introduction of iOS 12, Siri Shortcuts have been exposed which allow providing key capabilities of your application to Siri. You can use the Shortcuts by saying the respective phrase to Siri.
随着iOS 12的引入,Siri快捷方式已公开,可以为Siri提供应用程序的关键功能。 您可以通过对Siri说相应的短语来使用快捷方式。
Siri also predicts the right time to show you a shortcut on your lock screen. Clicking the shortcut handles the Intent defined for that shortcut. Applications can also provide their own custom UI which would be shown by Siri.
Siri还会预测在正确的时间在锁定屏幕上向您显示快捷方式。 单击快捷方式将处理为该快捷方式定义的Intent。 应用程序还可以提供自己的自定义UI,Siri将显示这些UI。
How does Siri adopt the Shortcuts defined by the Application?
You need to donate the Shortcuts either using NSUserActivity or using Intents
.
Siri如何采用应用程序定义的快捷方式?
您需要使用NSUserActivity或Intents
捐赠快捷方式。
Intents use INInteraction
class to donate shortcuts.
意图使用INInteraction
类捐赠快捷方式。
In this tutorial, we’ll focus on donating shortcuts using Intents.
在本教程中,我们将重点介绍使用Intents捐赠快捷方式。
Intents are a framework used to define the type of requests and handle the responses from Siri.
意图是用于定义请求类型和处理来自Siri的响应的框架。
To create shortcuts you need to use the following:
要创建快捷方式,您需要使用以下内容:
Resolving the voice message – Based on the voice message from the user, it fetches the important parameters that are required for running the Shortcut.
解决语音消息–根据用户的语音消息,它获取运行快捷方式所需的重要参数。
Confirming – The user can confirm the request one last time (provided a confirmation is set in the code).
确认 –用户可以最后一次确认请求(前提是在代码中设置了确认)。
Handling – Handling the intent i.e. matching the type of the intent from the ones defined and executing.
处理 –处理意图,即从已定义和执行的意图中匹配意图的类型。
The above concepts are easier when explained through code.
Let’s start by creating a new XCode project.
通过代码解释时,上述概念更容易。
让我们从创建一个新的XCode项目开始。
We’ll be creating a Siri Shortcut that :
我们将创建一个Siri快捷方式:
https://www.journaldev.com/wp-json/wp/v2/posts?filter[posts_per_page]=1&page=1
Following is the gist to create a Siri Shortcut:
以下是创建Siri快捷方式的要点:
info.plist
在info.plist
提及您的意图 Create a new XCode project as Single View Application.
创建一个新的XCode项目作为Single View Application。
Enable Siri Capabilities:
启用Siri功能:
Note: To enable Siri capabilities you must have an Apple Developer Account.
注意:要启用Siri功能,您必须具有Apple开发者帐户。
Once Siri capabilities is enabled, an entitlements
file is created.
启用Siri功能后,将创建一个entitlements
文件。
Create a custom intent
创建自定义意图
We need to create a custom intent file in order to perform our specific request with Siri.
Add the following file:
我们需要创建一个自定义的Intent文件,以便对Siri执行特定的请求。
添加以下文件:
Defining Intents
定义意图
Goto File | New | Target
转到文件| 新增| 目标
We’d checked the Intents UI to create the target for the same.
我们已经检查了Intents UI来为其创建目标。
Defining the custom intent
定义自定义意图
LatestArticle
by clicking on the plus symbol. 通过单击加号创建一个名为LatestArticle
的新意图。 Make sure that all the three targets are selected.
确保选择了所有三个目标。
Adding the Intent to the info.plist.
将Intent添加到info.plist 。
Make sure the Intent is added to all the three info.plist
files as shown below:
确保将Intent添加到所有三个info.plist
文件中,如下所示:
Let’s add the Alamofire pod dependency along with SwiftyJSON in our Xcode project from the terminal.
Goto the XCode project path and run the following commands
让我们在终端的Xcode项目中添加Alamofire pod依赖项以及SwiftyJSON。
转到XCode项目路径并运行以下命令
pod init
open -a Xcode Podfile
pod init
open -a Xcode Podfile
Add the pod dependencies in the Podfile at the top:
在顶部的Podfile中添加pod依赖项:
# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
pod 'Alamofire'
pod 'SwiftyJSON'
target 'IntentsTest' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for IntentsTest
end
target 'IntentsTestUI' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for IntentsTestUI
end
target 'SiriTest' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for SiriTest
end
Save the file and exit
保存文件并退出
pod install
pod install
Please close Xcode sessions and use .xcworkspace for opening this project from now on.
从现在开始,请关闭Xcode会话并使用.xcworkspace打开此项目。
Create a new Swift file APIController.swift and make sure all the targets are checked.
创建一个新的Swift文件APIController.swift并确保检查所有目标。
import Foundation
import Alamofire
import SwiftyJSON
struct APIController {
static var postId = ""
static var authorAPI = ""
func articleOfTheDay(completion: @escaping (String?) -> Void) {
Alamofire.request("https://www.journaldev.com/wp-json/wp/v2/posts?filter[posts_per_page]=1&page=1").responseJSON { response in
if let result = response.result.value {
let json = JSON(result)
let str = json.first?.1["title"]["rendered"].stringValue
let id = json.first?.1["id"].stringValue
let authorAPI = json.first?.1["_links"]["author"].first?.1["href"].stringValue
APIController.postId = id ?? ""
APIController.authorAPI = authorAPI ?? ""
completion(str)
}
}
}
func contentOfArticle(completion: @escaping (String?) -> Void) {
Alamofire.request(APIController.authorAPI).responseJSON { response in
if let result = response.result.value {
let json = JSON(result)
let str = "Author Name: \(json["name"].stringValue).\nTap to view article"
completion(str)
}
}
}
}
We’ve said the authorAPI
and post id
in static variables.
我们已经说过authorAPI
和静态变量中的post id
。
Let’s look at the Main.storyboard of the application :
让我们看一下应用程序的Main.storyboard:
It’s an empty view controller embedded in a Navigation View Controller.
这是一个嵌入在导航视图控制器中的空视图控制器。
Inside the ViewController.swift, we’ll add the configuration to donate the Siri Shortcut for the Intent defined earlier. We’ll also add an Add to Siri button to create a shortcut directly from the app itself.
在ViewController.swift中,我们将添加配置以为先前定义的Intent捐赠Siri快捷方式。 我们还将添加一个“添加到Siri”按钮,以直接从应用程序本身创建快捷方式。
Note: The intentdefinition file auto generates a Swift class when you rebuild the project.
注意:重建项目时,intentdefinition文件会自动生成一个Swift类。
import UIKit
import Intents
import os.log
import Foundation
import IntentsUI
import Alamofire
class ViewController: UIViewController, INUIAddVoiceShortcutViewControllerDelegate, INUIEditVoiceShortcutViewControllerDelegate {
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didUpdate voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID) {
controller.dismiss(animated: true, completion: nil)
}
func editVoiceShortcutViewControllerDidCancel(_ controller: INUIEditVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
controller.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
addSiriButton(to: view)
let apiController = APIController()
apiController.articleOfTheDay { (articleInfo) in
if let title = articleInfo {
self.updateUI(with: title)
}
}
donateInteraction()
}
func donateInteraction() {
let intent = LatestArticleIntent()
intent.suggestedInvocationPhrase = "Lookup JD"
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
if error != nil {
if let error = error as NSError? {
os_log("Interaction donation failed: %@", log: OSLog.default, type: .error, error)
} else {
print("Successfully donated interaction")
}
}
}
}
func updateUI(with titleInfo: String) {
self.title = titleInfo
}
func addSiriButton(to view: UIView) {
let button = INUIAddVoiceShortcutButton(style: .blackOutline)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
view.centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true
button.addTarget(self, action: #selector(addToSiri(_:)), for: .touchUpInside)
}
@objc
func addToSiri(_ sender: Any) {
let intent = LatestArticleIntent()
intent.suggestedInvocationPhrase = "Lookup JD"
if let shortcut = INShortcut(intent: intent) {
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self // Object conforming to `INUIAddVoiceShortcutViewControllerDelegate`.
present(viewController, animated: true, completion: nil)
}
}
}
addSiriButton
is used to add the UI for the built-in Siri Button.
suggestedInvocationPhrase
shows the suggested voice command for the shortcut. Though the user can use any.
donateInteraction
function is where we donate the intent to Siri. So you can create the shortcut from the Settings | Siri and Search too.
addSiriButton
用于添加内置Siri Button的UI。
suggestedInvocationPhrase
显示有关该快捷方式的建议语音命令。 尽管用户可以使用任何一个。
donateInteraction
函数是我们向Siri捐赠意图的地方。 因此,您可以从“设置” |“创建” Siri和Search也是如此。
The above code also updates the title of the ViewController with the latest article retrieved from the API call in the method updateUI
.
上面的代码还使用updateUI
方法中从API调用检索到的最新文章来更新ViewController的标题。
Now let’s goto the JDIntents folder | IntentHandler.swift
:
现在让我们转到JDIntents文件夹| IntentHandler.swift
:
import Intents
class IntentHandler: INExtension {
override func handler(for intent: INIntent) -> Any {
guard intent is LatestArticleIntent else {
fatalError("Unhandled intent type: \(intent)")
}
return ArticleIntentHandler()
}
}
Here we check the type of Intent and invoke the AricleIntentHandler.swift
class.
在这里,我们检查Intent的类型并调用AricleIntentHandler.swift
类。
import Foundation
class ArticleIntentHandler: NSObject, LatestArticleIntentHandling {
func confirm(intent: LatestArticleIntent, completion: @escaping (LatestArticleIntentResponse) -> Void) {
let apiController = APIController()
apiController.articleOfTheDay { (articleInfo) in
if let articleInfo = articleInfo {
if articleInfo.count > 0 {
completion(LatestArticleIntentResponse(code: .ready, userActivity: nil))
} else {
completion(LatestArticleIntentResponse(code: .failure, userActivity: nil))
}
}
}
}
func handle(intent: LatestArticleIntent, completion: @escaping (LatestArticleIntentResponse) -> Void) {
let apiController = APIController()
apiController.articleOfTheDay { (articleInfo) in
if let title = articleInfo {
completion(LatestArticleIntentResponse.success(articleTitle: title))
}
}
}
}
success is the response code defined in the intent definitions. articleTitle is the parameter
On completion, the response is sent to the Intent Definitions file and the articleTitle if fetched is displayed in Siri.
成功是意图定义中定义的响应代码。 articleTitle是参数
完成后,响应将发送到Intent Definitions文件,Siri中将显示articleTitle(如果已获取)。
The Main.storyboard for the JDIntentsUI extension | IntentViewController.swift file is
JDIntentsUI扩展的Main.storyboard | IntentViewController.swift文件为
The code for the IntentViewController.swift is given below:
IntentViewController.swift的代码如下:
import IntentsUI
class IntentViewController: UIViewController, INUIHostedViewControlling {
@IBOutlet weak var myLabel: UILabel!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
}
func configureView(for parameters: Set,
of interaction: INInteraction,
interactiveBehavior: INUIInteractiveBehavior,
context: INUIHostedViewContext,
completion: @escaping (Bool, Set, CGSize) -> Void) {
guard interaction.intent is LatestArticleIntent else {
completion(false, Set(), .zero)
return
}
let width = self.extensionContext?.hostedViewMaximumAllowedSize.width ?? 320
let desiredSize = CGSize(width: width, height: 300)
activityIndicator.startAnimating()
let apiController = APIController()
apiController.articleOfTheDay { (articleInfo) in
if let articleInfo = articleInfo {
DispatchQueue.main.async {
self.myLabel.text = articleInfo
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
apiController.contentOfArticle{[weak self] (content) in
if let content = content {
DispatchQueue.main.async {
self?.myLabel.text = content
self?.activityIndicator.stopAnimating()
self?.activityIndicator.isHidden = true
}
}
}
}
}
completion(true, parameters, desiredSize)
}
}
Here we are performing back to back API calls. First, we’re retrieving the posts, then in contentOfArticle
method from the APIController.swift we fetch the author’s name and update the label in the Intents UI extension with the author’s name.
在这里,我们正在执行背对背的API调用。 首先,我们检索帖子,然后在APIController.swift的contentOfArticle
方法中,获取作者的姓名,并使用作者的姓名更新Intents UI扩展中的标签。
How to trigger the UI click from Siri to do something?
如何触发Siri的用户界面点击以执行某项操作?
In the AppDelegate.swift file add the following method:
在AppDelegate.swift文件中,添加以下方法:
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard let url = URL(string: "https://www.journaldev.com/\(APIController.postId)") else {
return false
}
UIApplication.shared.open(url, options: [:], completionHandler: nil)
return true
}
This launches the url by appending the post id we’d retrieved to the url.
这会通过将我们检索到的帖子ID附加到url来启动url。
In order to launch a specific ViewController of our application from the Intents UI Extension, we can change the method with the following:
为了从Intents UI Extension中启动应用程序的特定ViewController,我们可以使用以下方法更改方法:
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard
userActivity.interaction?.intent is LatestArticleIntent,
let window = window,
let rootViewController = window.rootViewController as? UINavigationController
else {
return false
}
if rootViewController.viewControllers.count > 1 && rootViewController.viewControllers.last is ViewController {
return false
}
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "viewController") as! ViewController
rootViewController.pushViewController(vc, animated: true)
return true
}
Let’s build and run the application.
让我们构建并运行该应用程序。
The part 1 of the output of the application is(because screen recording stops when siri is up sometimes):
该应用程序输出的第1部分是(因为siri有时启动时屏幕记录会停止):
Part 2:
第2部分:
You can also add/delete shortcuts from the Settings:
您还可以从“设置”中添加/删除快捷方式:
And that brings an end to this tutorial. You can download the project from the link below:
这样就结束了本教程。 您可以从下面的链接下载项目:
翻译自: https://www.journaldev.com/23505/ios-12-siri-shortcuts-sirikit
sirikit