← Todos os Posts

App Schemas: deixe seu app disponível para a Siri

Na WWDC 2026, um engenheiro da Apple pegou um app de calendário em SwiftUI que só respondia a toques e fez a Siri pesquisar seus eventos, responder perguntas sobre eles por nome e por conteúdo de notas, criá-los e atualizá-los por voz, e renderizar um cartão de resultado personalizado, escrevendo três structs e preenchendo um punhado de snippets de código para chegar lá.1 O mecanismo por trás dessa mudança é o App Schemas: uma forma de descrever o conteúdo e as ações de um app em termos que a Siri já entende, sem frases de treinamento e sem processamento de linguagem natural do lado do desenvolvedor.1 A sessão é um code-along construído em torno de um projeto de exemplo chamado CometCal, e a lição por baixo do tema cósmico é estrutural. Você não ensina seu vocabulário à Siri. Você declara seus dados e suas ações contra um formato que a Siri já conhece, e o resto vem em seguida.

Este post percorre os três pilares que sustentam esse resultado: o modelo de schema-domínio, a doação semântica para o Spotlight por meio de IndexedEntity e a consciência de tela mais a distinção de valueState que torna seguras as atualizações guiadas por voz. Tudo o que segue vem diretamente da sessão. O assunto difere da execução em segundo plano em App Intents, que trata de executar trabalho sem abrir a UI; o foco aqui é como a Siri raciocina sobre o seu conteúdo e age sobre ele.

Atualização, 9 de setembro: a data de lançamento está marcada. A Siri AI chega com o iOS 27 em beta na segunda-feira, 14 de setembro, para aparelhos configurados em inglês, com francês, japonês, coreano, português e espanhol em outubro, e a Apple afirma que ela “will not be available initially in the EU on iOS, iPadOS, and watchOS” (não estará disponível inicialmente na UE no iOS, iPadOS e watchOS).2 A primeira demonstração da Siri na keynote foi uma demonstração de App Intents em tudo, menos no nome: em uma barraca de feira, um pedido para adicionar o resto dos ingredientes de uma receita à lista de compras. Os AirPods 5 abrem um caminho sem as mãos para o mesmo assistente, e o comunicado da Apple sobre os AirPods nomeia o mecanismo em que os apps de terceiros embarcam: a Siri “works seamlessly with apps from Apple’s vast ecosystem of developers, so users can continue to take action in the apps they already use” (funciona de forma integrada com apps do vasto ecossistema de desenvolvedores da Apple, para que os usuários continuem agindo nos apps que já usam).3 Um app sem entidades esquematizadas não está nessa frase. A keynote e os comunicados da Apple estão registrados no post do evento.

Atualização, 15 de setembro: o iOS 27.0 saiu em 14 de setembro como build 24A437, com o SDK dentro do Xcode 27, e as release notes finais trazem duas entradas de App Intents que tocam o código de schema diretamente.4 Um problema conhecido: “Existing entities that conformed to @AppEntity(schema: .photos.asset) in prior releases might no longer compile in the 27 SDKs because new properties were added to the schema in this release.” (Entidades existentes que aderiam a @AppEntity(schema: .photos.asset) em versões anteriores podem não compilar mais nos SDKs 27, porque novas propriedades foram adicionadas ao schema nesta versão.) A solução da Apple: “To continue conforming to the schema, adopt the additional properties and move the code behind an availability check.” (Para continuar aderindo ao schema, adote as propriedades adicionais e mova o código para trás de uma verificação de disponibilidade.)4 E uma renomeação registrada em Deprecations: “The calendar.deleteEvents schema has been renamed to calendar.deleteEvent.”4 Na interface Swift do AppIntents no SDK do iOS 27, deleteEvents não aparece nenhuma vez e deleteEvent está declarado, então um intent que ainda adere ao nome antigo falha na compilação em vez de gerar um warning; o DeleteEventIntent da sessão precisa passar para o nome novo.4 Um acréscimo menor das mesmas notas: “You can now pass a name parameter of type AttributedString to the notes.createNote and notes.updateNote schemas.”4 A leitura completa da versão final está no post sobre as release notes do iOS 27.0.

