App Schemas: haz que tu app esté disponible para Siri
En la WWDC 2026, un ingeniero de Apple tomó una app de calendario en SwiftUI que solo respondía a toques y logró que Siri buscara sus eventos, respondiera preguntas sobre ellos por su nombre y por el contenido de las notas, los creara y actualizara por voz, y mostrara una tarjeta de resultado personalizada, todo escribiendo tres structs y completando un puñado de fragmentos de código.1 El mecanismo detrás de ese cambio es App Schemas: una forma de describir el contenido y las acciones de una app en términos que Siri ya entiende, sin frases de entrenamiento y sin procesamiento de lenguaje natural por parte del desarrollador.1 La sesión es un code-along construido en torno a un proyecto de ejemplo llamado CometCal, y la lección que subyace al tema cósmico es estructural. No le enseñas tu vocabulario a Siri. Declaras tus datos y tus acciones frente a una forma que Siri ya conoce, y el resto viene solo.
Este artículo recorre los tres pilares que sostienen ese resultado: el modelo esquema-dominio, la donación semántica a Spotlight mediante IndexedEntity, y la conciencia de pantalla junto con la distinción de valueState que vuelve seguras las actualizaciones por voz. Todo lo que sigue proviene directamente de la sesión. El tema difiere de la ejecución en segundo plano en App Intents, que cubre cómo ejecutar trabajo sin abrir la interfaz; aquí el foco está en cómo Siri razona sobre tu contenido y actúa sobre él.
TL;DR
- Los
App Schemasdescriben las entidades de una app, los parámetros de sus acciones y sus salidas en términos que Siri ya entiende, organizados en App Schema Domains; el dominio de calendario cubre eventos, calendarios, asistentes y las acciones sobre ellos, sin frases de entrenamiento y sin NLP por parte del desarrollador.1 - Las entidades esquematizadas provienen de fragmentos de código de Xcode: escribes un prefijo de dominio como
calendar_y eliges un fragmento (por ejemplocalendar_calendar), lo que genera la estructura base de la entidad con su macro, sus propiedades, su representación de visualización y los esqueletos de consulta.1 - Hacer que una entidad cumpla con
IndexedEntityy donarla a unCSSearchableIndexmedianteindexAppEntities(y eliminarla condeleteAppEntities) permite que Siri la resuelva por su nombre, por una propiedad o por el contexto, sin una consulta de propiedad personalizada.1 - Dos view modifiers,
.appEntityIdentifieren una lista y.userActivityen una vista de detalle (cada uno con unEntityIdentifier), le dan a Siri conciencia de pantalla, de modo que una petición como «envía un correo a las personas de este evento» se resuelve sin nombrar el evento.1 - Los intents de actualización exponen
IntentParameter.valueState, donde.setcon un valor,.setcon nil y.unsetdistinguen un valor nuevo, un borrado explícito y un parámetro ausente, de modo que las ediciones impulsadas por Siri se mantienen sin ambigüedad.1
Qué son realmente los App Schemas (sesión 344)
Justin, del equipo de Swift Intelligence Frameworks, explica los App Schemas antes de abrir Xcode, a partir del minuto 3:12.
Siri llega a una app a través del framework App Intents, y Apple Intelligence impulsa el razonamiento que se construye encima.1 El problema de partida en CometCal es claro: «Ahora mismo, Siri no tiene ni idea de qué significa un calendario o un evento dentro de CometCal.»1 Los App Schemas cierran esa brecha. Como lo expresa la sesión, «describen el contenido y las acciones de mi app en términos que Siri ya puede entender. Definen la estructura de mis entidades, los parámetros de mis acciones y las salidas. Sin frases de entrenamiento, sin procesamiento de lenguaje natural de mi parte.»1
La unidad organizadora es el App Schema Domain. El dominio de calendario «cubre todo lo relacionado con la planificación: eventos, calendarios, asistentes y las acciones que operan sobre ellos.»1 Como las formas están predefinidas, el editor se encarga de catalogar. El ingeniero crea un archivo CalendarEntity, importa AppIntents, escribe calendar_, y «Xcode ofrece todos los esquemas del dominio Calendar, directamente en el autocompletado.»1 Seleccionar calendar_calendar rellena la estructura: la macro de entidad, las propiedades, una representación de visualización y los esqueletos de consulta, produciendo lo que la sesión llama «una entidad esquematizada, un tipo sobre el que Siri puede razonar.»1
La convención de nomenclatura merece una nota cuidadosa. Los nombres de los fragmentos de esquema aparecen en el editor como identificadores en minúsculas con prefijo de guion bajo (calendar_calendar, calendar_attendee, calendar_event, calendar_createEvent, calendar_updateEvent, además de fragmentos de enum como calendar_attendeeStatus y calendar_attendeeType), y la transcripción hablada los representa así. Los tipos de Swift cuya estructura generan (una macro @AppEntity, una DisplayRepresentation, las conformidades con los protocolos de consulta) siguen el uso habitual de mayúsculas y minúsculas de Swift. Confirma la ortografía y el uso exacto de mayúsculas de cada símbolo en la documentación de App Intents de Apple y en el proyecto de ejemplo CometCal descargable antes de compilar con ellos, ya que un code-along hablado no es una referencia precisa para las mayúsculas.
La recompensa del modelo de esquema es un gran alcance con muy poco código. La sesión enmarca toda la capa de contenido como «tres structs y completar unos cuantos fragmentos de código.»1 CometCal construye tres entidades de riqueza creciente: un calendario, un asistente y un evento que reúne a los otros dos. El evento «se compone con las demás entidades construidas antes»: su calendario es un CalendarEntity, y sus asistentes son un array de AttendeeEntity, y «Siri entiende estas relaciones gracias a los App Schemas.»1 El esquema también decide qué es obligatorio y qué es opcional. Los elementos esenciales como el título o la fecha de inicio se conectan directamente, las propiedades de esquema opcionales que una app no usa (la sesión menciona el tiempo de viaje y la ubicación virtual) pueden quedar sin establecer, y una propiedad que vive en el modelo de datos pero no en el esquema, como isFavorite, igual puede añadirse a la entidad.1
En el evento aparecen otras dos mecánicas de esquema. Los valores union permiten que una propiedad contenga uno de varios tipos: la ubicación puede ser «o bien un PlaceDescriptor del framework GeoToolbox, o bien un String», y una alarma puede ser o una Duration o una Date.1 La propiedad de recurrencia usa la Calendar.RecurrenceRule de Foundation y se convierte en ambos sentidos con el propio enum de frecuencia de CometCal para los casos diario, semanal, mensual y anual.1 Los enums esquematizados (la sesión señala un enum de estado de evento al que llama EventEntityStatus, y los enums de asistente de más arriba) llegan completos desde el fragmento, y la app adopta los casos que correspondan; si una app usa una terminología diferente, mapeas el modelo existente a los casos del esquema «para que Siri pueda reconocer la forma.»1
La donación semántica mediante IndexedEntity
El esquema le da a Siri un vocabulario. La donación le da a Siri los datos reales sobre los que razonar. Son dos pasos distintos, y la sesión es explícita en que es fácil pasar por alto el segundo: «IndexedEntity define la forma de mi contenido indexado, pero las entidades aún deben donarse.»1
Hacer que una entidad cumpla con el protocolo IndexedEntity es lo que habilita la coincidencia por significado y no solo por texto.1 La razón es el índice de búsqueda. Cumplir con él «permite que mi app done entidades usando el índice de Spotlight para obtener los beneficios de la comprensión semántica», y una vez donada una entidad, «Siri puede resolverla por su nombre, por una propiedad o por el contexto, sin requerir una consulta de propiedad personalizada.»1 Esa última cláusula es lo esencial. No escribes ningún comparador a medida para «el almuerzo de la tripulación» o «los eventos que mencionan oxígeno». Siri busca directamente en los títulos donados y en el contenido de las notas, y «responde cada pregunta usando el contenido de la app. No hace falta lenguaje natural personalizado… solo entidades y esquemas.»1
La donación se realiza a través de CSSearchableIndex. CometCal mantiene una instancia de CSSearchableIndex, creada en el inicializador de su CalendarManager con un nombre único de la app.1 La regla que enuncia la sesión es que «cada vez que los calendarios, o cualquier entidad indexada en realidad, cambian, el índice debe actualizarse.»1 Por eso la capa de datos dona al escribir: la ruta de creación llama a indexAppEntities con el índice de búsqueda antes de retornar, la ruta de actualización reindexa la entidad modificada, y la ruta de eliminación llama a deleteAppEntities, «pasando el id y el tipo de la entidad.»1 Tras conectar la entidad de calendario, el ingeniero crea un calendario llamado «Lunar Orbit Log», desliza para buscar y lo encuentra con su icono y su título, la prueba de que la donación surtió efecto.1
No toda entidad debería indexarse, y el asistente es el contraejemplo que enseña la regla. AttendeeEntity cumple con TransientAppEntity en lugar de IndexedEntity, «una entidad temporal que no requiere un identificador único y no está pensada para ser consultada.»1 El razonamiento es disciplina de modelado: en CometCal un asistente representa «la participación de una persona en un evento específico, no la persona en sí», la misma persona puede asistir a muchos eventos, e «indexar cada asistencia por separado crearía resultados duplicados en Spotlight.»1 Como a los asistentes siempre se llega a través de su evento, no hay una ruta de búsqueda independiente que mantener, y TransientAppEntity «lo hace explícito… ninguna consulta que escribir, ningún índice que mantener.»1 El asistente también introduce IntentPerson, «la forma estándar del sistema de representar a una persona con un nombre e información de contacto», útil para entregar el correo de un asistente a Mail con el fin de redactar un mensaje.1
Las entidades indexadas todavía necesitan su cableado de consulta. La consulta mantiene la capa de datos a través del property wrapper @Dependency, «la forma en que App Intents inyecta recursos compartidos en los intents y las consultas», de modo que la consulta usa el único CalendarManager registrado en lugar de una instancia nueva, y la consulta se marca como main-actor porque el manager lo es.1 El método EntityQuery requerido obtiene por ID en los casos en que el sistema ya lo conoce, y cumplir con EnumerableEntityQuery mediante un método allEntities permite que el sistema liste más tarde los calendarios disponibles cuando Siri necesita ofrecerlos como opciones al crear un evento.1 Una DisplayRepresentation (un título más una imagen de calendario del sistema) le indica a Siri y a Spotlight cómo mostrar la entidad.1
Hay una costura de navegación que vale la pena nombrar, porque la donación por sí sola deja al usuario en la pantalla principal de la app. Un OpenEventIntent que cumple con el esquema system.open, toma un EventEntity como destino y le indica a la capa de navegación que vaya hacia él cierra esa brecha: el sistema lo invoca «cada vez que alguien toca un resultado de evento en Spotlight o Siri, o le pide a Siri que abra uno», de modo que un resultado tocado abre directamente la vista de detalle del evento.1
La conciencia de pantalla y la distinción de valueState
Los dos primeros pilares permiten que Siri encuentre contenido por su nombre. El tercero permite que Siri use lo que ya está frente al usuario, y luego actúe sobre ello sin ambigüedad.
La conciencia de pantalla cuesta «solo dos view modifiers.»1 En la vista de lista, .appEntityIdentifier se adjunta a la lista, «pasando un EntityIdentifier por cada una de las entidades de evento», lo que «conecta la lista con sus entidades, de modo que cuando alguien navega por la lista, el sistema sabe qué eventos están en pantalla.»1 En la vista de detalle, .userActivity lleva un EntityIdentifier para el único evento en foco, indicándole al sistema «que ese evento específico está en primer plano para que Siri pueda resolver este evento exactamente al que se está viendo.»1 Con ambos en su lugar, un usuario en la vista de detalle de un evento puede decir «envía un correo a las personas de este evento y pídele a alguien que traiga chocolate y malvaviscos», y Siri usa su comprensión del evento en pantalla para encontrar a los asistentes y entregárselos a Mail, sin necesidad de título.1
Actuar sobre el contenido sigue el mismo patrón que leerlo, ejecutado a la inversa. Los intents también provienen de fragmentos. El fragmento calendar_createEvent genera la estructura base del intent con su macro, el esquema, los parámetros que el esquema requiere y un esqueleto de perform.1 La lógica de perform tiene una forma de tres pasos que la sesión enuncia con claridad: «resolver los parámetros del intent en algo que la capa de datos entienda, realizar la acción y devolver el resultado como una entidad.»1 Para la creación, eso significa extraer la ubicación de su valor union, convertir la recurrencia si se proporciona, llamar al método de creación del manager y devolver un EventEntity.1 Como el intent cumple con un esquema, «Siri puede encargarse de todo el trabajo pesado: interpretar el lenguaje, pedir aclaraciones y confirmar detalles», de modo que el desarrollador nunca escribe la conversación.1
Las actualizaciones sacan a la luz la sutileza que hace confiables las ediciones por voz. La mayoría de los parámetros de calendar_updateEvent son opcionales, porque un usuario suele cambiar una o dos cosas, y «el parámetro de evento es lo que Siri resuelve; todo lo demás es opcional.»1 Una simple comprobación de nil no puede responder a la verdadera pregunta. Como lo plantea la sesión, «cuando la recurrencia es nil, ¿significa eso “no la cambies” o “elimínala”? Una simple comprobación de nil no me dice con qué caso estoy lidiando.»1 La respuesta es IntentParameter.valueState, expuesta porque la macro del intent envuelve cada propiedad en un IntentParameter. Los tres estados tienen un significado distinto: «.set con un valor real significa que se proporciona un valor nuevo. .set con un valor nil significa que se borra de forma explícita. .unset significa que el parámetro no forma parte de la petición.»1 La distinción «se aplica a cualquier parámetro opcional en el que borrar el valor sea una acción significativa», y por eso «no repitas este evento» borra de forma fiable la recurrencia en lugar de dejarla intacta.1
Dos toques finales completan la capa de acción. Una tarjeta de resultado personalizada reemplaza la tarjeta de representación de visualización predeterminada de Siri: añadir ShowsSnippetView al tipo de retorno del método perform y pasar una vista de SwiftUI preparada (la de la sesión toma un EventEntity) muestra el estilo propio de la app dentro de Siri, un enfoque que «funciona para cualquier otro intent que devuelva un resultado.»1 Y DeleteEventIntent, «el más simple de los tres», toma solo el evento y un span opcional para eventos recurrentes; Siri «maneja automáticamente el cuadro de diálogo de confirmación antes de que se elimine nada» y resuelve la ambigüedad cuando coincide más de un evento.1
Puntos clave
Para desarrolladores de iOS que adoptan App Intents:
- Recurre primero al esquema. Escribe un prefijo de dominio como
calendar_en Xcode y deja que el autocompletado liste los fragmentos disponibles; el fragmento genera la estructura base de la macro, las propiedades, la representación de visualización y los esqueletos de consulta, de modo que rellenas los tipos y el mapeo en lugar de inventar la estructura.1 - Decide por cada entidad si se gana un índice. Haz que el contenido duradero y consultable cumpla con
IndexedEntityy dónalo; usaTransientAppEntitypara los registros de tipo participación (el asistente de CometCal) a los que siempre se llega a través de un padre y que solo contaminarían Spotlight si se indexaran.1 - Verifica la ortografía y el uso exacto de mayúsculas de los símbolos en la documentación de App Intents de Apple y en el ejemplo CometCal antes de compilar, ya que los nombres del code-along provienen de una transcripción hablada.
Para equipos que diseñan flujos de voz y Apple Intelligence:
- Trata la donación como una responsabilidad de la ruta de escritura. Llama a
indexAppEntitiesal crear y actualizar, y adeleteAppEntitiesal eliminar, indexados por el id y el tipo de la entidad, para que el índice de Siri nunca se desvíe de los datos.1 - Añade la conciencia de pantalla pronto:
.appEntityIdentifieren las listas y.userActivityen las vistas de detalle (cada uno con unEntityIdentifier) permiten que los usuarios digan «este evento» en lugar de su título.1 - Maneja
valueStatede forma explícita en los intents de actualización. Ramifica en.set-con-valor,.set-con-nil y.unsetpara que un borrado explícito nunca se lea como «dejar sin cambios.»1
Preguntas frecuentes
¿Qué son los App Schemas en App Intents?
Los App Schemas describen el contenido y las acciones de una app en términos que Siri ya entiende: definen la estructura de las entidades de una app, los parámetros de sus acciones y las salidas, sin frases de entrenamiento y sin procesamiento de lenguaje natural por parte del desarrollador. Están organizados en App Schema Domains; el dominio de calendario cubre eventos, calendarios, asistentes y las acciones sobre ellos. En Xcode adoptas un esquema escribiendo un prefijo de dominio como calendar_ y eligiendo un fragmento de código como calendar_calendar, que genera la estructura base de la entidad.1
¿Cómo resuelve Siri el contenido de mi app por su nombre o por el contexto?
Haz que la entidad cumpla con el protocolo IndexedEntity y dónala a un CSSearchableIndex (el índice de Spotlight) llamando a indexAppEntities al crear y actualizar, y a deleteAppEntities con el id y el tipo de la entidad al eliminar. La donación le da a Siri «comprensión semántica», lo que le permite resolver una entidad por su nombre, por una propiedad o por el contexto sin una consulta de propiedad personalizada, incluido buscar en el contenido de las notas para preguntas como «¿qué eventos mencionan oxígeno?»1
¿Cuándo debería usar TransientAppEntity en lugar de IndexedEntity?
Usa TransientAppEntity para una entidad temporal que no necesita un identificador único y no está pensada para ser consultada. El asistente de CometCal encaja porque un asistente representa la participación de una persona en un evento específico, no a la persona; la misma persona asiste a muchos eventos, e indexar cada asistencia por separado crearía resultados duplicados en Spotlight. Como a los asistentes solo se llega a través de su evento, no hay una ruta de búsqueda independiente, por lo que la entidad transitoria no necesita ni consulta ni índice.1
¿Qué es valueState y por qué importa en los intents de actualización?
En un intent de actualización, la macro de App Intents envuelve cada propiedad en un IntentParameter que expone un valueState. Distingue tres casos que una comprobación de nil no puede: .set con un valor significa un valor nuevo, .set con nil significa que el valor se borra de forma explícita, y .unset significa que el parámetro no formaba parte de la petición. La distinción permite que las ediciones impulsadas por Siri borren una propiedad (por ejemplo, «no repitas este evento») sin que eso se confunda con «dejar sin cambios.»1
¿Cómo le doy a Siri conciencia de pantalla de mi app?
Añade dos view modifiers. Pon .appEntityIdentifier en la vista de lista, pasando un EntityIdentifier por cada entidad de evento, para que el sistema sepa qué eventos están en pantalla mientras se navega. Pon .userActivity con un EntityIdentifier en la vista de detalle para que el sistema sepa que un evento específico está en foco. Juntos permiten que un usuario diga «envía un correo a las personas de este evento» y que Siri resuelva «este evento» exactamente al que se está viendo.1
Este artículo forma parte de un cluster sobre los frameworks de inteligencia de Apple. Para el framework sobre el que se apoyan los App Schemas, empieza por App Intents: la nueva API de Apple hacia tu app. Para ejecutar el trabajo de un intent sin abrir la interfaz, lo cual es una preocupación distinta del razonamiento sobre el contenido que se trata aquí, lee la ejecución en segundo plano en App Intents. Para la historia más amplia de la donación a Spotlight detrás de la resolución semántica, consulta la IA en el dispositivo y la indexación de medios en Spotlight. El centro completo de la serie es la serie Apple Ecosystem.
Referencias
-
Apple, WWDC 2026 session 344, Code-along: Make your app available to Siri. Fuente de los App Schemas y los App Schema Domains (el dominio de calendario; sin frases de entrenamiento, sin NLP); las entidades esquematizadas mediante fragmentos de Xcode (
calendar_calendar,calendar_attendee,calendar_event,calendar_createEvent,calendar_updateEvent,calendar_attendeeStatus,calendar_attendeeType);IndexedEntityy la donación a Spotlight medianteCSSearchableIndexa través deindexAppEntities/deleteAppEntities; la resolución por nombre, propiedad o contexto;TransientAppEntityy la justificación de modelado del asistente;IntentPerson; los valores union (PlaceDescriptordel frameworkGeoToolbox, String; alarmasDurationoDate) yCalendar.RecurrenceRule; el wrapper@Dependency,EntityQuery,EnumerableEntityQueryyDisplayRepresentation; elOpenEventIntentdesystem.open; la conciencia de pantalla mediante.appEntityIdentifiery.userActivitycon unEntityIdentifier;IntentParameter.valueState(.set/.unset); la tarjeta de resultado personalizadaShowsSnippetView; la confirmación y resolución de ambigüedad deDeleteEventIntent; y el frameworkAppIntentsTestingreferenciado para las pruebas automatizadas. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