App Schemas : rendre votre application accessible à Siri
Lors de la WWDC 2026, un ingénieur d’Apple a pris une application calendrier SwiftUI qui ne répondait qu’aux taps et a fait en sorte que Siri en recherche les événements, réponde à des questions à leur sujet par leur nom et le contenu de leurs notes, les crée et les mette à jour à la voix, et affiche une carte de résultat personnalisée, le tout en écrivant trois structs et en complétant une poignée d’extraits de code.1 Le mécanisme derrière ce changement, c’est App Schemas : une manière de décrire le contenu et les actions d’une application dans des termes que Siri comprend déjà, sans phrases d’entraînement et sans traitement du langage naturel côté développeur.1 La session est un code-along construit autour d’un projet d’exemple nommé CometCal, et la leçon sous-jacente au thème cosmique est structurelle. Vous n’apprenez pas votre vocabulaire à Siri. Vous déclarez vos données et vos actions par rapport à une forme que Siri connaît déjà, et le reste suit.
Cet article parcourt les trois piliers qui portent ce résultat : le modèle schéma-domaine, la donation sémantique vers Spotlight via IndexedEntity, et la conscience de l’écran ainsi que la distinction valueState qui rend sûres les mises à jour pilotées à la voix. Tout ce qui suit provient directement de la session. Le sujet diffère de l’exécution en arrière-plan dans App Intents, qui couvre l’exécution de travaux sans lancer l’interface ; l’accent porte ici sur la façon dont Siri raisonne sur votre contenu et agit dessus.
TL;DR
- Les
App Schemasdécrivent les entités d’une application, les paramètres de ses actions et ses sorties dans des termes que Siri comprend déjà, organisés en App Schema Domains ; le domaine calendrier couvre les événements, les calendriers, les participants et les actions qui les concernent, sans phrases d’entraînement et sans NLP côté développeur.1 - Les entités schématisées proviennent d’extraits de code Xcode : tapez un préfixe de domaine comme
calendar_et choisissez un extrait (par exemplecalendar_calendar), ce qui génère le squelette de l’entité avec sa macro, ses propriétés, sa représentation d’affichage et les ébauches de requête.1 - Faire conformer une entité à
IndexedEntityet la donner à unCSSearchableIndexviaindexAppEntities(et la retirer viadeleteAppEntities) permet à Siri de la résoudre par son nom, par une propriété ou par le contexte, sans requête de propriété personnalisée.1 - Deux view modifiers,
.appEntityIdentifiersur une liste et.userActivitysur une vue de détail (chacun portant unEntityIdentifier), donnent à Siri la conscience de l’écran, si bien qu’une requête comme « envoie un e-mail aux personnes de cet événement » se résout sans nommer l’événement.1 - Les intents de mise à jour exposent
IntentParameter.valueState, où.setavec une valeur,.setavec nil et.unsetdistinguent une nouvelle valeur, un effacement explicite et un paramètre absent, de sorte que les modifications pilotées par Siri restent sans ambiguïté.1
Ce que sont réellement les App Schemas (session 344)
Justin, de l’équipe Swift Intelligence Frameworks, explique les App Schemas avant d’ouvrir Xcode, à partir de 3:12.
Siri atteint une application via le framework App Intents, et Apple Intelligence alimente le raisonnement par-dessus.1 Le problème de départ dans CometCal est clair : « Pour l’instant, Siri n’a aucune idée de ce que signifient un calendrier ou un événement à l’intérieur de CometCal. »1 Les App Schemas comblent cet écart. Comme le formule la session, ils « décrivent le contenu et les actions de mon application dans des termes que Siri peut déjà comprendre. Ils définissent la structure de mes entités, les paramètres de mes actions et les sorties. Pas de phrases d’entraînement, pas de traitement du langage naturel de mon côté. »1
L’unité d’organisation est l’App Schema Domain. Le domaine calendrier « couvre tout ce qui touche à la planification : événements, calendriers, participants et les actions qui opèrent dessus. »1 Comme les formes sont prédéfinies, l’éditeur se charge du catalogage. L’ingénieur crée un fichier CalendarEntity, importe AppIntents, tape calendar_, et « Xcode propose tous les schémas du domaine Calendar, directement dans l’autocomplétion. »1 Sélectionner calendar_calendar remplit la structure : la macro d’entité, les propriétés, une représentation d’affichage et les ébauches de requête, produisant ce que la session appelle « une entité schématisée, un type sur lequel Siri peut raisonner. »1
La convention de nommage mérite une note attentive. Les noms des extraits de schéma apparaissent dans l’éditeur sous forme d’identifiants en minuscules préfixés d’un tiret bas (calendar_calendar, calendar_attendee, calendar_event, calendar_createEvent, calendar_updateEvent, ainsi que des extraits d’enum comme calendar_attendeeStatus et calendar_attendeeType), et la transcription orale les rend ainsi. Les types Swift dont ils génèrent le squelette (une macro @AppEntity, une DisplayRepresentation, les conformités aux protocoles de requête) suivent la casse Swift habituelle. Vérifiez l’orthographe et la casse exactes de chaque symbole dans la documentation App Intents d’Apple et dans le projet d’exemple CometCal téléchargeable avant de compiler avec eux, car un code-along oral n’est pas une référence précise pour la casse.
Le bénéfice du modèle de schéma, c’est une grande portée pour très peu de code. La session présente toute la couche de contenu comme « trois structs et le remplissage de quelques extraits de code. »1 CometCal construit trois entités de richesse croissante : un calendrier, un participant, et un événement qui réunit les deux autres. L’événement « se compose avec les autres entités construites précédemment » : son calendrier est un CalendarEntity, et ses participants sont un tableau d’AttendeeEntity, et « Siri comprend ces relations grâce aux App Schemas. »1 Le schéma décide aussi de ce qui est requis et de ce qui est optionnel. Les éléments essentiels comme le titre ou la date de début se branchent directement, les propriétés de schéma optionnelles qu’une application n’utilise pas (la session cite le temps de trajet et le lieu virtuel) peuvent rester non définies, et une propriété qui vit dans le modèle de données mais pas dans le schéma, comme isFavorite, peut tout de même être ajoutée à l’entité.1
Deux autres mécaniques de schéma apparaissent sur l’événement. Les valeurs union permettent à une propriété de contenir l’un de plusieurs types : le lieu peut être « soit un PlaceDescriptor du framework GeoToolbox, soit un String », et une alarme peut être soit une Duration, soit une Date.1 La propriété de récurrence utilise la Calendar.RecurrenceRule de Foundation et se convertit dans les deux sens avec l’enum de fréquence propre à CometCal pour les cas quotidien, hebdomadaire, mensuel et annuel.1 Les enums schématisés (la session pointe un enum de statut d’événement qu’elle nomme EventEntityStatus, et les enums de participant ci-dessus) arrivent complets depuis l’extrait, et l’application adopte les cas qui s’appliquent ; si une application utilise une terminologie différente, vous faites correspondre le modèle existant aux cas du schéma « pour que Siri puisse reconnaître la forme. »1
La donation sémantique via IndexedEntity
Le schéma donne à Siri un vocabulaire. La donation donne à Siri les données réelles sur lesquelles raisonner. Ce sont deux étapes distinctes, et la session est explicite sur le fait qu’il est facile de manquer la seconde : « IndexedEntity définit la forme de mon contenu indexé, mais les entités doivent encore être données. »1
Faire conformer une entité au protocole IndexedEntity est ce qui permet une correspondance par le sens plutôt que par le seul texte.1 La raison tient à l’index de recherche. La conformité « permet à mon application de donner des entités via l’index Spotlight pour bénéficier de la compréhension sémantique », et une fois une entité donnée, « Siri peut la résoudre par son nom, par une propriété ou par le contexte, sans nécessiter de requête de propriété personnalisée. »1 Cette dernière proposition est tout l’enjeu. Vous n’écrivez aucun comparateur sur mesure pour « le déjeuner de l’équipage » ou « les événements qui mentionnent l’oxygène. » Siri recherche directement dans les titres donnés et le contenu des notes, et « répond à chaque question en utilisant le contenu de l’application. Pas besoin de langage naturel personnalisé… juste des entités et des schémas. »1
La donation passe par CSSearchableIndex. CometCal détient une instance de CSSearchableIndex, créée dans l’initialiseur de son CalendarManager sous un nom propre à l’application.1 La règle énoncée par la session est que « chaque fois que des calendriers, ou n’importe quelle entité indexée d’ailleurs, sont modifiés, l’index doit être mis à jour. »1 La couche de données donne donc à l’écriture : le chemin de création appelle indexAppEntities avec l’index de recherche avant de retourner, le chemin de mise à jour réindexe l’entité modifiée, et le chemin de suppression appelle deleteAppEntities, « en passant l’id et le type de l’entité. »1 Après avoir branché l’entité calendrier, l’ingénieur crée un calendrier nommé « Lunar Orbit Log », balaie pour rechercher, et le trouve avec son icône et son titre, la preuve que la donation a fonctionné.1
Toutes les entités ne devraient pas être indexées, et le participant est le contre-exemple qui enseigne la règle. AttendeeEntity se conforme à TransientAppEntity plutôt qu’à IndexedEntity, « une entité temporaire qui ne nécessite pas d’identifiant unique et n’est pas destinée à être interrogée. »1 Le raisonnement relève de la discipline de modélisation : dans CometCal, un participant représente « la participation d’une personne à un événement spécifique, pas la personne elle-même », la même personne peut assister à de nombreux événements, et « indexer chaque participation séparément créerait des résultats redondants dans Spotlight. »1 Puisque les participants sont toujours atteints à travers leur événement, il n’y a aucun chemin de recherche indépendant à maintenir, et TransientAppEntity « rend cela explicite… aucune requête à écrire, aucun index à maintenir. »1 Le participant introduit aussi IntentPerson, « la manière standard du système de représenter une personne avec un nom et des informations de contact », utile pour remettre l’e-mail d’un participant à Mail afin de rédiger un message.1
Les entités indexées ont tout de même besoin de leur plomberie de requête. La requête détient la couche de données via le property wrapper @Dependency, « la façon dont App Intents injecte des ressources partagées dans les intents et les requêtes », de sorte que la requête utilise l’unique CalendarManager enregistré plutôt qu’une nouvelle instance, et la requête est marquée main-actor parce que le manager l’est.1 La méthode EntityQuery requise récupère par ID pour les cas où le système le connaît déjà, et la conformité à EnumerableEntityQuery avec une méthode allEntities permet au système de lister plus tard les calendriers disponibles lorsque Siri doit les proposer comme options lors de la création d’un événement.1 Une DisplayRepresentation (un titre plus une image système de calendrier) indique à Siri et à Spotlight comment afficher l’entité.1
Il y a une jointure de navigation qui mérite d’être nommée, car la donation seule fait atterrir l’utilisateur sur l’écran principal de l’application. Un OpenEventIntent qui se conforme au schéma system.open, prend un EventEntity comme cible et indique à la couche de navigation de s’y rendre comble cet écart : le système l’invoque « chaque fois que quelqu’un tape un résultat d’événement dans Spotlight ou Siri, ou demande à Siri d’en ouvrir un », de sorte qu’un résultat tapé ouvre directement la vue de détail de l’événement.1
La conscience de l’écran et la distinction valueState
Les deux premiers piliers permettent à Siri de trouver le contenu par son nom. Le troisième lui permet d’utiliser ce qui se trouve déjà devant l’utilisateur, puis d’agir dessus sans ambiguïté.
La conscience de l’écran coûte « seulement deux view modifiers. »1 Dans la vue liste, .appEntityIdentifier s’attache à la liste, « en passant un EntityIdentifier pour chacune des entités d’événement », ce qui « connecte la liste à ses entités, de sorte que lorsqu’on parcourt la liste, le système sait quels événements sont à l’écran. »1 Dans la vue de détail, .userActivity porte un EntityIdentifier pour l’unique événement en focus, indiquant au système « que cet événement précis est au premier plan, afin que Siri puisse résoudre cet événement vers exactement celui qui est consulté. »1 Avec les deux en place, un utilisateur sur la vue de détail d’un événement peut dire « envoie un e-mail aux personnes de cet événement et demande à quelqu’un d’apporter du chocolat et des marshmallows », et Siri utilise sa compréhension de l’événement à l’écran pour trouver les participants et les remettre à Mail, sans titre requis.1
Agir sur le contenu suit le même schéma que le lire, exécuté à l’envers. Les intents proviennent aussi d’extraits. L’extrait calendar_createEvent génère le squelette de l’intent avec sa macro, le schéma, les paramètres que le schéma requiert et une ébauche de perform.1 La logique de perform suit une forme en trois étapes que la session énonce simplement : « résoudre les paramètres de l’intent en quelque chose que la couche de données comprend, effectuer l’action, et retourner le résultat sous forme d’entité. »1 Pour la création, cela signifie extraire le lieu de sa valeur union, convertir la récurrence si elle est fournie, appeler la méthode de création du manager et retourner un EventEntity.1 Parce que l’intent se conforme à un schéma, « Siri peut prendre en charge tout le gros du travail. Interpréter le langage, demander des clarifications et confirmer les détails », de sorte que le développeur n’écrit jamais la conversation.1
Les mises à jour font apparaître la subtilité qui rend dignes de confiance les modifications pilotées à la voix. La plupart des paramètres de calendar_updateEvent sont optionnels, car un utilisateur change généralement une ou deux choses, et « le paramètre événement est ce que Siri résout ; tout le reste est optionnel. »1 Une simple vérification de nil ne peut pas répondre à la vraie question. Comme le formule la session, « quand la récurrence est nil, cela veut-il dire “ne la change pas” ou “supprime-la” ? Une simple vérification de nil ne me dit pas à quel cas j’ai affaire. »1 La réponse est IntentParameter.valueState, exposé parce que la macro d’intent enveloppe chaque propriété dans un IntentParameter. Les trois états portent un sens distinct : « .set avec une valeur réelle signifie qu’une nouvelle valeur est fournie. .set avec une valeur nil signifie qu’elle est explicitement effacée. .unset signifie que le paramètre ne fait pas partie de la requête. »1 La distinction « s’applique à tout paramètre optionnel pour lequel effacer la valeur est une action significative », c’est pourquoi « ne répète pas cet événement » efface de manière fiable la récurrence au lieu de la laisser intacte.1
Deux touches finales complètent la couche d’action. Une carte de résultat personnalisée remplace la carte de représentation d’affichage par défaut de Siri : ajouter ShowsSnippetView au type de retour de la méthode perform et passer une vue SwiftUI préparée (celle de la session prend un EventEntity) affiche le style propre de l’application à l’intérieur de Siri, une approche qui « fonctionne pour tout autre intent qui retourne un résultat. »1 Et DeleteEventIntent, « le plus simple des trois », ne prend que l’événement et un span optionnel pour les événements récurrents ; Siri « gère automatiquement la boîte de dialogue de confirmation avant que quoi que ce soit ne soit supprimé » et lève l’ambiguïté lorsque plus d’un événement correspond.1
Points clés à retenir
Pour les développeurs iOS qui adoptent App Intents :
- Commencez par le schéma. Tapez un préfixe de domaine comme
calendar_dans Xcode et laissez l’autocomplétion lister les extraits disponibles ; l’extrait génère le squelette de la macro, des propriétés, de la représentation d’affichage et des ébauches de requête, si bien que vous remplissez les types et le mappage au lieu d’inventer la structure.1 - Décidez par entité si elle mérite un index. Faites conformer le contenu durable et interrogeable à
IndexedEntityet donnez-le ; utilisezTransientAppEntitypour les enregistrements de type participation (le participant de CometCal) toujours atteints à travers un parent et qui ne feraient que polluer Spotlight s’ils étaient indexés.1 - Vérifiez l’orthographe et la casse exactes des symboles dans la documentation App Intents d’Apple et l’exemple CometCal avant de compiler, car les noms du code-along proviennent d’une transcription orale.
Pour les équipes qui conçoivent des flux voix et Apple Intelligence :
- Traitez la donation comme une responsabilité du chemin d’écriture. Appelez
indexAppEntitiesà la création et à la mise à jour, etdeleteAppEntitiesà la suppression, indexés par l’id et le type de l’entité, afin que l’index de Siri ne dérive jamais des données.1 - Ajoutez la conscience de l’écran tôt :
.appEntityIdentifiersur les listes et.userActivitysur les vues de détail (chacun portant unEntityIdentifier) permettent aux utilisateurs de dire « cet événement » au lieu de son titre.1 - Gérez
valueStateexplicitement dans les intents de mise à jour. Branchez sur.set-avec-valeur,.set-avec-nil et.unsetpour qu’un effacement explicite ne se lise jamais comme « laisser inchangé. »1
FAQ
Que sont les App Schemas dans App Intents ?
Les App Schemas décrivent le contenu et les actions d’une application dans des termes que Siri comprend déjà : ils définissent la structure des entités d’une application, les paramètres de ses actions et les sorties, sans phrases d’entraînement et sans traitement du langage naturel côté développeur. Ils sont organisés en App Schema Domains ; le domaine calendrier couvre les événements, les calendriers, les participants et les actions qui les concernent. Dans Xcode, vous adoptez un schéma en tapant un préfixe de domaine comme calendar_ et en choisissant un extrait de code tel que calendar_calendar, qui génère le squelette de l’entité.1
Comment Siri résout-il le contenu de mon application par son nom ou par le contexte ?
Faites conformer l’entité au protocole IndexedEntity et donnez-la à un CSSearchableIndex (l’index Spotlight) en appelant indexAppEntities à la création et à la mise à jour, et deleteAppEntities avec l’id et le type de l’entité à la suppression. La donation donne à Siri une « compréhension sémantique », lui permettant de résoudre une entité par son nom, par une propriété ou par le contexte sans requête de propriété personnalisée, y compris en recherchant dans le contenu des notes pour des questions comme « quels événements mentionnent l’oxygène ? »1
Quand devrais-je utiliser TransientAppEntity plutôt qu’IndexedEntity ?
Utilisez TransientAppEntity pour une entité temporaire qui n’a besoin d’aucun identifiant unique et n’est pas destinée à être interrogée. Le participant de CometCal convient parce qu’un participant représente la participation d’une personne à un événement spécifique, pas la personne ; la même personne assiste à de nombreux événements, et indexer chaque participation séparément créerait des résultats redondants dans Spotlight. Puisque les participants ne sont atteints qu’à travers leur événement, il n’y a aucun chemin de recherche indépendant, si bien que l’entité transitoire ne nécessite ni requête ni index.1
Qu’est-ce que valueState et pourquoi est-ce important pour les intents de mise à jour ?
Dans un intent de mise à jour, la macro App Intents enveloppe chaque propriété dans un IntentParameter qui expose un valueState. Il distingue trois cas qu’une vérification de nil ne peut pas distinguer : .set avec une valeur signifie une nouvelle valeur, .set avec nil signifie que la valeur est explicitement effacée, et .unset signifie que le paramètre ne faisait pas partie de la requête. La distinction permet aux modifications pilotées par Siri d’effacer une propriété (par exemple, « ne répète pas cet événement ») sans que cela soit confondu avec « laisser inchangé. »1
Comment donner à Siri la conscience de l’écran de mon application ?
Ajoutez deux view modifiers. Placez .appEntityIdentifier sur la vue liste, en passant un EntityIdentifier pour chaque entité d’événement, afin que le système sache quels événements sont à l’écran pendant le parcours. Placez .userActivity avec un EntityIdentifier sur la vue de détail afin que le système sache qu’un événement précis est en focus. Ensemble, ils permettent à un utilisateur de dire « envoie un e-mail aux personnes de cet événement » et à Siri de résoudre « cet événement » vers exactement celui qui est consulté.1
Cet article s’inscrit dans un cluster sur les frameworks d’intelligence d’Apple. Pour le framework sur lequel reposent les App Schemas, commencez par App Intents : la nouvelle API d’Apple vers votre application. Pour exécuter le travail d’un intent sans lancer l’interface, ce qui est une préoccupation distincte du raisonnement sur le contenu traité ici, lisez l’exécution en arrière-plan dans App Intents. Pour l’histoire plus large de la donation Spotlight derrière la résolution sémantique, voyez l’IA sur l’appareil et l’indexation des médias Spotlight. Le hub complet de la série est la série Apple Ecosystem.
Références
-
Apple, WWDC 2026 session 344, Code-along: Make your app available to Siri. Source pour les App Schemas et les App Schema Domains (le domaine calendrier ; pas de phrases d’entraînement, pas de NLP) ; les entités schématisées via les extraits Xcode (
calendar_calendar,calendar_attendee,calendar_event,calendar_createEvent,calendar_updateEvent,calendar_attendeeStatus,calendar_attendeeType) ;IndexedEntityet la donation Spotlight viaCSSearchableIndexau moyen deindexAppEntities/deleteAppEntities; la résolution par nom, propriété ou contexte ;TransientAppEntityet la justification de modélisation du participant ;IntentPerson; les valeurs union (PlaceDescriptordu frameworkGeoToolbox, String ; alarmesDurationouDate) etCalendar.RecurrenceRule; le wrapper@Dependency,EntityQuery,EnumerableEntityQueryetDisplayRepresentation; l’OpenEventIntentsystem.open; la conscience de l’écran via.appEntityIdentifieret.userActivityportant unEntityIdentifier;IntentParameter.valueState(.set/.unset) ; la carte de résultat personnaliséeShowsSnippetView; la confirmation et la levée d’ambiguïté deDeleteEventIntent; et le frameworkAppIntentsTestingréférencé pour les tests automatisés. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