TL;DR

  • Os App Schemas descrevem as entidades, os parâmetros de ação e as saídas de um app em termos que a Siri já entende, organizados em App Schema Domains; o domínio de calendário cobre eventos, calendários, participantes e as ações sobre eles, sem frases de treinamento e sem NLP do lado do desenvolvedor.1
  • Entidades esquematizadas vêm de snippets de código do Xcode: digite um prefixo de domínio como calendar_ e escolha um snippet (por exemplo, calendar_calendar), que estrutura a entidade com sua macro, propriedades, display representation e stubs de query.1
  • Fazer uma entidade conformar a IndexedEntity e doá-la a um CSSearchableIndex via indexAppEntities (e removê-la via deleteAppEntities) permite que a Siri a resolva por nome, por propriedade ou por contexto, sem uma query de propriedade personalizada.1
  • Dois view modifiers, .appEntityIdentifier em uma lista e .userActivity em uma tela de detalhe (cada um carregando um EntityIdentifier), dão à Siri consciência de tela, de modo que uma solicitação como “envie um e-mail para as pessoas deste evento” se resolva sem nomear o evento.1
  • Os intents de atualização expõem IntentParameter.valueState, em que .set com um valor, .set com nil e .unset distinguem um valor novo, uma limpeza explícita e um parâmetro ausente, mantendo inequívocas as edições guiadas pela Siri.1

O que os App Schemas realmente são (Session 344)

Watch on Apple Developer ↗

Justin, da equipe de Swift Intelligence Frameworks, explica os App Schemas antes de abrir o Xcode, a partir de 3:12.

A Siri alcança um app por meio do framework App Intents, e o Apple Intelligence dá força ao raciocínio que vem por cima.1 O problema inicial no CometCal é simples: “Neste momento, a Siri não faz ideia do que significam um calendário ou um evento dentro do CometCal.”1 Os App Schemas fecham essa lacuna. Como a sessão coloca, eles “descrevem o conteúdo e as ações do meu app em termos que a Siri já consegue entender. Eles definem a estrutura das minhas entidades, os parâmetros das minhas ações e as saídas. Sem frases de treinamento, sem processamento de linguagem natural do meu lado.”1

A unidade organizadora é o App Schema Domain. O domínio de calendário “cobre tudo o que se refere a agendamento: eventos, calendários, participantes e as ações que operam sobre eles.”1 Como os formatos são predefinidos, o editor faz a catalogação. O engenheiro cria um arquivo CalendarEntity, importa AppIntents, digita calendar_ e “o Xcode oferece todos os schemas do domínio Calendar, ali mesmo no autocompletar.”1 Selecionar calendar_calendar preenche a estrutura: a macro da entidade, propriedades, uma display representation e stubs de query, produzindo o que a sessão chama de “uma entidade esquematizada, um tipo sobre o qual a Siri consegue raciocinar.”1

A convenção de nomenclatura merece uma observação cuidadosa. Os nomes dos snippets de schema aparecem no editor como identificadores em minúsculas e prefixados por sublinhado (calendar_calendar, calendar_attendee, calendar_event, calendar_createEvent, calendar_updateEvent, além de snippets de enum como calendar_attendeeStatus e calendar_attendeeType), e a transcrição falada os apresenta assim. Os tipos Swift que eles estruturam (uma macro @AppEntity, uma DisplayRepresentation, conformidades a protocolos de query) seguem a capitalização comum do Swift. Confirme a grafia e a capitalização exatas de cada símbolo na documentação de App Intents da Apple e no projeto de exemplo CometCal disponível para download antes de programar contra eles, já que um code-along falado não é uma referência precisa para capitalização.

O retorno do modelo de schema é alcance com muito pouco código. A sessão resume toda a camada de conteúdo como “três structs e o preenchimento de alguns snippets de código.”1 O CometCal constrói três entidades de riqueza crescente: um calendário, um participante e um evento que reúne os outros dois. O evento “se compõe com as outras entidades construídas antes”: seu calendário é uma CalendarEntity, e seus participantes são um array de AttendeeEntity, e “a Siri entende essas relações com os App Schemas.”1 O schema também decide o que é obrigatório versus opcional. Itens essenciais como título ou data de início se conectam diretamente; propriedades de schema opcionais que um app não usa (a sessão cita o tempo de deslocamento e a localização virtual) podem ficar sem definição; e uma propriedade que existe no modelo de dados, mas não no schema, como isFavorite, ainda pode ser adicionada à entidade.1

