Кнопка ярлыка siri (INUIAddVoiceShortcutButton) показывает неправильный заголовок при наличии нескольких ярлыков (NSUserActivity)

В моем приложении есть 2 ярлыка siri. Я использую NSUserActivity, чтобы пожертвовать эти ярлыки. Я также создал 2 NSUserActivityTypes в моем info.plist.

Есть 2 контроллера представления, которые обрабатывают эти ярлыки (1 контроллер представления для 1 ярлыка).

Если я добавлю 1 ярлык siri из 1 контроллера представления, а затем перейду к контроллеру второго представления, собственная кнопка ярлыка siri (INUIAddVoiceShortcutButton) на контроллере второго представления автоматически выберет первый ярлык (созданный из контроллера первого представления) и покажет «Добавлено в Siri» с предложенным фразу вместо отображения кнопки «Добавить в 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)

Аналогичная вещь происходит, когда я удаляю приложение и переустанавливаю его, не удаляя ярлыки из приложения «Настройки телефона».

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
3 972
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Похоже, это ошибка IOS. Я нашел способ решения этой проблемы. Вам нужно создавать новую кнопку siri каждый раз, когда пользователь добавляет / редактирует ярлык siri. Перед созданием кнопки siri выполните следующие действия

1- Получите все голосовые ярлыки от INVoiceShortcutCenter, вызвав функцию. Обратите внимание, что это происходит асинхронно, поэтому вам нужно сделать это за некоторое время, прежде чем вам понадобятся данные (например, в вашем AppDelegate). Вам также потребуется перезагружать его всякий раз, когда пользователь добавляет ярлык Siri (возможно, в методе INUIAddVoiceShortcutViewControllerDelegate.addVoiceShortcutViewController(_:didFinishWith:error)).

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
} 

Сделайте то же самое в Second View Controller.

Я сам исправил эту проблему, изменив свою реализацию (изначально основанную на приложении soupchef) на этот образец кода, предоставленный Apple (https://developer.apple.com/documentation/sirikit/inuiaddvoiceshortcutbutton):

Обновлено: я добавил код, который показывает, как я создаю и передаю shortcutObject (INShortcut) как для UserActivity, так и для пользовательских ярлыков Intent.

Класс Shortcut - это перечисление, которое содержит вычисляемое свойство, называемое намерением, которое возвращает экземпляр пользовательского намерения.

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)
}

Проблема в нескольких ярлыках. Где вы обрабатываете несколько ярлыков?

Bilal 15.09.2018 18:55

У меня есть свойство, в котором я устанавливаю активность пользователя для ярлыка, который я хотел бы использовать, и использую его для создания INShortcut. Я обновлю это позже, добавив более подробный код, когда вернусь к своей машине разработчика.

rmooney 15.09.2018 18:56

Привет. Я борюсь с этой настройкой на данный момент. Не могли бы вы рассказать, как вы использовали пример для UserActivity, предоставленный Apple? if let shortcut = INShortcut (userActivity: Используете ли вы функцию для выбора активности, чтобы войти сюда?

Dan Korkelia 25.10.2018 18:27

Дэн, я передаю контроллер представления, у которого есть пожертвованная активность пользователя (parentViewController), и вытаскиваю userActivity из его представления. Я добавил еще код, чтобы показать это.

rmooney 26.10.2018 19:42

Это ошибка iOS 12.0. Вы можете исправить это, обновив INUIAddVoiceShortcutButton.voiceShortcut с правильным значением. Используйте KVO для наблюдения за свойством voiceShortcut и при его изменении присвойте ему правильное значение.

Я не вижу свойства voiceShortcut на INUIAddVoiceShortcutButton - это личное?

Tim 19.10.2018 17:04

Хорошо, даже не наблюдая, я смог исправить это, просто позвонив в [addToSiriButton setValue:voiceShortcut forKey:@"voiceShortcut"], где я когда-то звонил addToSiriButton.shortcut = voiceShortcut.shortcut;.

Tim 19.10.2018 17:14

@ Виталий Алексеев, можешь лучше это объяснить?

Tiago Mendes 20.02.2020 19:25

Я перешел к настройке намерений и обнаружил, что даже имея только одну настройку намерений и работая с INUIAddVoiceShortcutButton, я не могу отслеживать мой ярлык. После того, как фраза записана, отображается фраза, добавленная в Siri.

Но каждый раз, когда приложение перезапускает, появляется кнопка «Добавить в Siri» вместо кнопки «Добавлено в Siri» с записанной фразой.

Я попытался пойти по предложению Билала, и хотя я вижу, что 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, но просто не могу понять, что вызывает эту неточность.

Как ни странно, даже разработчики приложений British Airways отказались от этого, поскольку их кнопка имеет точно такое же поведение ошибки.

Обновлять: Я построил еще один тестовый проект с минимальной реализацией Intent, и Add to Siri и Added to Siri отлично работают. На данный момент я предполагаю, что в кодовой базе моих собственных приложений есть что-то, что вызывает такое нежелательное поведение.

обновление 2 Просто хотел, чтобы все знали, что я исправил проблему. Использование намерений работает нормально, но в самом файле определения намерений определенно есть небольшая чувствительность. Все, что мне нужно было сделать, это создать новое намерение, которое затем было сгенерировано и сработало. Кажется, мое первоначальное намерение было каким-то образом испорчено, но ошибок не было. После создания другого намерения и переназначения ему функции обработки намерения все работало по назначению. (предназначен каламбур)

Есть ли способ отобразить «Добавлено в Siri» без фразы под ним? Я вижу, как некоторые приложения это делают, но сам не могу понять.

Cityzen26 07.02.2019 20:03

Привет, Рюмин, я не видел способа удалить текст ниже. Сам текст добавляется только после того, как фраза была записана на сервер в качестве напоминания о том, что у вас есть фраза, это одна из причин, по которой Apple предлагает короткую запоминающуюся фразу. Другая причина, по которой отображается текст, заключается в том, что вся кнопка «Добавить в Siri» локализована, поэтому вы можете локализовать «Добавить в Siri», а также записанную фразу.

Dan Korkelia 08.02.2019 17:34

Просто еще раз взглянул на INUIAddVoiceShortcutButton, и это просто подкласс UIButton, что может означать, что вы можете установить метку на все, что захотите, хотя я все еще не на 100% в этом. Фактически INUIAddVoiceShortcutButtonStyle - это часть Init, которая устанавливает стиль кнопки, и это всего лишь свойство {get}.

Dan Korkelia 08.02.2019 23:07

да, спасибо Дэн! Похоже, что текст «Добавлено в Siri» является стандартной реализацией Apple после того, как вы задали фразу. Если я попытаюсь установить заголовок, он будет перекрывать этот текст.

Cityzen26 11.02.2019 19:23

Поэтому мы не можем использовать кнопку 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/

Мой опыт решения этой проблемы был немного другим. Некоторые намерения, добавленные с помощью кнопки «Добавить в Siri», работали, а другие - нет. Я понял, что действующие действия не требуют параметров.

После установки значений по умолчанию для намерений, предоставляющих параметры, которые передаются в INShortcut (а затем назначаются INUIAddVoiceShortcutButton), все кнопки обновили свое состояние правильно!

Другие вопросы по теме