← Todos os Posts

A superfície de widgets do iOS 26: um App Intent, muitos lugares

Durante anos, um widget foi apenas um instantâneo. O sistema renderizava sua view em uma timeline, o usuário olhava para ela, e qualquer toque abria o app. Esse modelo acabou. Desde o iOS 17, um widget pode carregar botões e interruptores que executam código sem abrir nada, e o código que eles executam é um App Intent1. O mesmo vale para os controles da Central de Controle e para os botões dentro de uma Live Activity. Quando você enxerga isso, a superfície de widgets do iOS 26 deixa de parecer três APIs separadas e passa a parecer uma só: um conjunto de lugares onde o sistema renderiza seus App Intents, cada um com seu próprio espaço e a mesma estrutura por baixo.

Essa mudança de perspectiva é o ponto central deste artigo. Aprenda o App Intent uma vez e você dá vida à Tela de Início, à Tela Bloqueada, à Central de Controle, ao botão de Ação, à Ilha Dinâmica e (o mesmo intent de novo) à Siri e à Apple Intelligence. Escreva três recursos desconexos e você fará quatro vezes mais trabalho para um resultado pior.

Resumo

  • Widgets interativos (iOS 17+): coloque um Button(intent:) ou um Toggle(isOn:intent:) na view de um widget; o sistema executa o perform() do App Intent na sua extensão de widget, fora do app, e em seguida recarrega a timeline1.
  • Controles da Central de Controle (iOS 18+): um ControlWidget construído a partir de ControlWidgetButton ou ControlWidgetToggle, apoiado nos mesmos App Intents, aparece na Central de Controle, na Tela Bloqueada e no botão de Ação2.
  • Live Activities (ActivityKit): ActivityAttributes mais uma ActivityConfiguration movem a Tela Bloqueada e a Ilha Dinâmica; as atualizações vindas do servidor chegam por push, e os botões internos também são App Intents3.
  • O iOS 26 acrescenta a renderização, não o modelo: os widgets ganham a apresentação Liquid Glass e modos de renderização com cor de destaque, mas a arquitetura de App-Intents-como-superfície permanece inalterada desde o iOS 184.
  • O fato que unifica tudo: um botão de widget, um controle, uma frase para a Siri e uma ação da Apple Intelligence podem ser todos o mesmo App Intent. Projete a capacidade uma única vez.

Widgets interativos: o botão que não abre o app

O mecanismo é simples e vale a pena descrevê-lo com exatidão. Você adiciona um Button ou um Toggle do SwiftUI à view de um widget, mas, em vez de uma closure de ação, você passa um App Intent1:

struct WaterWidgetView: View {
    let logged: Int

    var body: some View {
        VStack {
            Text("\(logged) glasses")
            Button(intent: LogWaterIntent()) {
                Label("Add", systemImage: "plus")
            }
        }
    }
}

Quando o usuário toca, o sistema executa LogWaterIntent.perform() dentro da sua extensão de widget. O app não abre. O intent faz seu trabalho (grava no armazenamento compartilhado, atualiza uma contagem), e a timeline do widget recarrega para mostrar o resultado.

Um Toggle funciona da mesma maneira por meio de um SetValueIntent, que recebe o novo valor on/off que o usuário acabou de definir:

struct ToggleReminderIntent: SetValueIntent {
    static let title: LocalizedStringResource = "Toggle Reminder"

    @Parameter(title: "Enabled")
    var value: Bool

    func perform() async throws -> some IntentResult {
        ReminderStore.shared.enabled = value
        return .result()
    }
}

O widget vincula Toggle(isOn: store.enabled, intent: ToggleReminderIntent()), o sistema define value com o novo estado, executa perform() e recarrega. O mesmo formato do botão, com um parâmetro a mais1.

