如何管理 Siri 意图启动我的应用程序并将数据传输到应用程序?
Posted
技术标签:
【中文标题】如何管理 Siri 意图启动我的应用程序并将数据传输到应用程序?【英文标题】:How to manage that Siri intent launches my app and transfers data to the app? 【发布时间】:2021-02-12 14:57:29 【问题描述】:经过数小时的搜索,我请求您的帮助。
我正在编写一个应用程序来管理我的库存。作为通过专用视图“AddNewEntry”手动输入库存项目的替代方法,我想使用 Siri 并打算在“将 item 存储在 的意义上捕获数据放置在部分”。 item、place 和 section 是我想通过 Siri 获取的属性,然后使用视图“AddNewEntry”将它们存储在我的数据库中,其中我处理这些数据的手动输入、检查和存储。为了从意图中移交新数据,我想向我的 mainViewController 发布一个通知,然后它启动对视图的 segue 以显示和检查/存储新条目。
我已经通过意图定义设置了意图(“VorratAdd”),并且该快捷方式似乎可以正常工作并收集数据。但是该快捷方式不会返回到我的应用程序并以弹出视图结束,并显示如下消息(我的德语翻译):
“Vorrat Add”无法执行。任务需要很长时间才能关闭。 重试”
我的设置如下:
我的意图处理程序 VorratAdd:
import Foundation
import Intents
import UIKit
class VorratAddIntentHandler: NSObject, VorratAddIntentHandling
func handle(intent: VorratAddIntent, completion: @escaping (VorratAddIntentResponse) -> Void)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NewVorratInputFromSiri"), object: intent)
func resolveBezeichnung(for intent: VorratAddIntent, with completion: @escaping (INStringResolutionResult) -> Void)
if intent.item == " "
completion(INStringResolutionResult.needsValue())
else
completion(INStringResolutionResult.success(with: intent.bezeichnung ?? "_"))
func resolveOrt(for intent: VorratAddIntent, with completion: @escaping (INStringResolutionResult) -> Void)
if intent.place == " "
completion(INStringResolutionResult.needsValue())
else
completion(INStringResolutionResult.success(with: intent.ort ?? "_"))
func resolveFach(for intent: VorratAddIntent, with completion: @escaping (VorratAddFachResolutionResult) -> Void)
if intent.section == 0
completion(VorratAddFachResolutionResult.needsValue())
else
completion(VorratAddFachResolutionResult.success(with: intent.fach as! Int))
IntentHandler.swift:
import UIKit
import Intents
class IntentHandler: INExtension
override func handler(for intent: INIntent) -> Any
guard intent is VorratAddIntent else
fatalError("unhandled Intent error: \(intent)")
return VorratAddIntentHandler()
捐赠在我的 mainViewController“HauptVC”中:
extension HauptVC
func initSiriIntent()
let intent = VorratAddIntent()
intent.suggestedInvocationPhrase = "Neuer Vorrat"
intent.item = " "
intent.location = " "
intent.section = 0
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate (error) in
if error != nil
if let error = error as NSError?
print("Interaction donation fehlgeschlagen: \(error.description)")
else
print("Interaction donation erfolgreich")
AppDelegate:
import UIKit
import Intents
@main
class AppDelegate: UIResponder, UIApplicationDelegate
var rootViewController: UINavigationController?
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
if userActivity.activityType == "VorratAddIntent"
restorationHandler(rootViewController!.viewControllers)
return true
return false
场景代理:
import UIKit
import Intents
class SceneDelegate: UIResponder, UIWindowSceneDelegate
var window: UIWindow?
let app = UIApplication.shared.delegate as! AppDelegate
var rootVC: UINavigationController?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
guard let _ = (scene as? UIWindowScene) else return
rootVC = self.window?.rootViewController as? UINavigationController
app.rootViewController = rootVC
func scene(_ scene: UIScene, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool
if userActivity.activityType == "VorratAddIntent"
app.rootViewController = rootVC
restorationHandler(rootVC!.viewControllers)
return true
return false
有人知道我做错了什么吗?非常感谢您的支持。
【问题讨论】:
【参考方案1】:我认为您缺少一种方法实现“确认”
func confirm(intent: VorratAddIntent, completion: @escaping (VorratAddIntentResponse) -> Void)
completion(.init(code: .success, userActivity: nil))
编辑:
这里是documentation,用于确认意图详细信息
编辑 2:
必须在“handle”方法中调用完成处理程序
func handle(intent: VorratAddIntent, completion: @escaping (VorratAddIntentResponse) -> Void)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NewVorratInputFromSiri"), object: intent)
completion(your response)
编辑 3 - 将数据从扩展程序 (Siri) 传递到应用程序:
NotificationCenter 在扩展程序和主应用程序之间不起作用,因为它们没有以任何方式连接,这是完全不同的过程。
有不同的方法来实现这一点:
App Group
:Here 是 Core Data 和 Extension 如何共享数据库的示例
UserDefaults with AppGroup
:
你也可以使用UserDefaults(suiteName: your app group name)
NSUserActivity
:
SiriKit最方便的方式apple doc
NSUserActivity 示例
您将在 handle 方法中创建 NSUserActivity 的实例,如下所示:
func handle(intent: VorratAddIntent, completion: @escaping (VorratAddIntentResponse) -> Void)
let response = VorratAddIntentResponse.success()
let activity = NSUserActivity(activityType:NSStringFromClass(VorratAddIntent.self))
activity.addUserInfoEntries(from: [
"task_id" : your task id
])
response.userActivity = activity
completion(response)
而且您可以在应用中处理用户信息,如果应用已经在运行,您可以像这样提取 task_id 值:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity)
guard userActivity.interaction?.intent is VorratAddIntent else return
#if DEBUG
print("Siri Intent user info: \(String(describing: userActivity.userInfo))")
#endif
guard let taskID = userActivity.userInfo?["task_id"] as? String
else return
但是如果你的应用没有在后台运行,你需要在场景中处理用户活动(willConnectTo:)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
guard let _ = (scene as? UIWindowScene) else return
for activity in connectionOptions.userActivities
self.scene(scene, continue: activity)
【讨论】:
非常感谢 - 这让我更进一步,Siri 对话现在以 .success 的确认屏幕结束。但是,在确认屏幕中按“完成”后,我的应用程序都不会启动,也不会通过通知传输意图数据。你知道这是什么原因吗?我把句柄函数作为完成:completion(.init(code: .success, userActivity: nil))
我编辑了答案,进一步说明了如何在扩展程序和您的应用程序之间共享数据。以上是关于如何管理 Siri 意图启动我的应用程序并将数据传输到应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
如何自定义有关“failureRequiringAppLaunch”类型的 Siri 意图响应的错误消息
当我的应用程序通过我的 UITabBar 完成启动时,如何将加载的数据传递给 UITableView?
如何在 iOS 中检索数据并将数据传递给标签栏控制器的子视图?