-
Conoce App Intents
Obtén información sobre la estructura App Intents y su papel cada vez más crucial dentro de las plataformas para desarrolladores de Apple. Te guiaremos a través de una introducción básica de los conceptos centrales: Intents, entidades, consultas y mucho más. Aprenderás cómo estas piezas encajan entre sí y te permitirán integrar tu app a través de los dispositivos de Apple, desde funcionalidades de software como Spotlight y Atajos hasta funcionalidades de hardware como el botón de Acción. También analizaremos cómo App Intents es la puerta de entrada de tu app para integrarse en Apple Intelligence más adelante.
Capítulos
- 0:00 - Introducción
- 0:45 - Ecosistema de App Intents
- 2:47 - Navegación por la estructura
- 21:15 - Cómo funciona
Recursos
- Adopting App Intents to support system experiences
- Building a workout app for iPhone and iPad
- Accelerating app interactions with App Intents
- App intent domains
- Creating your first app intent
- Integrating actions with Siri and Apple Intelligence
- Making actions and content discoverable and widely available
- App Shortcuts
- App Intents
Videos relacionados
WWDC25
WWDC24
-
Buscar este video…
-
-
3:23 - Navigate Intent
struct NavigateIntent: AppIntent { static let title: LocalizedStringResource = "Navigate to Landmarks" static let supportedModes: IntentModes = .foreground @MainActor func perform() async throws -> some IntentResult { Navigator.shared.navigate(to: .landmarks) return .result() } } -
5:02 - Navigation Option App Enum
enum NavigationOption: String, AppEnum { case landmarks case map case collections static let typeDisplayRepresentation: TypeDisplayRepresentation = "Navigation Option" static let caseDisplayRepresentations: [NavigationOption: DisplayRepresentation] = [ .landmarks: "Landmarks", .map: "Map", .collections: "Collections" ] } -
5:38 - Navigate Intent with Parameter
struct NavigateIntent: AppIntent { static let title: LocalizedStringResource = "Navigate to Section" static let supportedModes: IntentModes = .foreground @Parameter var navigationOption: NavigationOption @MainActor func perform() async throws -> some IntentResult { Navigator.shared.navigate(to: navigationOption) return .result() } } -
6:57 - Case Display Representations with Images
static let caseDisplayRepresentations = [ NavigationOption.landmarks: DisplayRepresentation( title: "Landmarks", image: .init(systemName: "building.columns") ), NavigationOption.map: DisplayRepresentation( title: "Map", image: .init(systemName: "map") ), NavigationOption.collections: DisplayRepresentation( title: "Collections", image: .init(systemName: "book.closed") ) ] -
7:28 - Navigation Option With Parameter Summary
struct NavigateIntent: AppIntent { static let title: LocalizedStringResource = "Navigate to Section" static let supportedModes: IntentModes = .foreground static var parameterSummary: some ParameterSummary { Summary("Navigate to \(\.$navigationOption)") } @Parameter( title: "Section", requestValueDialog: "Which section?" ) var navigationOption: NavigationOption @MainActor func perform() async throws -> some IntentResult { Navigator.shared.navigate(to: navigationOption) return .result() } } -
9:22 - App Shortcuts Provider and Navigation Intent App Shortcut
struct TravelTrackingAppShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: NavigateIntent(), phrases: [ "Navigate in \(.applicationName)", "Navigate to \(\.$navigationOption) in \(.applicationName)"a ], shortTitle: "Navigate", systemImageName: "arrowshape.forward" ) } } -
11:02 - Landmark Entity
struct LandmarkEntity: AppEntity { var id: Int { landmark.id } @ComputedProperty var name: String { landmark.name } @ComputedProperty var description: String { landmark.description } let landmark: Landmark static let typeDisplayRepresentation = TypeDisplayRepresentation(name: "Landmark") var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(name)") } static let defaultQuery = LandmarkEntityQuery() } -
13:19 - Landmark Entity Query
struct LandmarkEntityQuery: EntityQuery { @Dependency var modelData: ModelData func entities(for identifiers: [LandmarkEntity.ID]) async throws -> [LandmarkEntity] { modelData .landmarks(for: identifiers) .map(LandmarkEntity.init) } } -
13:50 - App Dependency Manager
@main struct LandmarksApp: App { init() { AppDependencyManager.shared.add { ModelData() } } } -
14:18 - Closest Landmark Intent
struct ClosestLandmarkIntent: AppIntent { static let title: LocalizedStringResource = "Find Closest Landmark" @Dependency var modelData: ModelData @MainActor func perform() async throws -> some ReturnsValue<LandmarkEntity> & ProvidesDialog & ShowsSnippetView { let landmark = try await modelData.findClosestLandmark() return .result( value: landmark, dialog: "The closest landmark to you is \(landmark.name)", view: ClosestLandmarkView(landmark: landmark) ) } } -
15:18 - Closest Landmark App Shortcut
AppShortcut( intent: ClosestLandmarkIntent(), phrases: [ "Find closest landmark in \(.applicationName)" ], shortTitle: "Closest landmark", systemImageName: "location" ) -
16:33 - Transferable
extension LandmarkEntity: Transferable { static var transferRepresentation: some TransferRepresentation { DataRepresentation(exportedContentType: .image) { return try $0.imageRepresentationData } } } -
17:31 - Indexed Entity
struct LandmarkEntity: IndexedEntity { // ... @Property( indexingKey: \.displayName ) var name: String @Property( indexingKey: \.contentDescription ) var description: String } -
18:17 - Open Landmark Intent
struct OpenLandmarkIntent: OpenIntent, TargetContentProvidingIntent { static let title: LocalizedStringResource = "Open Landmark" @Parameter(title: "Landmark", requestValueDialog: "Which landmark?") var target: LandmarkEntity } struct LandmarksNavigationStack: View { @State var path: [Landmark] = [] var body: some View { NavigationStack(path: $path) {} .onAppIntentExecution(OpenLandmarkIntent.self) { intent in path.append(intent.target.landmark) } } } -
19:24 - Open Landmark App Shortcut
AppShortcut( intent: OpenLandmarkIntent(), phrases: [ "Open \(\.$target) in \(.applicationName)", "Open landmark in \(.applicationName)" ], shortTitle: "Open", systemImageName: "building.columns" ) -
19:39 - Suggested Entities
struct LandmarkEntityQuery: EntityQuery { // ... func suggestedEntities() async throws -> [LandmarkEntity] { modelData .favoriteLandmarks() .map(LandmarkEntity.init) } } -
20:06 - Update App Shortcut Parameters
TravelTrackingAppShortcuts.updateAppShortcutParameters() -
20:25 - EnumerableEntityQuery
extension LandmarkEntityQuery: EnumerableEntityQuery { func allEntities() async throws -> [LandmarkEntity] { // ... } } -
20:36 - EntityPropertyQuery
extension LandmarkEntityQuery: EntityPropertyQuery { static var properties = QueryProperties { // ... } static var sortingOptions = SortingOptions { // ... } func entities( matching comparators: [Predicate<LandmarkEntity>], mode: ComparatorMode, sortedBy: [Sort<LandmarkEntity>], limit: Int? ) async throws -> [LandmarkEntity] { // ... } } -
20:44 - EntityStringQuery
extension LandmarkEntityQuery: EntityStringQuery { func entities(matching: String) async throws -> [LandmarkEntity] { modelData .landmarks .filter { $0.name.contains(matching) || $0.description.contains(matching) } .map(LandmarkEntity.init) } } -
23:10 - App Intents Package
// TravelTrackingKit public struct TravelTrackingKitPackage: AppIntentsPackage {} public structaLandmarkEntity: AppEntity {} // TravelTracking struct TravelTrackingPackage: AppIntentsPackage { static var includedPackages: [any AppIntentsPackage.Type] { [TravelTrackingKitPackage.self] } } struct OpenLandmarkIntent: OpenIntent {} // TravelTrackingAppIntentsExtension struct TravelTrackingExtensionPackage: AppIntentsPackage { static var includedPackages: [any AppIntentsPackage.Type] { [TravelTrackingKitPackage.self] } } struct FavoriteLandmarkIntent: AppIntent {}
-
-
- 0:00 - Introducción
Obtén información sobre App Intents una estructura que puedes utilizar para mejorar la capacidad de descubrimiento y la funcionalidad de las apps en todas las plataformas de Apple. Los temas incluyen la importancia de la estructura, la implementación y las mejores prácticas para escribir en Apps Intents.
- 0:45 - Ecosistema de App Intents
App Intents es un ecosistema que permite que las apps extiendan su funcionalidad a todo el sistema Spotlight, Botón de acción, Widgets, Centro de control y Apple Pencil Pro. Las personas pueden realizar acciones en la app desde cualquier lugar, incluso cuando no están en la app. Defines las acciones de la app como intenciones, que pueden tomar parámetros y devolver valores utilizando enumeraciones de app para constantes o entidades de app para tamaños de letra dinámicos. Los Atajos a apps, creados a partir de intenciones y parámetros, mejoran la accesibilidad y la capacidad de descubrimiento a través de Spotlight, Siri y el botón de acción.
- 2:47 - Navegación por la estructura
La app de ejemplo explora lugares famosos de todo el mundo. Para mejorar la experiencia del usuario, implementa App Intents, que permiten a las personas realizar acciones directamente desde Siri, Atajos y Spotlight. El proceso implica definir estructuras que adoptan el protocolo App Intents, especificando títulos, métodos de ejecución y resultados de intenciones. Agrega parámetros a las intenciones, lo que permite a las personas elegir secciones específicas de la app, como la cuadrícula de puntos de referencia o la vista del mapa. Para que la app sea más fácil de descubrir y usar, se crean Atajos a apps, que exponen automáticamente las intenciones en todo el sistema. También modelan datos dinámicos como puntos de referencia utilizando entidades de app, lo que permite a las personas realizar acciones en puntos de referencia específicos a través de intenciones. En la estructura de App Intents, las entidades de la app representan datos dinámicos, como puntos de referencia. Las consultas son componentes esenciales que permiten al sistema razonar sobre estas entidades. Responden varias preguntas, incluida la recuperación de todas las entidades, la coincidencia de cadenas o propiedades específicas y la referencia única a las entidades por ID. Puede personalizar consultas utilizando diferentes tipos, como EntityStringQuery y EntityPropertyQuery y estas consultas pueden depender de bases de datos locales u otros recursos. Las dependencias se pueden agregar a las consultas mediante el atributo @Dependency. Registra las dependencias lo antes posible en el ciclo de vida de tu app. Al usar App Intents, puedes crear acciones personalizadas que se pueden realizar usando Siri, Spotlight o Atajos. Al devolver tipos de entidades desde las intenciones, estas acciones se pueden encadenar entre sí en atajos de varios pasos. Para mejorar la experiencia del usuario, puedes hacer que las entidades sean transferibles, lo que permitirá compartirlas entre apps. La adopción del protocolo de entidad indexada permite a Spotlight realizar búsquedas semánticas. También puedes crear intenciones abiertas para navegar directamente a vistas específicas dentro de la app cuando se tocan entidades en Spotlight.
- 21:15 - Cómo funciona
App Intents utiliza el código fuente Swift en el momento de la compilación para generar una representación de App Intents, que luego se almacena dentro de la app o la estructura. Esto permite que el sistema comprenda las capacidades de la app sin ejecutarla. El nombre de la intención sirve como su identificador único; el título ayuda a las personas a diferenciar entre intenciones y la firma de retorno del método 'perform' define cómo representar el resultado. Es necesario proporcionar valores constantes para ciertas propiedades de intención porque el procesamiento se produce en el momento de la compilación. Para compartir tipos de App Intent entre objetivos, como una app y su extensión, puede utilizar paquetes Swift o bibliotecas estáticas. Debe registrar cada objetivo como un paquete de App Intents para garantizar la indexación y validación adecuadas de los tipos compartidos por parte del tiempo de ejecución de App Intents.