sirikit_iOS 12 Siri捷径SiriKit

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上发布的最新教程。

SiriKit (SiriKit)

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,其中允许以下域/类别:

  • Messaging

    讯息传递
  • VoIP calling

    VoIP通话
  • Payment

    付款
  • Ride booking

    乘车预订
  • Photo search

    图片搜寻
  • Workouts

    锻炼

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)

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:

要创建快捷方式,您需要使用以下内容:

  • Intents App Extension – These receive the requests from SiriKit and perform the actions.

    Intents App Extension –用于接收来自SiriKit的请求并执行操作。
  • Intents UI Extension – These are optional if you want to create a custom UI that would be displayed in Siri.

    意图UI扩展 –如果要创建将在Siri中显示的自定义UI,则这些是可选的。

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快捷方式:

  • Fetches the latest article posted on Journaldev.com from the APIs defined below.

    通过下面定义的API获取发布在Journaldev.com上的最新文章。
  • Show the user with a custom UI containing the author’s name.

    向用户显示包含作者姓名的自定义UI。
  • Let the user tap on it to open the article link in the web browser.

    让用户点击它以在Web浏览器中打开文章链接。
https://www.journaldev.com/wp-json/wp/v2/posts?filter[posts_per_page]=1&page=1

入门 (Getting Started)

Following is the gist to create a Siri Shortcut:

以下是创建Siri快捷方式的要点:

  • Add intents and intentsUI extension targets (Targets because the Intents would run outside the app independently).

    加入的意图intentsUI扩展目标(目标,因为意图将应用程序之外独立运行)。
  • Override the Intent handlers


    覆盖意图处理程序
  • Mention your intents in info.plist

    info.plist提及您的意图

Create a new XCode project as Single View Application.

创建一个新的XCode项目作为Single View Application。

Enable Siri Capabilities:

启用S​​iri功能:

Note: To enable Siri capabilities you must have an Apple Developer Account.

注意:要启用Siri功能,您必须具有Apple开发者帐户。

Once Siri capabilities is enabled, an entitlements file is created.

启用S​​iri功能后,将创建一个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

定义自定义意图

  • Creating a new intent named LatestArticle by clicking on the plus symbol.

    通过单击加号创建一个名为LatestArticle的新意图。
  • The title would be shown in Siri. We’ve kept the confirmation dialog unchecked for now. Background execution is enabled in order to run the intents in the background.

    标题将显示在Siri中。 我们暂时未选中确认对话框。 启用后台执行以便在后台运行意图。
  • We’ve skipped the Parameters section since our intent does not have any.

    由于我们的意图没有任何内容,因此我们已跳过“参数”部分。
  • The response template has two codes. Each with a string text that would be displayed in the Siri.

    响应模板有两个代码。 每个都带有将在Siri中显示的字符串文本。

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文件中,如下所示:

添加Alamofire库 (Adding Alamofire Library)

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打开此项目。

项目结构 (Project Structure)

(Code)

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:

这样就结束了本教程。 您可以从下面的链接下载项目:

iOSSiriShortcuts iOSSiri快捷方式

翻译自: https://www.journaldev.com/23505/ios-12-siri-shortcuts-sirikit

sirikit

你可能感兴趣的:(java,python,vue,js,javascript,ViewUI)