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 umToggle(isOn:intent:)na view de um widget; o sistema executa operform()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
ControlWidgetconstruído a partir deControlWidgetButtonouControlWidgetToggle, apoiado nos mesmos App Intents, aparece na Central de Controle, na Tela Bloqueada e no botão de Ação2. - Live Activities (ActivityKit):
ActivityAttributesmais umaActivityConfigurationmovem 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
ButtonouToggledentro de um widget. - Um
ControlWidgetna 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.
-
Apple Developer, “Adding interactivity to widgets and Live Activities”. Os widgets interativos (iOS 17+) usam
Button(intent:)eToggle(isOn:intent:)do SwiftUI apoiados em umAppIntent(ouSetValueIntentpara os toggles); operform()do intent roda na extensão de widget sem abrir o app, e a timeline recarrega para refletir o resultado. ↩↩↩↩ -
Apple Developer, “Creating controls to perform actions across the system” e o protocolo
ControlWidget. Os controles (iOS 18+) são construídos a partir deControlWidgetButtoneControlWidgetToggleligados a App Intents, e aparecem na Central de Controle, na Tela Bloqueada e no botão de Ação. ↩↩↩ -
Apple Developer, “ActivityKit” e “Displaying live data with Live Activities”.
ActivityAttributeseActivityConfigurationdefinem 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 compushTokenUpdates. ↩↩↩↩ -
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
WidgetRenderingModee 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. ↩↩↩↩ -
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. ↩↩↩