View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Tópicos
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Resumo
  • Transcrição
  • Código
  • Novidades dos widgets

    O WidgetKit aprimora seu app com atualizações nos widgets, nas Atividades ao Vivo e nos controles. Saiba como incorporar seus widgets ao visionOS, adicioná-los ao CarPlay e deixá-los mais bonitos com os modos de renderização acentuados. Além disso, descubra como widgets relevantes podem aparecer no Conjunto Inteligente no watchOS e como as notificações por push podem ser usadas para manter seus widgets atualizados.

    Capítulos

    • 0:00 - Introdução
    • 1:03 - Widgets em novos lugares
    • 15:31 - Widgets de relevância
    • 18:12 - Atualizações de widgets por push

    Recursos

    • Increasing the visibility of widgets in Smart Stacks
    • Optimizing your widget for accented rendering mode and Liquid Glass
    • RelevanceKit
    • Updating widgets with WidgetKit push notifications
    • Updating your widgets for visionOS
      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC25

    • Aprimore seu app para o CarPlay
    • Crie widgets para visionOS
    • Novidades do watchOS 26

    WWDC24

    • Design Live Activities for Apple Watch
    • Extend your app’s controls across the system

    WWDC23

    • Bring widgets to new places
    • Meet Push Notifications Console

    WWDC20

    • The Push Notifications primer
  • Buscar neste vídeo...

    Olá! Meu nome é Tanner Oakes. Sou engineer na equipe System Experience. Widgets são ótimos para exibir informações e ações importantes no sistema, mantendo seu app útil mesmo quando estão em segundo plano. O WidgetKit continua evoluindo, tornando os widgets mais poderosos e presentes em novos lugares. Meu amigo Luca tem um app que regista o consumo de cafeína. Estou ajudado a atualizar esse app. Nesta apresentação, vou mostrar como ele aproveita todas as novidades nos widgets. Vou explorar os widgets, as Atividades ao Vivo e os controles reposicionados nas plataformas. Vou mostrar uma nova forma de exibir conteúdo relevante do widget no Conjunto Inteligente do watchOS. Por fim, vou mostrar como manter os widgets atualizados nos dispositivos com as notificações por push. Widgets, Atividades ao Vivo e controles estão em novos lugares. Primeiro, vou mostrar o novo visual dos widgets onde eles começaram. No iOS 26, a tela de Início pode exibir ícones e widgets em um visual de vidro transparente ou ser personalizada com uma cor de destaque específica, como azul. Esse visual pode ser configurado para widgets na Mesa e na Central de Notificações no macOS Tahoe. O novo visual foi criado de maneira semelhante no iOS e no macOS. O conteúdo dos widgets é criado no modo de renderização com destaque, aplicando tom branco aos elementos. Então, o fundo dos widgets é substituído por um vidro temático ou efeito de cor translúcida. O widget de monitoramento de cafeína fica ótimo no modo em destaque. Não preciso fazer nada. Pode ser necessário ajustar os widgets para parecerem melhor no modo com destaque. Adicionei um widget ao app que me mostra a bebida que mais consumo. A minha é matcha latte. O widget mostra a bebida com uma imagem grande, o nome na parte inferior e um fundo gradiente, tornando-o mais legível quando colocado sobre a imagem. Ao aplicar a renderização acentuada, todo o conteúdo do widget fica branco. Em conteúdo opaco, como a xícara de latte, tudo fica branco. O conteúdo parcialmente transparente, como o gradiente, fica branco e opaco. Não ficou legal. Não sei qual é a imagem, e é difícil ler o texto. Vou mostrar como personalizar o widget para processar a renderização com destaque. Esta é a visualização do widget. Tenho uma ZStack com a imagem da bebida, o gradiente e o texto. Vou adicionar a variável de ambiente widgetRenderingMode à visualização do widget. Vou exibir a imagem grande e o gradiente se o widget estiver sendo renderizado em cores completas. Depois, vou reposicionar a imagem sobre o texto, usando um VStack e exibindo a imagem se o widget estiver no modo com destaque. Acho que o layout ficou muito bom. Agora, só preciso melhorar a imagem. Vou adicionar o modificador widgetAccentedRenderingMode à imagem e definir como dessaturado. widgetAccentedRenderingMode é um modificador SwiftUI que pode ser aplicado a imagens nos widgets. O argumento me dá controle preciso como a imagem será exibida quando estiver no modo com destaque. O widgetAccentedRenderingMode aceita cinco opções diferentes. Vou mostrar como cada modo afeta a apresentação das imagens, comparando o modo com destaque no iOS e no macOS com o modo em um mostrador.

    No widgetAccentedRenderingMode, passar "nil" é o mesmo que não aplicar o modificador. Ele aplica a cor do conteúdo principal à imagem. A imagem nos widgets do iOS e do watchOS fica completamente branca. Ao passar "accented", a imagem fica com a cor de destaque. No iOS e macOS, as cores principal e de destaque são brancas, tornando minha imagem branca. No watchOS, a cor de destaque corresponde à cor do mostrador, tornando a imagem do widget azul. Passar em "desaturated" dessatura a cor na imagem. Esse efeito fica igual nos estilos de apresentação do iOS e do watchOS. Passar em accentedDesaturated aplica ambos os efeitos, dessatura as cores na imagem e aplica a cor com destaque do tema selecionado. No iOS, isso significa que a imagem é um pouco mais branca. No watchOS, minha imagem dessaturada assume a cor de destaque azul do tema. Passar fullColor exibe a imagem sem modificações no modo de renderização com destaque. Para se integrar melhor ao mostrador, essa opção é ignorada no watchOS. Em muitos widgets, use o modo dessaturado ou dessaturado com destaque para integrar o conteúdo da imagem ao restante da tela inicial. Use fullColor em imagens que representam conteúdo de mídia, como capas de álbuns ou capas. É com empolgação que vou mostrar como levar os widgets para uma nova dimensão. No visionOS 26, os apps para visionOS agora podem ter widgets. E, se você já tiver um app com widgets compatível com iPhone ou iPad, eles ficarão automaticamente disponíveis no visionOS. Todos os tamanhos da família do iOS e do macOS são compatíveis. Widgets no visionOS são interativos e animados, assim como nas outras plataformas. Vou mostrar como os widgets funcionam no visionOS e as novas opções no WidgetKit. No visionOS, os widgets podem ser adicionados ao ambiente e fixados em superfícies. Por padrão, eles assumem um visual elevado, ficando sobre a superfície. Os widgets também podem ser embutidos, fazendo com que pareçam integrados à superfície. Se um desses estilos não for adequado ao widget, use o modificador supportedMountingStyles na configuração para especificar quais opções devem ser fornecidas. Esse modificador está disponível para widgets do visionOS e do iOS. Por padrão, os widgets serão renderizados sob uma textura de vidro. Em apps para visionOS, uma textura de papel pode ser especificada, dando ao widget um visual de pôster. À esquerda está o widget de consumo de bebida frequente configurado com a textura vidro. À direita, vou testar o mesmo widget com a textura de papel. Use o modificador widgetTexture na configuração para especificar se o widget deve ser renderizado com uma textura de papel ou sob um painel de vidro. Para completar o visual dos widgets em estilo pôster, o visionOS disponibiliza uma nova família systemExtraLargePortrait. Esta é a versão vertical da família de widgets systemExtraLarge horizontais.

    Adicione-a à configuração do widget usando o modificador supportedFamilies. No visionOS, também é possível personalizar a cor do widget. Por padrão, o widget é exibido em cores completas. Ao selecionar o tema verde, o conteúdo do widget é exibido no modo de renderização com destaque. A moldura e o conteúdo do widget são tingidos com a cor selecionada. O fundo é substituído por uma cor sólida que complementa o tema de cor selecionado. Esse estilo usa a mesma abordagem de renderização já mencionada para iOS e macOS. Use as técnicas que mencionei para que o widget tenha a melhor aparência nesses temas de cores. Use o modificador widgetAccentedRenderingMode para personalizar a apresentação das imagens. Use a variável de ambiente widgetRenderingMode para aplicar modificações mais substanciais de modo condicional.

    No visionOS, os widgets podem ser integrados ao ambiente e posicionados em várias superfícies. Os widgets permanecem fixos quando você se move pelo ambiente. Widget fica visível, mesmo em uma parede do outro lado do ambiente. Como os objetos reais, os widgets mais distantes parecem menores e são mais difíceis de ver. Diferentemente de objetos físicos, os widgets no visionOS se adaptam à distância usando a nova API LevelOfDetail. Vou mostrar como adicionar LevelOfDetail ao widget de monitoramento de cafeína.

    Este é meu widget atual, que mostra meu consumo total de cafeína do dia, a última bebida consumida e um botão para adicionar outra bebida ao registro. Vou aumentar o tamanho do valor total de cafeína para ser mais fácil de ler quando o widget estiver longe. Também vou ocultar o botão, já que é mais difícil de tocar à distância. Aqui está o widget de monitoramento de cafeína. Vou atualizar TotalCaffeineView, alterando seu tamanho e mostrando ou ocultando LogDrinkView na parte inferior. Vou adicionar a propriedade de ambiente LevelOfDetail à visualização. LevelOfDetail pode ter dois valores. O padrão é o nível normal de detalhe esperado dos widgets. No visionOS, os widgets são exibidos no nível padrão de detalhe quando estão a uma distância confortável. Se o widget estiver fisicamente longe o suficiente, o nível de detalhe muda para simplificado, proporcionando uma representação mais enxuta e fácil de visualizar. Vou adicionar a condicional a LogDrinkView para que seja exibida apenas se LevelOfDetail for o padrão. Agora preciso atualizar a quantidade de cafeína.

    Na visualização do total de cafeína, exibo o nome e a quantidade total de cafeína formatada. Vou adicionar a variável de ambiente LevelOfDetail à visualização. Para aumentar, vou alterar condicionalmente a fonte da quantidade de cafeína de "title" para "large title", com base no nível de detalhe.

    Agora, sempre que estiver a uma distância suficiente, o widget fará a transição para uma versão mais simples e fácil de visualizar. Como as mudanças na linha do tempo, as alterações no nível de detalhe do widget são animadas. Para saber quando personalizar seu estilo espacial, recomendações de nível de detalhes e outras dicas para levar os widgets para essa nova plataforma, confira "Criar widgets para visionOS". Mudando de direção, agora widgets e Atividades ao Vivo estão pegando a estrada com o CarPlay. No CarPlay Ultra, os widgets aparecem em uma ou mais pilhas à esquerda do painel. E, no iOS 26, esse recurso está disponível em todos os carros com CarPlay. Widgets podem ser configurados no app Ajustes do CarPlay. No CarPlay, informações rápidas de visualizar, tipografia grande w legibilidade são essenciais para tornar o widget fácil de ler na tela do carro. Para tanto, o CarPlay renderiza widgets no estilo StandBy, utilizando a família systemSmall em fullColor, com o fundo do widget removido. Os widgets aceitam interações por toque, e você pode usar o simulador do CarPlay disponível no site do desenvolvedor para testar o widget. Tenha mais dicas sobre como adaptar o widget para uma apresentação StandBy em "Trazer os widgets para novos lugares" da WWDC 23. As Atividades ao Vivo também podem ser exibidas na tela de Início no CarPlay. As visualizações à esquerda e à direita na Dynamic Island das Atividades ao Vivo serão exibidas. Aqui está a Atividade ao Vivo de monitoramento do pedido de café exibida no CarPlay. É um bom começo. Mas com apenas um pouco de mais de programação, posso melhorar. Este é o código da Atividade ao Vivo. São exibidas as visualizações à esquerda e à direita. Para personalizar essa Atividade ao Vivo para o CarPlay, vou adicionar o modificador supplementalActivityFamilies, aplicando "small" como argumento na ActivityConfiguration. Agora, em vez de usar as visualizações à esquerda e à direita, o CarPlay exibirá ActivityView, a mesma usada na tela Bloqueada do iPhone. Isso funciona bem em algumas Atividades ao Vivo, mas, a minha está um pouco apertado, com parte do conteúdo cortado. Felizmente, posso personalizar ainda mais.

    Esta está minha ActivityView. Vou adicionar a variável de ambiente activityFamily à visualização. Agora, posso exibir conteúdos diferentes ou ajustar o layout no corpo da visualização para oferecer uma ótima experiência. Quando a activityFamily for "small", a visualização do pedido será otimizada para um layout menor. Caso contrário, a visualização de pedido padrão será exibida. Com um pouco de código extra, minha Atividade ao Vivo ficou ótima no CarPlay. Agora posso saber rapidamente quanto tempo falta para meu pedido ficar pronto. Ao adotar a supplementalActivityFamily, também melhorei muito a aparência da Atividade ao Vivo em um Apple Watch emparelhado. Isso vai automaticamente para app para iPhone, um app separado para watchOS não é necessário. Para saber como fazer sua Atividade ao Viva ficar melhor no Conjunto Inteligente do watchOS, confira "Criar Atividades ao Vivo para o Apple Watch". E confira "Aprimorar seu app para o CarPlay" para saber como acelerar os widgets no CarPlay. O CarPlay não é a única novidade das Atividades ao Vivo. As Atividades ao Vivo de um iPhone emparelhado aparecem no macOS Tahoe. Como na Dynamic Island do iPhone, a Atividade ao Vivo de pedido de café exibe as visualizações à esquerda e à direita na barra de menus. Selecionar opção Atividade ao Vivo exibe a apresentação na tela Bloqueada do iPhone. Clicar na apresentação na tela Bloqueada inicia o app associado, graças ao Espelhamento do iPhone. As Atividades ao Vivo no macOS podem ser fornecidas pelo iPhone com iOS 18 e posterior. Você não precisa alterar o código. Como os widgets do iPhone no macOS, elas suportam interação e links profundos. Agora vou mostrar os novos locais dos controles no macOS e watchOS. No macOS, os controles são fornecidos por apps do Mac, sejam eles criados com o SDK Catalyst do macOS ou por apps para iOS executados em computadores Mac com chip Apple Silicon. Controles podem ser adicionados na Central de Controle. As mesmas apresentações pequena, média e grande do iOS podem ser configuradas no macOS. E os controles podem ser colocados na barra de menus. Agora que adicionei um controle de monitoramento de café ao app no macOS, posso atualizar o registro de café na barra de menus. No watchOS 26, os controles podem aparecer em três locais. Eles podem ser configurados na Central de Controle, acessível pelo botão lateral. Podem ser executados ao pressionar o botão de Ação no Apple Watch Ultra. E podem ser configurados no Conjunto Inteligente, onde aparecem ao lado de outros widgets que exibem o símbolo, o título e o valor do controle. Os controles estão disponíveis em um app para watchOS ou iPhone em um dispositivo emparelhado. Para obter um guia completo sobre a criação de controles, confira "Estender os controles do app em todo o sistema" da WWDC24. Vou mostrar widgets de relevância no Conjunto Inteligente no watchOS 26. Adicionei um widget ao app de cafeína no watchOS para acompanhar quando minhas cafeterias favoritas têm happy hours pela metade do preço. Há duas coisas que gostaria de melhorar no widget. Primeiro, como estou acompanhando os happy hours das cafeterias, eles podem se sobrepor, deixando o conteúdo do widget no Conjunto Inteligente apertado. Segundo, os happy hours tendem a acontecer no mesmo horário. Então, no resto do dia, meu widget não é muito útil. Quero que o widget de happy hours só apareça no Conjunto Inteligente quando for relevante e mostre informações detalhadas para cada happy hour ativo. Com os widgets relevantes no watchOS 26, posso fazer isso. Vou mostrar como posso configurar os happy hours como um widget relevante. Para definir um widget relevante, crie um tipo de widget e, em vez de StaticConfiguration ou AppIntentConfiguration, forneça RelevanceConfiguration. Como outras configurações, ele usa uma string "kind", um objeto "provider" e um closure para transformar a entrada personalizada em uma visualização SwiftUI. O tipo de provedor é um RelevanceEntriesProvider. Os métodos "placeholder" e "relevance" são semelhantes a TimelineEntriesProvider. Em "placeholder", posso retornar apenas "Entry" para exibir enquanto o conteúdo está sendo preparado. Em "relevance", primeiro busco uma coleção de objetos de configuração que defini.

    No widget de happy hour, uma configuração é relevante entre o horário de início e término do happy hour. Vou definir o atributo "relevance" com esse contexto usando o intervalo de datas para cada happy hour. E implementar o método "entry". Diferentemente do widget Linha do tempo, um RelevanceEntriesProvider fornece uma entrada para uma configuração. Tenho os dados necessários para essa entrada na configuração, incluindo os dados da loja e o período do happy hour, para criá-la imediatamente. Se precisar de mais dados ou ativos, posso buscá-los aqui, já que o método é marcado como assíncrono. Depois de configurar o widget de relevância, o widget de happy hours só é exibido no Conjunto Inteligente quando é relevante. E, se houver várias configurações relevantes ao mesmo tempo, poderei abrir várias instâncias do meu widget no Conjunto Inteligente. Widgets de relevância são um novo recurso poderoso no watchOS 26, permitindo conectar o conteúdo do widget a sua relevância. Widgets são uma ótima adição por si só ou junto com widgets baseados na Linha do tempo. Para saber mais sobre widgets de relevância, confira "Novidades do watchOS 26" com Anne. Há muito mais lugares e plataformas onde os widgets podem aparecer, e quero manter os widgets sempre atualizados onde quer que estejam. Adicionei um servidor para manter os dados do registro de cafeína sincronizados nos dispositivos. Vou abordar quais opções estão disponíveis para atualizar o widget, começando com recargas programadas do widget. Neste diagrama, à esquerda, está o pacote de apps, que contém o app e a extensão de widget. Do lado direito, há uma caixa representando o WidgetKit. Quando o widget é configurado no dispositivo, como na tela de início do iPhone ou em um mostrador, o WidgetKit solicita uma linha do tempo da extensão do widget. A extensão responde com uma linha do tempo do widget, que inclui TimelineReloadPolicy. O WidgetKit usa isso para determinar o próximo momento apropriado para recarregar o widget. Usar TimelineReloadPolicy é uma ótima opção para widgets que precisam ser atualizados regularmente, como um widget com o horário de funcionamento de uma cafeteria, um de clima ou um de ações. O sistema gerencia a recarga programada da linha do tempo para manter o desempenho e a duração da bateria.

    A API WidgetCenter é outra opção disponível para apps. No app, se ocorrer alterações de dados a serem refletidas no widget, o método reloadAllTimelines ou reloadTimelines(ofKind:) do WidgetCenter pode ser chamado. Isso informa ao WidgetKit que o conteúdo do widget está desatualizado e precisa ser recarregado. O WidgetKit então solicita uma linha do tempo da extensão do widget para atualizá-lo. É uma ótima opção caso o conteúdo do widget mude no app exemplo: atualizar um registro de cafeína, modificar uma nota ou marcar um lembrete como concluído. Como o app está em execução quando essa API é chamada, o sistema não gerencia essa solicitação. Mas o que acontece se uma alteração de dados ocorrer no servidor ou em outro dispositivo? É aqui que entram as atualizações push de widgets. Um servidor que monitora alterações de dados envia uma notificação por push para APNs, que informam ao WidgetKit para recarregar os widgets do app. E, como outras atualizações, o WidgetKit solicita uma linha do tempo atualizada do widget. Atualizações por push em widgets são ótimas quando os dados podem mudar fora do dispositivo. Como TimelineReloadPolicy, atualizações de notificações por push também são gerenciadas para manter o desempenho e a duração da bateria. Com essa capacidade, os widgets agora têm um pacote de opções de recarga para lidar com diversas situações. Elas não são mutuamente exclusivas. Alguns widgets podem usar duas ou até mesmo todas as três opções. Com as atualizações push, o registro de cafeína no widget é atualizado nos dispositivos ao registrar uma atualização no app para iPad, no widget do Vision Pro ou na barra de menus do macOS. Vou mostrar como adicionar isso ao widget. Vou criar um WidgetPushHandler e adicioná-lo à configuração do widget, adicionar a permissão de notificação por push à extensão e construir uma solicitação de atualização push. Vou criar uma "struct" que esteja em conformidade com o protocolo WidgetPushHandler. Esse tipo é como notificamos quando o token de push muda ou quando o conjunto de widgets configurados é alterado. Use o método pushTokenDidChange como uma oportunidade para enviar o token de push e os dados do widget para o servidor. Agora, preciso atualizar a configuração do widget. Aqui está a configuração do widget de monitoramento de cafeína. Vou adicionar o modificador pushHandler ao widget para registrar seu suporte a notificações por push. Nesse modificador, passo o tipo do pushHandler do widget que implementei.

    Finalmente, no Xcode, irei até a aba Assinatura e Capacidades da extensão do widget. Vou adicionar a permissão de notificação por push para ela se comunicar com APNs. Agora que o configurei as atualizações push do widget, vou mostrar como enviar uma notificação por push de atualização de widget. Para atualizar o widget via notificação por push, envie uma solicitação HTTPS POST para o servidor de Push da Apple. Use o token de push do widget fornecido no WidgetPushHandler na última parte do caminho da solicitação. Nos cabeçalhos, use o tipo de push APNs para widgets e defina o cabeçalho do tópico APNs usando o ID de pacote do app, com o sufixo .push-type.widgets. No corpo da solicitação no dicionário aps, defina o valor da chave "content-changed" como true. Para saber sobre as notificações por push, confira "Guia introdutório das notificações por push". E confira o "Conhecer o console de notificações por push" para saber como testar as solicitações de notificações por push. As atualizações push de widgets mantêm o conteúdo do widget atualizado, mas são realizadas de modo oportunista e não substituem outras experiências de notificação. Se a atualização for urgente ou importante, forneça uma Notificação ao Usuário. Se atualizações ocorrerem regularmente durante um período, como pedido de bebida, atualização de placares ou informações de voo, use a Atividade ao Vivo. Use atualizações push de widgets para atualizar o conteúdo do widget. As atualizações push estão disponíveis nas plataformas com suporte a widgets. Ao envia uma notificação por push de widget, os widgets habilitados para push no dispositivo são atualizados. As recargas de widgets são limitadas por um orçamento. Tente manter as atualizações push limitadas, como ao restringir sua frequência no servidor. E, no desenvolvimento e teste, use o modo de desenvolvedor do WidgetKit em Ajustes para ignorar os orçamentos de push e recarga do app. Foi bastante informação. Reserve um tempo para explorar essas novas plataformas para widgets. Confira alguns dos vídeos mencionados para se inspirar. Certifique-se de que os widgets tenham um ótimo visual nos novos layouts do iOS e macOS. E, se os dados dos widgets puderem ser atualizados por fontes externas ou outros dispositivos, adicione notificações por push para mantê-los atualizados. As novas capacidades e lugares dos widgets são empolgantes. Mal posso esperar para levar seus widgets para onde eu for. Agradeço a participação.

    • 2:44 - Observe .widgetRenderingMode

      struct MostFrequentBeverageWidgetView: View {
          @Environment(\.widgetRenderingMode) var renderingMode
          
          var entry: Entry
          
          var body: some View {
              ZStack {
                  if renderingMode == .fullColor {
                      Image(entry.beverageImage)
                          .resizable()
                          .aspectRatio(contentMode: .fill)
                  
                      LinearGradient(gradient: Gradient(colors: [.clear, .clear, .black.opacity(0.8)]), startPoint: .top, endPoint: .bottom)
                  }
                  
                  VStack {
                      if renderingMode == .accented {
                          Image(entry.beverageImage)
                              .resizable()
                              .widgetAccentedRenderingMode(.desaturated)
                              .aspectRatio(contentMode: .fill)
                      }
                      
                      BeverageTextView()
                  }
              }
          }
      }
    • 6:08 - visionOS Widget Configuration

      struct CaffeineTrackerWidget: Widget {
          var body: some WidgetConfiguration {
              StaticConfiguration(
                  kind: "BaristaWidget",
                  provider: Provider()
              ) { entry in
                  CaffeineTrackerWidgetView(entry: entry)
              }
              .configurationDisplayName("Caffeine Tracker")
              .description("A widget tracking your caffeine intake during the day.")
              .supportedMountingStyles([.elevated])
              .widgetTexture(.paper)
              .supportedFamilies([.systemExtraLargePortrait])
          }
      }
    • 8:56 - LevelOfDetail - CaffeineTrackerWidgetView

      struct CaffeineTrackerWidgetView : View {
          @Environment(\.levelOfDetail) var levelOfDetail
          
          var entry: CaffeineLogEntry
      
          var body: some View {
              VStack(alignment: .leading) {
                  TotalCaffeineView(entry: entry)
      
                  if let log = entry.log {
                      LastDrinkView(log: log)
                  }
      
                  if levelOfDetail == .default {
                      LogDrinkView()
                  }
              }
          }
      }
    • 9:46 - LevelOfDetail - TotalCaffeineView

      struct TotalCaffeineView: View {
          @Environment(\.levelOfDetail) var levelOfDetail
          
          let entry: CaffeineLogEntry
      
          var body: some View {
              VStack {
                  Text("Total Caffeine")
                      .font(.caption)
      
                  Text(totalCaffeine.formatted())
                      .font(caffeineFont)
              }
          }
          
          var caffeineFont: Font {
              if levelOfDetail == .simplified {
                  .largeTitle
              } else {
                  .title
              }
          }
          
          var totalCaffeine: Measurement<UnitMass> {
              entry.totalCaffeine
          }
      }
    • 11:49 - Add .supplementalActivityFamilies

      struct ShopOrderLiveActivity: Widget {
          var body: some WidgetConfiguration {
              ActivityConfiguration(for: Attributes.self) { context in
                  ActivityView(context: context)
              } dynamicIsland: { context in
                  DynamicIsland {
                      DynamicIslandExpandedRegion(.leading) {
                          ExpandedView(context: context)
                      }
                  } compactLeading: {
                      LeadingView(context: context)
                  } compactTrailing: {
                      TrailingView(context: context)
                  } minimal: {
                      MinimalView(context: context)
                  }
              }
              .supplementalActivityFamilies([.small])
          }
      }
    • 12:27 - Add .activityFamily

      struct ActivityView: View {
          @Environment(\.activityFamily) var activityFamily
          var context: ActivityViewContext<Attributes>
          
          var body: some View {
              switch activityFamily {
              case .small:
                  ShopOrderSmallView(context: context)
              default:
                  ShopOrderView(context: context)
              }
          }
      }
    • 16:20 - Define relevance widget with RelevanceConfiguration

      struct HappyHourRelevanceWidget: Widget {
          var body: some WidgetConfiguration {
              RelevanceConfiguration(
                  kind: "HappyHour",
                  provider: Provider()
              ) { entry in
                  WidgetView(entry: entry)
              }
          }
      }
    • 16:41 - Implement RelevanceEntriesProvider

      struct Provider: RelevanceEntriesProvider {
          func placeholder(context: Context) -> Entry {
              Entry()
          }
          
          func relevance() async -> WidgetRelevance<Configuration> {
              let configs = await fetchConfigs()
              var attributes: [WidgetRelevanceAttribute<Configuration>] = []
              
              for config in configs {
                  attributes.append(WidgetRelevanceAttribute(
                      configuration: config,
                      context: .date(interval: config.interval, kind: .default)))
              }
              
              return WidgetRelevance(attributes)
          }
          
          func entry(configuration: Configuration,
                     context: RelevanceEntriesProviderContext) async throws -> Entry {
              Entry(shop: configuration.shop, timeRange: configuration.timeRange)
          }
      }
    • 21:13 - Handle push token and widget configuration changes

      struct CaffeineTrackerPushHandler: WidgetPushHandler {
          func pushTokenDidChange(_ pushInfo: WidgetPushInfo, widgets: [WidgetInfo]) {
              // Send push token and subscription info to server
          }
      }
    • 21:30 - Add pushHandler to WidgetConfiguration

      struct CaffeineTrackerWidget: Widget {
          var body: some WidgetConfiguration {
              StaticConfiguration(
                  kind: Constants.widgetKind,
                  provider: Provider()
              ) { entry in
                  CaffeineTrackerWidgetView(entry: entry)
              }
              .configurationDisplayName("Caffeine Tracker")
              .pushHandler(CaffeineTrackerPushHandler.self)
          }
      }
    • 22:29 - Push Notification Request Body

      {
          "aps": {
              "content-changed": true
          }
      }
    • 0:00 - Introdução
    • Saiba mais sobre as atualizações do WidgetKit, incluindo novas formas de incorporar o app ao sistema, mostrar conteúdo relevante no Conjunto Inteligente e manter seu app atualizado.

    • 1:03 - Widgets em novos lugares
    • Os widgets têm novas opções de estilo e estão disponíveis em novos lugares. Confira dicas para deixar seus widgets ainda mais bonitos usando o modo de renderização com destaque. Os widgets estão disponíveis em mais lugares, incluindo o visionOS 26 e o CarPlay. No visionOS 26, eles podem ser adicionados aos ambientes e fixados a superfícies. Também podem ser personalizados para incluir compatibilidade com diferentes estilos de montagem, texturas e níveis de detalhes com base na proximidade. O CarPlay e o macOS 26 agora são compatíveis com Atividades ao Vivo. Os controles estão disponíveis no macOS Tahoe e no watchOS 26.

    • 15:31 - Widgets de relevância
    • Os widgets mais relevantes aparecem no Conjunto Inteligente do watchOS 26 com base na rotina e na localização das pessoas e muito mais. Eles só são exibidos no Conjunto Inteligente quando são relevantes, e várias instâncias podem aparecer ao mesmo tempo, como no caso de eventos de calendário sobrepostos ou happy hours. Se quiser usar esse recurso, especifique em que situações seus widgets são mais relevantes, como em um determinado horário ou tipo de local.

    • 18:12 - Atualizações de widgets por push
    • Agora os widgets de todas as plataformas do WidgetKit podem ser atualizados com atualizações por push no APNS. Existem várias ferramentas para manter os widgets atualizados, e a melhor opção para cada caso depende de como os dados do seu widget são atualizados. É útil ter cronogramas para atualizar os dados regularmente. Para as alterações impulsionadas pela interação com o app, é preciso chamar o método reloadAllTimelines. Para sincronização entre dispositivos ou alterações de dados externos, como de um servidor, use atualizações por push. Elas ajudam a manter os widgets mais atualizados, mas não substituem outras experiências de notificação. Considere se uma Notificação de Usuário, uma Atividade ao Vivo ou um widget é melhor para cada caso de uso.

Developer Footer

  • Vídeos
  • WWDC25
  • Novidades dos widgets
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines