9

我的应用中有 2 个 siri 快捷方式。我使用 NSUserActivity 来捐赠这些快捷方式。我还在 info.plist 中创建了 2 个 NSUserActivityTypes。

有 2 个视图控制器处理这些快捷方式(1 个视图控制器用于 1 个快捷方式)。

如果我从 1 个视图控制器添加 1 个 siri 快捷方式,然后转到第 2 个视图控制器,则第 2 个视图控制器上的本机 siri 快捷按钮INUIAddVoiceShortcutButton(而不是显示“添加到 Siri”按钮。我仔细检查了每个NSUserActivity都有不同的标识符,但仍然以某种方式选择了错误的快捷方式。

视图控制器 1:

let userActivity = NSUserActivity(activityType: "com.activity.type1")
userActivity.isEligibleForSearch = true
userActivity.isEligibleForPrediction = true
userActivity.title = shortcut.title
userActivity.suggestedInvocationPhrase = suggestedPhrase

let attributes = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
attributes.contentDescription = description
userActivity.contentAttributeSet = attributes
let shortcut = INShortcut(userActivity: userActivity)
let siriButton = INUIAddVoiceShortcutButton(style: .whiteOutline)
siriButton.translatesAutoresizingMaskIntoConstraints = false
siriButton.shortcut = shortcut
self.view.addSubview(siriButton)

视图控制器 2:

let userActivity2 = NSUserActivity(activityType: "com.activity.type2")
userActivity2.isEligibleForSearch = true
userActivity2.isEligibleForPrediction = true
userActivity2.title = shortcut.title
userActivity2.suggestedInvocationPhrase = suggestedPhrase

let attributes = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
attributes.contentDescription = description
userActivity2.contentAttributeSet = attributes

let shortcut = INShortcut(userActivity: userActivity2)
let siriButton = INUIAddVoiceShortcutButton(style: .whiteOutline)
siriButton.translatesAutoresizingMaskIntoConstraints = false
siriButton.shortcut = shortcut
self.view.addSubview(siriButton)

当我删除应用程序并重新安装而不从电话的设置应用程序中删除快捷方式时,也会发生类似的事情。

4

7 回答 7

3

似乎它是一个 IOS 错误。我想出了解决这个问题的方法。每次用户添加/编辑 siri 快捷方式时,您都必须创建一个新的 siri 按钮。在创建 siri 按钮之前,请执行以下操作

INVoiceShortcutCenter1-通过调用函数获取所有语音快捷方式。请注意,这是异步发生的,因此您需要在需要数据之前执行此操作(例如,在您的 AppDelegate 中)。INUIAddVoiceShortcutViewControllerDelegate.addVoiceShortcutViewController(_:didFinishWith:error)每当用户添加 Siri 快捷方式(可能在方法中)时,您还需要重新加载它。

INVoiceShortcutCenter.shared.getAllVoiceShortcuts  { (voiceShortcutsFromCenter, error) in
    guard let voiceShortcutsFromCenter = voiceShortcutsFromCenter else {
            if let error = error as NSError? {
                os_log("Failed to fetch voice shortcuts with error: %@", log: OSLog.default, type: .error, error)
            }
            return
        }
        self.voiceShortcuts = voiceShortcutsFromCenter
}

2- 在 View Controller-1 中,通过迭代所有语音快捷方式来检查快捷方式是否已添加

let voiceShorcut = voiceShortcuts.first { (voiceShortcut) -> Bool in
    if let activity = voiceShortcut.shortcut.userActivity, activity.activityType == "com.activity.type1" {
        return true
    }
    return false
}

3-如果您的语音快捷方式已注册,则传递INShortcut到 siri 按钮,否则不要设置它。

if voiceShorcut != nil {
    let shortcut = INShortcut(userActivity: userActivity1)
    siriButton.shortcut = shortcut
} 

在第二个视图控制器中做同样的事情。

于 2018-09-15T09:15:38.027 回答
2

It's iOS 12.0 bug. You can fix it by update INUIAddVoiceShortcutButton.voiceShortcut with correct value. Use KVO to observe "voiceShortcut" property and when it change assign correct value to it.

于 2018-09-21T08:59:40.303 回答
0

我现在已经转移到意图设置,我发现即使只有一个意图设置并使用INUIAddVoiceShortcutButton也无法跟踪我的快捷方式。记录短语后,它会显示已添加到 Siri 和短语。

但是每次应用程序重新启动时,都会显示添加到 Siri 按钮,而不是带有录制短语的添加到 Siri 按钮。

我尝试按照 Bilal 的建议进行操作,虽然我可以看到 INVoiceShortcutCenter 显示我的快捷方式,但它并没有将它加载到 Siri 按钮中。

对于按钮本身,我的代码看起来像这样。

 private func addSiriButton() {
    let addShortcutButton = INUIAddVoiceShortcutButton(style: .blackOutline)
    addShortcutButton.delegate = self

    addShortcutButton.shortcut = INShortcut(intent: engine.intent )
    addShortcutButton.translatesAutoresizingMaskIntoConstraints = false

    siriButtonSubView.addSubview(addShortcutButton)
    siriButtonSubView.centerXAnchor.constraint(equalTo: addShortcutButton.centerXAnchor).isActive = true
    siriButtonSubView.centerYAnchor.constraint(equalTo: addShortcutButton.centerYAnchor).isActive = true

}

我已经实现了所有协议,并且仔细查看了 Soup 应用程序,但无法弄清楚是什么导致了这种不准确。

有趣的是,即使是英国航空公司的应用程序开发人员也已经放弃了这一点,因为他们的按钮具有完全相同的故障行为。

更新:我已经为 Intent 和 Add to Siri 和 Add to Siri 构建了另一个测试项目,它的实现量很小。我猜在这一点上,我自己的应用程序代码库中有一些东西导致了这种不需要的行为。

更新 2只是想让大家知道我已经解决了这个问题。使用意图工作正常,但在意图定义文件本身中肯定有一点敏感性。我所要做的就是创建一个新的意图,然后生成并且有效。似乎我最初的意图在某种程度上是腐败的,但没有错误。在创建另一个意图并为其重新分配意图处理功能后,一切都按预期工作。(双关语)

于 2018-12-14T16:01:31.903 回答
0

一个 BOOL 参数会破坏 Siri 按钮。它不会显示“已添加...”。真是一团糟。

于 2022-03-02T20:00:42.733 回答
-1

我解决这个问题的经验有点不同。通过“添加到 Siri”按钮添加的一些意图有效,调整为“已添加到 Siri”,而其他意图则没有。我意识到有效的操作不需要参数。

在为暴露参数的意图设置默认值后,这些参数被传递到INShortcut(然后分配给INUIAddVoiceShortcutButton),所有按钮都正确更新了它们的状态!

于 2021-04-19T05:39:29.567 回答
-1

我刚刚通过将我的实现(最初基于 soupchef 应用程序)更改为苹果提供的代码示例(https://developer.apple.com/documentation/sirikit/inuiaddvoiceshortcutbutton)自己解决了这个问题:

编辑:我添加了显示如何为 UserActivity 和自定义 Intent 快捷方式创建和传递快捷方式对象(INShortcut)的代码。

Shortcut 类是一个枚举,其中包含一个名为 Intent 的计算属性,该属性返回自定义 Intent 的实例化。

private func addShortcutButton(shortcut: Shortcut, parentViewController: UIViewController, shortcutViewControllerDelegate: INUIAddVoiceShortcutViewControllerDelegate) {
    guard let view = parentViewController.view else { return }

    if let intent = shortcut.intent {
        shortcutObject = INShortcut(intent: intent)
    } else if let userActivity = view.userActivity {
        shortcutObject = INShortcut(userActivity: userActivity)
    }

    self.shortcutViewControllerDelegate = shortcutViewControllerDelegate
    addSiriButton(to: shortcutButtonContainer)
}

func addSiriButton(to view: UIView) {
    let button = INUIAddVoiceShortcutButton(style: .whiteOutline)
    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)
}

// Present the Add Shortcut view controller after the
// user taps the "Add to Siri" button.
@objc
func addToSiri(_ sender: Any) {
    guard let shortcutObject = shortcutObject else { return }
    let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcutObject)
    viewController.modalPresentationStyle = .formSheet
    viewController.delegate = shortcutViewControllerDelegate
    parentViewController?.present(viewController, animated: true, completion: nil)
}
于 2018-09-15T15:36:15.433 回答
-1