Duas restrições definem o que você pode fazer aqui, e ambas são fáceis de violar. Primeira: o perform() roda no ambiente restrito da extensão de widget, com um orçamento de execução apertado; ele serve para uma mudança rápida de estado, não para um upload de rede ou um cálculo pesado. Segunda: o widget reflete estado, ele não anima uma UI arbitrária. Você altera os dados e a timeline é renderizada de novo; você não executa uma transição personalizada. Projete a interação como “inverter um valor, mostrar o novo valor” e ela funciona. Tente ir além disso e o sistema vai resistir.

Controles da Central de Controle: o mesmo intent, outra sala

O iOS 18 abriu a Central de Controle, a Tela Bloqueada e o botão de Ação a controles de terceiros, e a API é deliberadamente paralela à dos widgets2. Um controle é um ControlWidget, e seu corpo é um ControlWidgetButton ou um ControlWidgetToggle ligado a um App Intent:

struct LogWaterControl: ControlWidget {
    var body: some ControlWidgetConfiguration {
        StaticControlConfiguration(kind: "com.example.logWater") {
            ControlWidgetButton(action: LogWaterIntent()) {
                Label("Log Water", systemImage: "drop.fill")
            }
        }
    }
}

Se o LogWaterIntent já dá vida ao seu widget interativo, o controle sai quase de graça: mesmo intent, novo invólucro. É a arquitetura dando retorno. O controle não é uma segunda implementação do recurso; é um segundo ponto de montagem para aquele que você já escreveu. Um controle de alternância usa SetValueIntent exatamente como o toggle do widget faz, então uma capacidade de “silenciar”, “iniciar sessão” ou “alternar modo escuro” construída uma única vez aparece na Central de Controle, na Tela Bloqueada e no botão de Ação sem nenhuma lógica nova2.

Live Activities: a superfície que se atualiza sozinha

As Live Activities são o terceiro lugar, e o que tem mais peças em movimento. Um tipo ActivityAttributes define o conteúdo estático e o dinâmico, uma ActivityConfiguration renderiza a apresentação na Tela Bloqueada e as regiões da Ilha Dinâmica, e o ActivityKit inicia, atualiza e encerra a atividade3. Os botões dentro de uma Live Activity são, mais uma vez, App Intents, de modo que um controle de “pausar” ou “próximo” na Ilha Dinâmica executa o mesmo tipo de intent que o botão do widget.

A parte que torna as Live Activities uma disciplina à parte é o caminho de atualização. Um timer que você atualiza localmente é simples. Uma atividade movida por eventos que acontecem em um servidor (uma entrega em trânsito, o placar de um jogo mudando) atualiza por push: você se registra em pushTokenUpdates, envia payloads de push do ActivityKit a partir do seu backend, e o sistema atualiza a Tela Bloqueada e a Ilha Dinâmica sem que seu app esteja rodando3. Isso é genuinamente poderoso e genuinamente fácil de errar, porque agora a correção da sua atividade depende de um contrato com o servidor, da confiabilidade do push e de uma política de data de expiração, não apenas do código local.

O que o iOS 26 de fato mudou

A manchete dos widgets do iOS 26 é apresentação, não arquitetura. Os widgets adotam o material Liquid Glass e ganham modos de renderização com cor de destaque, de modo que combinam com a nova linguagem de design do sistema e recebem a tonalidade correta nos contextos em que o sistema recolore o conteúdo4. Isso importa para como um widget se apresenta na Tela de Início, na Tela Bloqueada e no StandBy, e merece uma revisão de design. Mas não muda como a interatividade funciona. Se você construiu widgets e controles interativos no iOS 18, o movimento do iOS 26 é uma reformulação visual, não uma reescrita. Encare com desconfiança qualquer afirmação de que o iOS 26 “introduziu” os widgets interativos; a interatividade chegou no iOS 17, os controles no iOS 18, e o iOS 26 os fez parecer com o resto do sistema.