Outras duas mecânicas de schema aparecem no evento. Valores de união permitem que uma propriedade contenha um de vários tipos: a localização pode ser “ou um PlaceDescriptor do framework GeoToolbox, ou uma String”, e um alarme pode ser ou uma Duration ou uma Date.1 A propriedade de recorrência usa o Calendar.RecurrenceRule do Foundation e converte de e para o próprio enum de frequência do CometCal para os casos diário, semanal, mensal e anual.1 Enums esquematizados (a sessão aponta para um enum de status de evento que ela chama de EventEntityStatus, e os enums de participante acima) chegam completos a partir do snippet, e o app adota os casos que se aplicam; se um app usa terminologia diferente, você mapeia o modelo existente para os casos do schema “para que a Siri reconheça o formato.”1

Doação semântica por meio de IndexedEntity

O schema dá à Siri um vocabulário. A doação dá à Siri os dados de verdade sobre os quais raciocinar. Os dois são passos separados, e a sessão é explícita ao dizer que é fácil esquecer o segundo: “IndexedEntity define o formato do meu conteúdo indexado, mas as entidades ainda precisam ser doadas.”1

Fazer uma entidade conformar ao protocolo IndexedEntity é o que habilita a correspondência por significado, e não apenas por texto.1 A razão é o índice de busca. A conformidade “permite que meu app doe entidades usando o índice do Spotlight para obter os benefícios do entendimento semântico”, e, uma vez que uma entidade é doada, “a Siri consegue resolvê-la por nome, por propriedade ou por contexto, sem exigir uma query de propriedade personalizada.”1 Essa última frase é o ponto inteiro. Você não escreve nenhum matcher sob medida para “o almoço da tripulação” ou “eventos que mencionam oxigênio”. A Siri pesquisa diretamente os títulos e o conteúdo de notas doados, e “responde a cada pergunta usando o conteúdo do app. Sem necessidade de linguagem natural personalizada… apenas entidades e schemas.”1

A doação corre por meio do CSSearchableIndex. O CometCal mantém uma instância de CSSearchableIndex, criada no inicializador de seu CalendarManager sob um nome exclusivo do app.1 A regra que a sessão estabelece é que “sempre que calendários, ou qualquer entidade indexada por sinal, mudam, o índice precisa ser atualizado.”1 Então a camada de dados doa na escrita: o caminho de criação chama indexAppEntities com o índice pesquisável antes de retornar, o caminho de atualização reindexa a entidade alterada, e o caminho de exclusão chama deleteAppEntities, “passando o id e o tipo da entidade.”1 Depois de conectar a entidade de calendário, o engenheiro cria um calendário chamado “Lunar Orbit Log”, desliza até a busca e o encontra com seu ícone e título, a prova de que a doação pegou.1

Nem toda entidade deveria ser indexada, e o participante é o contraexemplo que ensina a regra. AttendeeEntity conforma a TransientAppEntity em vez de IndexedEntity, “uma entidade temporária que não exige um identificador único e não se destina a ser consultada.”1 O raciocínio é disciplina de modelagem: no CometCal, um participante representa “a participação de uma pessoa em um evento específico, não a pessoa em si”, a mesma pessoa pode comparecer a muitos eventos, e “indexar cada participação separadamente criaria resultados duplicados no Spotlight.”1 Como os participantes são sempre alcançados por meio de seu evento, não há um caminho de busca independente a manter, e TransientAppEntity “deixa isso explícito… nenhuma query a escrever, nenhum índice a manter.”1 O participante também introduz IntentPerson, “a forma padrão do sistema de representar uma pessoa com nome e informações de contato”, útil para entregar ao Mail o e-mail de um participante e redigir uma mensagem.1

As entidades indexadas ainda precisam de seu encanamento de query. A query mantém a camada de dados por meio do property wrapper @Dependency, “como o App Intents injeta recursos compartilhados em intents e queries”, de modo que a query usa o único CalendarManager registrado em vez de uma instância nova, e a query é marcada como main-actor porque o manager também é.1 O método EntityQuery obrigatório busca por ID nos casos em que o sistema já a conhece, e conformar a EnumerableEntityQuery com um método allEntities permite que o sistema liste mais tarde os calendários disponíveis quando a Siri precisar oferecê-los como opções ao criar um evento.1 Uma DisplayRepresentation (título mais uma imagem de calendário do sistema) diz à Siri e ao Spotlight como renderizar a entidade.1