所以我们不能使用默认的 Siri 按钮,你必须使用自定义 UIButton。VoiceShortcutsManager 类将检查所有语音意图,然后我们可以搜索该列表检查是否存在一个匹配项,如果是,那么我们应该建议版本,如果没有,我们应该建议添加。

public class VoiceShortcutsManager {

    private var voiceShortcuts: [INVoiceShortcut] = []

    public init() {

        updateVoiceShortcuts(completion: nil)
    }


    public func voiceShortcut(for order: DeviceIntent, powerState: State) -> INVoiceShortcut? {

        for element in voiceShortcuts {

            guard let intent = element.shortcut.intent as? ToggleStateIntent else {
                continue
            }
            let deviceIntent = DeviceIntent(identifier: intent.device?.identifier, display: intent.device?.displayString ?? "")
            if(order == deviceIntent && powerState == intent.state) {
                return element
            }
        }
        return nil
    }


    public func updateVoiceShortcuts(completion: (() -> Void)?) {

        INVoiceShortcutCenter.shared.getAllVoiceShortcuts { (voiceShortcutsFromCenter, error) in
            guard let voiceShortcutsFromCenter = voiceShortcutsFromCenter else {
                if let error = error {
                    print("Failed to fetch voice shortcuts with error: \(error.localizedDescription)")
                }
                return
            }
            self.voiceShortcuts = voiceShortcutsFromCenter
            if let completion = completion {
                completion()
            }
        }
    }

}