A implicação de design do Liquid Glass, porém, é real. Um widget é conteúdo que o sistema compõe sobre o papel de parede e refrata através do chrome de vidro, então valem as mesmas regras que governam o Liquid Glass em um app: respeite a separação entre camada funcional e camada de conteúdo, e não brigue com o material usando fundos personalizados pesados que o vidro não consegue interpretar.

A arquitetura, dita sem rodeios

Aqui está o modelo que vale a pena guardar. Um App Intent é uma capacidade nomeada, tipada e descrita. O iOS oferece a você um conjunto crescente de lugares onde montar essa capacidade:

  • Um Button ou Toggle dentro de um widget.
  • Um ControlWidget na Central de Controle, na Tela Bloqueada e no botão de Ação.
  • Um botão dentro de uma Live Activity e de sua Ilha Dinâmica.
  • Uma frase para a Siri e uma ação dos Atalhos.
  • Uma ação que a Apple Intelligence pode invocar em nome do usuário5.

Cada um desses é o mesmo tipo AppIntent com um método perform(). O trabalho está em projetar bem essa capacidade: um nome claro, parâmetros tipados, um perform() rápido e idempotente, e um resultado sensato. Faça isso uma vez e as superfícies passam a ser invólucros. Esse é o mesmo argumento que defendi sobre os App Intents serem a verdadeira API do seu app e sobre as três superfícies que um app iOS hoje expõe: a superfície de widgets não é um recurso que você constrói, é um lugar onde suas capacidades aparecem assim que passam a existir.

Quando não vale a pena

A superfície de widgets recompensa apps com estado genuinamente consultável de relance e ações rápidas: um rastreador, um timer, um interruptor, um controle de reprodução. Ela não recompensa qualquer coisa.

  • Sem estado consultável de relance, sem widget. Se o seu app não tem nada que valha a pena mostrar sem ser aberto, um widget é só decoração que custa manutenção e mais um alvo de extensão.
  • Ações pesadas ou lentas não cabem no perform() aqui. O ambiente de execução do widget e do controle é restrito. Se a ação precisa de tempo real ou de processamento real, o botão deve abrir o app em um estado preparado, não fingir que faz o trabalho dentro da extensão.
  • Uma Live Activity para algo que não é ao vivo. As Live Activities são para eventos com prazo definido e em mudança ativa. Usar uma como um selo de status permanente é uma leitura errada da superfície e um caminho rápido para a lista negra do sistema no que toca ao orçamento de atividade.

A habilidade não está em aprender três APIs. Está em projetar App Intents que valham a pena montar, e então montá-los onde o usuário já está: a Tela de Início que ele consulta, a Central de Controle até onde ele desliza, a Ilha Dinâmica que já lhe mostra algo. Construa a capacidade uma vez, com bom gosto, e o iOS lhe entrega as superfícies de graça.

Perguntas frequentes

O iOS 26 introduziu os widgets interativos?

Não. Os widgets interativos chegaram no iOS 17 e os controles da Central de Controle no iOS 18; o iOS 26 fez com que eles adotassem o material Liquid Glass e a renderização com cor de destaque, de modo a combinar com a linguagem de design do sistema4. Encare com desconfiança qualquer afirmação de que o iOS 26 “introduziu” os widgets interativos: a mudança do iOS 26 é uma reformulação visual, não uma reescrita.

Como um botão dentro de um widget do iOS realmente executa uma ação?

O botão executa um App Intent. Um Button ou Toggle em um widget invoca um AppIntent nomeado e tipado com um método perform(), de modo que o widget age sem abrir o app. O mesmo intent dá vida a um controle da Central de Controle, a um botão de Live Activity, a uma frase para a Siri e a uma ação dos Atalhos5.

O que de fato mudou para os widgets no iOS 26?

Apresentação, não arquitetura. Os widgets adotam o Liquid Glass e ganham modos de renderização com cor de destaque, de modo a receber a tonalidade correta na Tela de Início, na Tela Bloqueada e no StandBy4. A interatividade funciona exatamente como no iOS 18, então um widget interativo já existente precisa de uma revisão de design, não de uma reescrita.