Há uma costura de navegação que vale a pena nomear, porque a doação sozinha leva o usuário à tela principal do app. Um OpenEventIntent que conforma ao schema system.open, recebe uma EventEntity como seu alvo e diz à camada de navegação para rotear até ele fecha essa lacuna: o sistema o invoca “sempre que alguém toca em um resultado de evento no Spotlight ou na Siri, ou pede à Siri para abrir um”, de modo que um resultado tocado abre direto na tela de detalhe do evento.1

Consciência de tela e a distinção de valueState

Os dois primeiros pilares deixam a Siri encontrar conteúdo por nome. O terceiro deixa a Siri usar o que já está diante do usuário e, então, agir sobre isso sem ambiguidade.

A consciência de tela custa “apenas dois view modifiers.”1 Na tela de lista, .appEntityIdentifier se anexa à lista, “passando um EntityIdentifier para cada uma das entidades de evento”, o que “conecta a lista às suas entidades, de modo que, quando alguém está navegando pela lista, o sistema sabe quais eventos estão na tela.”1 Na tela de detalhe, .userActivity carrega um EntityIdentifier para o único evento em foco, dizendo ao sistema “que aquele evento específico está em primeiro plano, para que a Siri consiga resolver este evento para exatamente aquele que está sendo visto.”1 Com ambos no lugar, um usuário na tela de detalhe de um evento pode dizer “envie um e-mail para as pessoas deste evento e peça que alguém traga chocolate e marshmallows”, e a Siri usa seu entendimento do evento na tela para encontrar os participantes e entregá-los ao Mail, sem exigir título.1

Agir sobre o conteúdo é o mesmo padrão de lê-lo, executado ao contrário. Os intents também vêm de snippets. O snippet calendar_createEvent estrutura o intent com sua macro, o schema, os parâmetros que o schema exige e um stub de perform.1 A lógica de perform é um formato de três passos que a sessão enuncia sem rodeios: “resolver os parâmetros do intent em algo que a camada de dados entenda, executar a ação e retornar o resultado como uma entidade.”1 Para criar, isso significa extrair a localização de seu valor de união, converter a recorrência se fornecida, chamar o método de criação do manager e retornar uma EventEntity.1 Como o intent conforma a um schema, “a Siri consegue cuidar de todo o trabalho pesado. Interpretar a linguagem, pedir esclarecimentos e confirmar detalhes”, de modo que o desenvolvedor nunca escreve a conversa.1

As atualizações revelam a sutileza que torna confiáveis as edições guiadas por voz. A maioria dos parâmetros de calendar_updateEvent é opcional, porque um usuário em geral muda uma ou duas coisas, e “o parâmetro de evento é o que a Siri resolve; todo o resto é opcional.”1 Uma simples verificação de nil não consegue responder à pergunta real. Como a sessão coloca, “quando a recorrência é nil, isso significa ‘não mude’ ou ‘remova’? Uma simples verificação de nil não me diz com qual caso estou lidando.”1 A resposta é IntentParameter.valueState, exposto porque a macro do intent envolve cada propriedade em um IntentParameter. Os três estados carregam significados distintos: “.set com um valor de verdade significa que um novo valor foi fornecido. .set com um valor nil significa que ele foi explicitamente limpo. .unset significa que o parâmetro não faz parte da solicitação.”1 A distinção “se aplica a qualquer parâmetro opcional em que limpar o valor é uma ação significativa”, e é por isso que “não repita este evento” limpa a recorrência de forma confiável, em vez de deixá-la intocada.1

Dois acabamentos arrematam a camada de ação. Um cartão de resultado personalizado substitui o cartão padrão de display representation da Siri: adicionar ShowsSnippetView ao tipo de retorno do método de perform e passar uma view SwiftUI já preparada (a da sessão recebe uma EventEntity) renderiza o estilo do próprio app dentro da Siri, uma abordagem que “funciona para qualquer outro intent que retorne um resultado.”1 E DeleteEventIntent, “o mais simples dos três”, recebe apenas o evento e um span opcional para eventos recorrentes; a Siri “cuida automaticamente do diálogo de confirmação antes que qualquer coisa seja removida” e desambigua quando mais de um evento corresponde.1