然后在你的 ViewController 中实现

class SiriAddViewController: ViewController {

    let voiceShortcutManager = VoiceShortcutsManager.init()

    override func viewDidLoad() {
        super.viewDidLoad()

        contentView.btnTest.addTarget(self, action: #selector(self.testBtn), for: .touchUpInside)
    }

    ...


    @objc func testBtn() {

        let deviceIntent = DeviceIntent(identifier: smartPlug.deviceID, display: smartPlug.alias)

        //is action already has a shortcut, update shortcut else create shortcut
        if let shortcut = voiceShortcutManager.voiceShortcut(for: deviceIntent, powerState: .off) {

            let editVoiceShortcutViewController = INUIEditVoiceShortcutViewController(voiceShortcut: shortcut)
            editVoiceShortcutViewController.delegate = self
            present(editVoiceShortcutViewController, animated: true, completion: nil)
        } else if let shortcut = INShortcut(intent: intentTurnOff) {

            let addVoiceShortcutVC = INUIAddVoiceShortcutViewController(shortcut: shortcut)
            addVoiceShortcutVC.delegate = self
            present(addVoiceShortcutVC, animated: true, completion: nil)
        }
    }

}


@available(iOS 12.0, *)
extension SiriAddViewController: INUIAddVoiceShortcutButtonDelegate {


    func present(_ addVoiceShortcutViewController: INUIAddVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {
        addVoiceShortcutViewController.delegate = self
        addVoiceShortcutViewController.modalPresentationStyle = .formSheet
        present(addVoiceShortcutViewController, animated: true, completion: nil)
    }


    func present(_ editVoiceShortcutViewController: INUIEditVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {

        editVoiceShortcutViewController.delegate = self
        editVoiceShortcutViewController.modalPresentationStyle = .formSheet
        present(editVoiceShortcutViewController, animated: true, completion: nil)
    }

}


@available(iOS 12.0, *)
extension SiriAddViewController: INUIAddVoiceShortcutViewControllerDelegate {

    func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {

        voiceShortcutManager.updateVoiceShortcuts(completion: nil)
        controller.dismiss(animated: true, completion: nil)
    }

    func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
        controller.dismiss(animated: true, completion: nil)
    }

}


@available(iOS 12.0, *)
extension SiriAddViewController: INUIEditVoiceShortcutViewControllerDelegate {


    func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didUpdate voiceShortcut: INVoiceShortcut?, error: Error?) {

        voiceShortcutManager.updateVoiceShortcuts(completion: nil)
        controller.dismiss(animated: true, completion: nil)
    }

    func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID) {

        voiceShortcutManager.updateVoiceShortcuts(completion: nil)
        controller.dismiss(animated: true, completion: nil)
    }

    func editVoiceShortcutViewControllerDidCancel(_ controller: INUIEditVoiceShortcutViewController) {

        voiceShortcutManager.updateVoiceShortcuts(completion: nil)
        controller.dismiss(animated: true, completion: nil)
    }

}
}

此代码受此网页启发/复制: https ://www.nodesagency.com/test-drive-a-siri-shortcuts-intro/

于 2020-02-20T23:26:33.933 回答