Como as Live Activities se atualizam quando o app não está rodando?

Por push. Você se registra em pushTokenUpdates, envia payloads de push do ActivityKit a partir do seu backend, e o sistema atualiza a Tela Bloqueada e a Ilha Dinâmica sem que seu app esteja rodando3. Isso faz a correção da atividade depender de um contrato com o servidor, da confiabilidade do push e de uma política de data de expiração, não apenas do código local.

Onde um único App Intent pode aparecer?

O mesmo tipo AppIntent se monta em um Button/Toggle de widget, em um ControlWidget na Central de Controle / Tela Bloqueada / botão de Ação, em uma Live Activity e sua Ilha Dinâmica, em uma frase para a Siri, em uma ação dos Atalhos, e como uma ação que a Apple Intelligence pode invocar5. Projete a capacidade uma vez e as superfícies passam a ser invólucros.

Quando eu não deveria construir um widget ou uma Live Activity?

Dispense um widget quando o app não tem estado consultável de relance que valha a pena mostrar sem ser aberto. Mantenha ações pesadas ou lentas fora do perform() no ambiente restrito do widget; em vez disso, abra o app em um estado preparado. E não use uma Live Activity como um selo de status permanente; elas são para eventos com prazo definido e em mudança ativa, e usar uma da forma errada queima seu orçamento de atividade.



  1. Apple Developer, “Adding interactivity to widgets and Live Activities”. Os widgets interativos (iOS 17+) usam Button(intent:) e Toggle(isOn:intent:) do SwiftUI apoiados em um AppIntent (ou SetValueIntent para os toggles); o perform() do intent roda na extensão de widget sem abrir o app, e a timeline recarrega para refletir o resultado. 

  2. Apple Developer, “Creating controls to perform actions across the system” e o protocolo ControlWidget. Os controles (iOS 18+) são construídos a partir de ControlWidgetButton e ControlWidgetToggle ligados a App Intents, e aparecem na Central de Controle, na Tela Bloqueada e no botão de Ação. 

  3. Apple Developer, “ActivityKit” e “Displaying live data with Live Activities”. ActivityAttributes e ActivityConfiguration definem e renderizam a Tela Bloqueada e a Ilha Dinâmica; o ActivityKit inicia, atualiza e encerra atividades, e as atualizações vindas do servidor usam push com pushTokenUpdates

  4. Renderização de widgets no iOS 26: os widgets adotam o material Liquid Glass e o modo de renderização com cor de destaque, controlados por meio de WidgetRenderingMode e do valor de ambiente \.widgetRenderingMode. O modelo de interatividade (App Intents em widgets e controles) permanece inalterado desde o iOS 17 (widgets) e o iOS 18 (controles). Apple, “WWDC 2025: the new software design” e a documentação do WidgetKit

  5. Apple Developer, “App Intents”. O mesmo tipo AppIntent é a unidade que o sistema expõe por meio da Siri, dos Atalhos, do Spotlight, das superfícies de widget e de controle, e da Apple Intelligence. Análise do autor sobre o modelo entre superfícies: App Intents Are Apple’s New API to Your App, App Intents 2 and the iOS 26 additions e as três superfícies de um app iOS

Artigos relacionados

Live Activities são uma máquina de estados, não um badge

A Live Activity do Return parece uma contagem regressiva na Lock Screen. É uma máquina de ciclo de vida com cinco estado…

15 min de leitura

O framework de tradução da Apple: gratuito, no dispositivo e mais afiado do que parece

O framework Translation da Apple: tradução gratuita no dispositivo com translationPresentation e TranslationSession, alé…

10 min de leitura

The Robots Are Taking Exams in My Search Console

First-party GSC data: 91% of 3.8M impressions fail a human-query filter. Exam questions, pasted errors, and agent sweeps…

10 min de leitura