Principais conclusões

Para desenvolvedores iOS adotando App Intents:

  • Recorra primeiro ao schema. Digite um prefixo de domínio como calendar_ no Xcode e deixe o autocompletar listar os snippets disponíveis; o snippet estrutura a macro, as propriedades, a display representation e os stubs de query, de modo que você preenche tipos e mapeamento em vez de inventar estrutura.1
  • Decida, por entidade, se ela merece um índice. Faça conteúdo durável e consultável conformar a IndexedEntity e doe-o; use TransientAppEntity para registros do tipo participação (o participante do CometCal) que são sempre alcançados por meio de um pai e só poluiriam o Spotlight se indexados.1
  • Verifique a grafia e a capitalização exatas dos símbolos na documentação de App Intents da Apple e no exemplo CometCal antes de programar, já que os nomes do code-along vêm de uma transcrição falada.

Para equipes projetando fluxos de voz e Apple Intelligence:

  • Trate a doação como uma responsabilidade do caminho de escrita. Chame indexAppEntities na criação e na atualização e deleteAppEntities na exclusão, indexados pelo id e pelo tipo da entidade, para que o índice da Siri nunca se desvie dos dados.1
  • Adicione consciência de tela cedo: .appEntityIdentifier em listas e .userActivity em telas de detalhe (cada um carregando um EntityIdentifier) deixam os usuários dizerem “este evento” em vez do título.1
  • Trate valueState explicitamente nos intents de atualização. Ramifique em .set-com-valor, .set-com-nil e .unset, para que uma limpeza explícita nunca seja lida como “deixar inalterado.”1

FAQ

O que são os App Schemas em App Intents?

Os App Schemas descrevem o conteúdo e as ações de um app em termos que a Siri já entende: eles definem a estrutura das entidades de um app, os parâmetros de suas ações e as saídas, sem frases de treinamento e sem processamento de linguagem natural do lado do desenvolvedor. Eles são organizados em App Schema Domains; o domínio de calendário cobre eventos, calendários, participantes e as ações sobre eles. No Xcode, você adota um schema digitando um prefixo de domínio como calendar_ e escolhendo um snippet de código como calendar_calendar, que estrutura a entidade.1

Como a Siri resolve o conteúdo do meu app por nome ou contexto?

Faça a entidade conformar ao protocolo IndexedEntity e doe-a a um CSSearchableIndex (o índice do Spotlight) chamando indexAppEntities na criação e na atualização, e deleteAppEntities com o id e o tipo da entidade na exclusão. A doação dá à Siri “entendimento semântico”, deixando-a resolver uma entidade por nome, por propriedade ou por contexto sem uma query de propriedade personalizada, inclusive pesquisando o conteúdo de notas para perguntas como “quais eventos mencionam oxigênio?”1

Quando devo usar TransientAppEntity em vez de IndexedEntity?

Use TransientAppEntity para uma entidade temporária que não precisa de identificador único e não se destina a ser consultada. O participante do CometCal se encaixa porque um participante representa a participação de uma pessoa em um evento específico, não a pessoa; a mesma pessoa comparece a muitos eventos, e indexar cada participação separadamente criaria resultados duplicados no Spotlight. Como os participantes são alcançados apenas por meio de seu evento, não há um caminho de busca independente, então a entidade transitória não precisa de query nem de índice.1

O que é valueState e por que ele importa para os intents de atualização?

Em um intent de atualização, a macro do App Intents envolve cada propriedade em um IntentParameter que expõe um valueState. Ele distingue três casos que uma verificação de nil não consegue: .set com um valor significa um valor novo, .set com nil significa que o valor foi explicitamente limpo, e .unset significa que o parâmetro não fez parte da solicitação. A distinção deixa as edições guiadas pela Siri limparem uma propriedade (por exemplo, “não repita este evento”) sem que isso seja confundido com “deixar inalterado.”1

Como dou à Siri consciência de tela do meu app?

