В iOS 16 компания Apple запустила фреймворк App Intents, позволяющий разработчикам легче интегрировать действия своих приложений в систему. Действия приложений могут использоваться в различных частях системы, таких как виджеты, приложение Shortcuts, Siri и Spotlight. До появления фреймворка App Intents мы использовали SiriKit для передачи наших действий в систему, но эта платформа имела более высокий барьер для входа из-за недостатка документации и ресурсов.
Одна из моих любимых особенностей создания действий приложения с помощью App Intents — простота создания прототипов. Я могу пройти путь от идеи до работающего действия менее чем за час. В этом руководстве я расскажу вам о том, как создать первое действие для приложения Shortcuts.
Созданное нами действие будет доступно системе при первой установке нашего приложения и сразу же станет доступно Siri. Однако в данном руководстве мы не будем рассматривать взаимодействие между действием и Siri — мы сосредоточимся на том, как пользователь может использовать ваше действие в Shortcuts.
Прежде чем начать, давайте рассмотрим, что нам нужно сделать для создания простого ярлыка:
- Соответствовать протоколу AppIntent.
- Добавить описание
- Добавить параметр(ы)
- Обработать пользовательский ввод в методе
perform
Соответствие протоколу AppIntent
Начните с соответствия протоколу AppIntents. Это можно сделать, присвоив действию название, а затем добавив метод perform
.
import AppIntents struct AddTaskIntent: AppIntent { static var title: LocalizedStringResource = "Add task" func perform() async throws -> some IntentResult { return .result() } }
Здесь:
title
: Заголовок ярлыка, который будет отображаться в приложении ярлыков.perform()
: Методperform
непосредственно выполняет действие интента. Например:- Cохраняет данные после того, как пользователь выполнил ввод.
- Показывает новый запрос, если система обнаруживает двусмысленность из-за нескольких значений.
- Отображает представление после выполнения действия.
Если вы хотите открыть приложение после выполнения действия, установите свойство openAppWhenRun
в true
.
Первая задача выполнена!
Добавление описания
Описание говорит нам о цели интента — это необязательное свойство, но мы добавим его сюда в качестве следующего шага.
import AppIntents struct AddTaskIntent: App Intent { static var title: LocalizedStringResource = "Add task" static var description: IntentDescription? = "This action allows you to add a new task to your to-do list " func perform() async throws -> some IntentResult { return .result() } }
Добавление параметров
В нашем примере мы хотим, чтобы пользователь мог добавить задачу, введя ее в текстовое поле или обратившись к Siri. Чтобы это произошло, мы добавим параметр для получения пользовательского ввода. Параметры могут быть разных типов, от примитивных до более сложных типов, таких как IntentPerson
. Полный список возможных типов параметров приведен на этой странице документации.
import Foundation import AppIntents struct AddTaskIntent: App Intent { @Parameter(title: "Task") var task: String static var title: LocalizedStringResource = "Add task" static var description: IntentDescription? = "This action allows you to add a new task to your to-do list " func perform() async throws -> some IntentResult { return .result() } }
Мы можем добавить другие свойства в обертку свойства параметра, например:
description
описывает, что представляет собой данное свойство. Описание, добавленное к параметрам, будет отображаться в описании действия приложения.inputOptions
описывает, как мы хотим стилизовать вводимые данные при использовании приложения Shortcuts. Он имеет такие свойства, какkeyboardType
,capitalizationType
,multiline
,autocorrect
и другие.requestValueDialog
описывает точную фразу, которую мы хотим произнести в аудиоконтексте.requestDisambiguationDialog
описывает фразу, которую мы хотим произнести в случае нескольких значений — Siri попросит пользователя выбрать одно из них.
Наш параметр добавляется в виде строки под заголовком. Мы можем сделать его более красивым, добавив ParameterSummary
. ParameterSummary
— это предложение, представляющее намерение и его параметры. Apple рекомендует предоставлять резюме параметров, чтобы сделать пользовательский интерфейс более упорядоченным.
import Foundation import AppIntents struct AddTaskIntent: App Intent { @Parameter(title: "Task") var task: String static var title: LocalizedStringResource = "Add task" static var description: IntentDescription? = "This action allows you to add a new task to your to-do list " static var parameterSummary: some ParameterSummary { Summary("Add \(\.$task)") } func perform() async throws -> some IntentResult { return .result() } }
В данном примере при запуске ярлыка отображается текстовое поле. Нажатие кнопки «Готово» приводит к его удалению, но дальнейшего взаимодействия не происходит.
В зависимости от наличия знака ?
система рассматривает параметр как обязательный или нет. Если вы не добавите знак ?
, система предложит пользователю ввести параметр — при наличии знака ?
система продолжит выполнение действия. Если вы хотите запросить значение параметра, используйте .needsValueError()
с диалогом, который вы хотите, чтобы система использовала для запроса пользователя.
needsValueError(_:)
Возвращает ошибку restartPerform с контекстом для запроса у пользователя значения этого параметра и повторного выполнения намерения с новыми значениями. — Apple
import Foundation import AppIntents struct AddTaskIntent: App Intent { @Parameter(title: "Task") var task: String static var title: LocalizedStringResource = "Add task" static var description: IntentDescription? = "This action allows you to add a new task to your to-do list " static var parameterSummary: some ParameterSummary { Summary("Add \(\.$task)") } func perform() async throws -> some IntentResult { guard let task = task else { throw $task.needsValueError("What task would you like to add?") } return .result() } }
Обработка пользовательского ввода в методе perform
После определения того, какой ввод ожидается от пользователя, необходимо сделать то, что нужно приложению. В данном примере необходимо сохранить вводимые данные в задаче, которая будет храниться локально на устройстве. В методе perform
задача создается, а затем сохраняется. После этого отображается текстовое представление об успешном сохранении.
import Foundation import AppIntents import SwiftUI struct AddTaskIntent: App Intent { @Parameter(title: "Task") var task: String static var title: LocalizedStringResource = "Add task" static var description: IntentDescription? = "This action allows you to add a new task to your to-do list " static var parameterSummary: some ParameterSummary { Summary("Add \(\.$task)") } private let persistenceController: PersistenceController = .shared @MainActor func perform() async throws -> some ShowsSnippetView { try persistenceController.addTask(Task(title: task, createDate: .now)) return .result(view: Text("Task added successfully")) } }
Метод perform
выполняется, когда система разрешила все параметры, необходимые вашему коду для успешного выполнения его функциональности. При реализации задач в методе perform
добавляемая логика должна выполнить необходимую работу, которая вернет системе нужное значение. Таким результатом может быть значение, которое шорткат может использовать в последующих связанных действиях, диалог для отображения, представление сниппета SwiftUI и т.д. Если интенту нет смысла возвращать конкретный результат, верните .result()
, чтобы сообщить системе о завершении намерения.
Если намерение манипулирует пользовательским интерфейсом приложения, аннотируйте perform() с помощью @MainActor, чтобы убедиться, что функция выполняется в главной очереди. — Apple
Примечание: Когда мы указываем значения, возвращаемые из метода perform:
- Если вы возвращаете представление SwiftUI, укажите возвращаемый тип как
ShowsSnippetView
. - Если вы возвращаете значение из метода perform, укажите
ReturnsValue<T>
, а в круглых скобках укажите тип, который вы хотите вернуть. Если предоставить это значение без указания типа, то это приведет к аварийному завершению работы приложения. - Если вы хотите, чтобы Siri произнесла фразу, верните
ProvidesDialog
, указав, что должна произнести Siri. - Если необходимо вернуть несколько типов, укажите каждый тип, разделив их знаком
&
. Например:ShowsSnippetView & ProvidesDialog & ReturnsValue<T>
.
Теперь, когда мы выполнили все шаги, у нас есть основа для намерения! Используя полученные знания, мы можем создавать и более сложные сценарии использования — мы рассмотрим их в одной из следующих статей.