Adicione dois view modifiers. Coloque .appEntityIdentifier na tela de lista, passando um EntityIdentifier para cada entidade de evento, para que o sistema saiba quais eventos estão na tela enquanto se navega. Coloque .userActivity com um EntityIdentifier na tela de detalhe, para que o sistema saiba que um evento específico está em foco. Juntos, eles deixam um usuário dizer “envie um e-mail para as pessoas deste evento” e fazem a Siri resolver “este evento” para exatamente aquele que está sendo visto.1


Este post integra um cluster sobre os frameworks de inteligência da Apple. Para o framework sobre o qual os App Schemas se apoiam, comece por App Intents: a nova API da Apple para o seu app. Para executar trabalho de intent sem abrir a UI, o que é uma preocupação separada do raciocínio sobre conteúdo tratado aqui, leia execução em segundo plano em App Intents. Para a história mais ampla de doação ao Spotlight por trás da resolução semântica, veja IA no dispositivo e indexação de mídia no Spotlight. O hub completo da série é a Apple Ecosystem Series.

Referências


  1. Apple, WWDC 2026 session 344, Code-along: Make your app available to Siri. Fonte para App Schemas e App Schema Domains (o domínio de calendário; sem frases de treinamento, sem NLP); entidades esquematizadas via snippets do Xcode (calendar_calendar, calendar_attendee, calendar_event, calendar_createEvent, calendar_updateEvent, calendar_attendeeStatus, calendar_attendeeType); IndexedEntity e doação ao Spotlight por meio de CSSearchableIndex via indexAppEntities / deleteAppEntities; resolução por nome, propriedade ou contexto; TransientAppEntity e a justificativa de modelagem do participante; IntentPerson; valores de união (PlaceDescriptor do GeoToolbox, String; alarmes Duration ou Date) e Calendar.RecurrenceRule; o wrapper @Dependency, EntityQuery, EnumerableEntityQuery e DisplayRepresentation; o OpenEventIntent de system.open; consciência de tela via .appEntityIdentifier e .userActivity carregando um EntityIdentifier; IntentParameter.valueState (.set/.unset); o cartão de resultado personalizado ShowsSnippetView; a confirmação e a desambiguação de DeleteEventIntent; e o framework AppIntentsTesting referenciado para testes automatizados. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. Apple Newsroom, Apple debuts iPhone 18 Pro and iPhone 18 Pro Max, 9 de setembro de 2026: datas de lançamento da Siri AI e a nota sobre a UE. ↩

  3. Apple Newsroom, Apple introduces AirPods 5 with best-in-class open-ear Active Noise Cancellation, 9 de setembro de 2026: Siri AI sem as mãos; “Siri already works seamlessly with apps from Apple’s vast ecosystem of developers, so users can continue to take action in the apps they already use.” ↩

  4. Apple, iOS & iPadOS 27 Release Notes, obtidas em 15 de setembro de 2026 após o lançamento da versão final: App Intents, Known Issues (181800016, FB23652582) para a entrada de photos.asset e sua solução; App Intents, Deprecations (176751155) para a renomeação em calendar.deleteEvent; App Intents, New Features (173431080) para o parâmetro name do tipo AttributedString. O número do build vem do feed Releases da Apple, “iOS 27.0 (24A437)”, segunda-feira, 14 de setembro de 2026. Verificação do SDK pelo autor no Xcode 27.0 (27A266a) em 15 de setembro de 2026: AppIntents.swiftmodule/arm64e-apple-ios.swiftinterface no SDK do iPhoneOS 27.0 não contém nenhuma ocorrência de deleteEvents e declara deleteEvent: some AppIntents::AppSchemaIntent. ↩↩↩↩↩

Artigos relacionados

App Intents são a nova API da Apple para o seu app

Lancei um App Intent no Water e descobri o que o Apple Intelligence espera dos apps de terceiros no iOS 26. O contrato i…

16 min de leitura

O que há de novo no Instruments 27 para a responsividade de apps

O Instruments 27 adiciona Top Functions, Run Comparisons, um instrument de Swift executors e um painel Inspector para di…

12 min de leitura

Still Rooms: composição por IA, não geração por IA

Como Still Rooms, o álbum dentro do Return, foi escrito como partitura por um modelo, renderizado a partir de instrument…

32 min de leitura