Criar widgets controlados por PWA
Vários sistemas operacionais têm painéis de widgets que permitem aos usuários ler conteúdo e executar tarefas. Exemplos disso incluem widgets da Tela Inicial do Android, widgets do Painel macOS e Painel Hoje, a Barra de Toque da Apple, Cartões Diários samsung, widgets de Mini Aplicativo e companheiros de aplicativo watch inteligentes.
No Windows 11, os widgets aparecem no Widgets Board, que você abre do lado esquerdo da barra de tarefas:
Em Windows 11, pwas (Aplicativos Web progressivos) podem definir widgets, atualizá-los e manipular interações do usuário dentro deles.
Requer a criação de um widget personalizado para o PWA
Um PWA existente não pode simplesmente ser colocado no widget dashboard como está, como você pode com a barra lateral do Microsoft Edge. Em vez disso, você precisa criar uma experiência de widget personalizada apropriada para o host widget, que atualmente é o Windows 11 Widgets Board. (Pode haver outros hosts de widget no futuro.) O Windows 11 Widgets Board requer que os widgets sejam criados usando modelos de Cartão Adaptável em vez de HTML e JavaScript, portanto, o widget precisa ser projetado separadamente do restante da interface do usuário do aplicativo.
Veja também:
Para criar um widget controlado por PWA e entregá-lo por meio da loja da Microsoft, nenhum código C++/C# é necessário. Depois de produzir o widget e instalar e executar com êxito o widget de um ponto de extremidade público, você pode empacotar o aplicativo usando PWABuilder.com e enviar o aplicativo para a loja da Microsoft sem exigir nenhum código adicional. O suporte do PWA ao widget deve ser instalável a partir de um ponto de extremidade público, pois PWABuilder.com não dá suporte a aplicativos de empacotamento de localhost.
Veja também:
Instalar o WinAppSDK e habilitar o Modo de Desenvolvedor
Para habilitar o desenvolvimento e o teste de widgets em seu computador local:
Instale o WinAppSDK 1.2.
Habilitar o modo de desenvolvedor no Windows 11:
Abra Configurações.
Na caixa de texto Localizar uma configuração, insira e clique em
developer
Usar recursos do desenvolvedor.Habilitar o modo de desenvolvedor:
Definir widgets
Os widgets são definidos no arquivo de manifesto PWA usando o membro do widgets
manifesto. Esse membro de manifesto é uma matriz que pode conter várias definições de widget.
{
"name": "PWAmp",
"description": "A music player app",
"icons": [
{ "src": "img/icon-96.png", "sizes": "96x96" },
{ "src": "img/icon-128.png", "sizes": "128x128" },
{ "src": "img/icon-256.png", "sizes": "256x256" },
{ "src": "img/icon-512.png", "sizes": "512x512" }
],
"widgets": [
/* widget definitions go here */
]
}
Cada entrada na widgets
matriz contém vários campos, conforme mostrado abaixo:
{
...
"widgets": [
{
"name": "PWAmp mini player",
"description": "widget to control the PWAmp music player",
"tag": "pwamp",
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player-template.json",
"data": "widgets/mini-player-data.json",
"type": "application/json",
"screenshots": [
{
"src": "./screenshot-widget.png",
"sizes": "600x400",
"label": "The PWAmp mini-player widget"
}
],
"icons": [
{
"src": "./favicon-16.png",
"sizes": "16x16"
}
],
"auth": false,
"update": 86400
}
]
}
No exemplo acima, um aplicativo de music player define um widget de mini player. Uma definição de widget no manifesto do aplicativo Web tem os seguintes campos necessários e opcionais:
Campo | Descrição | Obrigatório |
---|---|---|
name |
O título do widget, apresentado aos usuários. | Sim |
short_name |
Uma versão curta alternativa do nome. | Não |
description |
Uma descrição do que o widget faz. | Sim |
icons |
Uma matriz de ícones a ser usada para o widget. Se estiver ausente, o membro do icons manifesto será usado em vez disso. Ícones maiores que 1024x1024 são ignorados. |
Não |
screenshots |
Uma matriz de capturas de tela que mostram como é o widget. Análogo ao membro do screenshot manifesto. O platform campo de um item de captura de tela dá suporte aos Windows valores e any . Imagens maiores que 1024x1024 pixels são ignoradas. Para obter requisitos de captura de tela específicos do Windows 11 Widgets Board, consulte Requisitos de imagem de captura de tela em Integrar com o seletor de widget. |
Sim |
tag |
Uma cadeia de caracteres usada para referenciar o widget no trabalho de serviço PWA. | Sim |
template |
O modelo a ser usado para exibir o widget nos widgets do sistema operacional dashboard. Observação: essa propriedade é atualmente apenas informativa e não usada. Confira ms_ac_template abaixo. |
Não |
ms_ac_template |
A URL do modelo personalizado de Cartões Adaptáveis a ser usado para exibir o widget nos widgets do sistema operacional dashboard. Confira Definir um modelo de widget abaixo. | Sim |
data |
A URL em que os dados para preencher o modelo podem ser encontrados. Se estiver presente, essa URL será necessária para retornar JSON válido. | Não |
type |
O tipo MIME para os dados de widget. | Não |
auth |
Um booliano indicando se o widget requer autenticação. | Não |
update |
A frequência, em segundos, em que o widget será atualizado. O código em seu trabalho de serviço deve executar a atualização; o widget não é atualizado automaticamente. Consulte Acessar instâncias de widget no runtime. | Não |
multiple |
Um booliano que indica se deve permitir várias instâncias do widget. O padrão é true |
Não |
Definir um modelo de widget
Para tornar os widgets fáceis de criar e se adaptar a vários painéis de widgets do sistema operacional, eles são exibidos usando modelos. Existem dois tipos de modelos:
- Modelos genéricos, definidos por seus nomes usando o
template
campo. - Modelos personalizados, definidos por suas URLs usando um campo de modelo personalizado.
Por enquanto, há suporte apenas para modelos de Cartões Adaptáveis personalizados. Cartões Adaptáveis é um formato de troca de cartão aberto que pode ser usado para trocar conteúdo da interface do usuário de maneira comum e consistente. Confira Visão geral de cartões adaptáveis.
Para definir um modelo personalizado de Cartões Adaptáveis no Windows 11, use o ms_ac_template
campo na definição de widget que está no manifesto do aplicativo Web. Embora não seja template
usado atualmente, é um campo obrigatório.
{
...
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player.json",
...
}
O ms_ac_template
valor de campo deve ser uma URL válida de um arquivo de modelo.
Aqui está um exemplo de um modelo de Cartões Adaptáveis:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"text": "Now playing...",
"horizontalAlignment": "Center"
},
{
"type": "TextBlock",
"spacing": "Large",
"weight": "Bolder",
"horizontalAlignment": "Center",
"text": "${song}, by ${artist}",
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
Para saber mais, confira Templating cartões adaptáveis.
Em seguida, você precisa associar dados ao modelo.
Associar dados ao modelo
O modelo declara a interface do usuário de um widget. Em seguida, os dados preenchem essa interface do usuário.
Para associar dados ao modelo, use o data
campo em sua definição de widget. Esse campo deve ser definido como uma URL que retorna dados JSON válidos.
O modelo definido na seção anterior contém duas variáveis: song
e artist
, que estão incluídas na sintaxe de expressão de associação: ${}
. Os dados retornados pela data
URL em sua definição de widget devem conter valores para essas variáveis.
Aqui está um exemplo do que a data
URL pode retornar:
{
"song": "I Will Always Love You",
"artist": "Whitney Houston"
}
Definir ações de widget
Se você quiser que seu widget permita que os usuários executem tarefas, defina um modelo que dê suporte a ações.
Aqui está um exemplo de uma ação definida em um modelo personalizado de Cartões Adaptáveis:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"text": "Now playing...",
"horizontalAlignment": "Center"
},
{
"type": "TextBlock",
"spacing": "Large",
"weight": "Bolder",
"horizontalAlignment": "Center",
"text": "${song}, by ${artist}",
}
],
"actions": [
{
"type": "Action.Execute",
"title": "Previous",
"verb": "previous-song"
},
{
"type": "Action.Execute",
"title": "Next",
"verb": "next-song"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
Observe o verb
campo no modelo JSON acima. Ele será usado ao lidar com ações de widget em seu código de trabalho de serviço. Consulte Manipular ações de widget.
Acessar instâncias de widget no runtime
Você pode acessar widgets e atualizá-los do código de trabalho do serviço PWA. Acessar widgets no runtime é útil em casos como:
- Renderizando widgets na instalação.
- Atualizando widgets em atualizações de trabalho de serviço.
- Manipulando ações do usuário em widgets.
- Atualizando widgets quando o aplicativo é alterado.
Os funcionários do serviço têm acesso ao objeto e a self.widgets
vários eventos de widget que, juntos, constituem uma API que você usa para reagir a alterações e acessar widgets no runtime.
As seções a seguir fornecem exemplos de código. Para obter uma referência da API, consulte a referência da API do trabalho de serviço.
Renderizar widgets na instalação
Quando um PWA é instalado, os widgets que o aplicativo define em seu manifesto são adicionados aos widgets dashboard mas ainda não instalados. Um widget só é instalado quando o usuário opta por adicionar o widget do dashboard.
Quando um widget é instalado, ele não é renderizado automaticamente usando os ms_ac_template
campos e data
da definição de widget.
Para renderizar o widget, ouça o widgetinstall
evento em seu trabalho de serviço e atualize o widget usando a widgets.updateByTag
função:
// Listen to the widgetinstall event.
self.addEventListener("widgetinstall", event => {
// The widget just got installed, render it using renderWidget.
// Pass the event.widget object to the function.
event.waitUntil(renderWidget(event.widget));
});
async function renderWidget(widget) {
// Get the template and data URLs from the widget definition.
const templateUrl = widget.definition.msAcTemplate;
const dataUrl = widget.definition.data;
// Fetch the template text and data.
const template = await (await fetch(templateUrl)).text();
const data = await (await fetch(dataUrl)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
Atualizar widgets em atualizações de trabalho de serviço
Quando o código do trabalho de serviço é alterado em um PWA, o navegador detecta essa alteração, instala o novo trabalho de serviço e, em seguida, o ativa.
Quando isso acontece, é importante atualizar todas as instâncias de widget que já estejam em execução. Os widgets podem ter sido instalados antes do evento de trabalho activate
do serviço ser emitido. Para evitar exibir widgets vazios, atualize seus widgets quando o activate
evento ocorrer
// Update the widgets to their initial states
// when the service worker is activated.
self.addEventListener("activate", event => {
event.waitUntil(updateWidgets());
});
async function updateWidgets() {
// Get the widget that match the tag defined in the web app manifest.
const widget = await self.widgets.getByTag("pwamp");
if (!widget) {
return;
}
// Using the widget definition, get the template and data.
const template = await (await fetch(widget.definition.msAcTemplate)).text();
const data = await (await fetch(widget.definition.data)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
Manipular ações de widget
Se o modelo de widget contiver ações, os usuários poderão executar essas ações clicando em botões no widget renderizado. Para obter informações sobre como definir ações em um modelo, consulte Definir ações de widget.
Quando um usuário executa uma ação de widget, um widgetclick
evento é disparado no trabalho de serviço PWA. Para lidar com a ação do usuário, ouça o evento:
self.addEventListener('widgetclick', (event) => {
switch (event.action) {
case 'previous-song':
// Application logic to play the previous song...
break;
case 'next-song':
// Application logic to play the next song...
break;
}
});
Para brevidade, o código do aplicativo real não é mostrado no snippet de código acima. Quando as previous-song
ações ou next-song
são recebidas, uma mensagem provavelmente precisaria ser enviada para o aplicativo usando Client.postMessage para informar ao aplicativo que ele deve começar a reproduzir as músicas anteriores ou próximas.
Observe que a action
propriedade do widgetEvent
objeto passada para o ouvinte de eventos acima corresponde à cadeia de caracteres definida no action.verb
campo do modelo de widget.
Para obter mais informações sobre o widgetclick
evento e quais informações você pode acessar dele, confira a referência da API do Trabalho de Serviço abaixo.
Atualizar widgets em alterações de aplicativo
Nas seções anteriores, você aprendeu a atualizar widgets quando ocorreram eventos de widget específicos, ações de widget e atualizações de trabalho de serviço. Também pode ser útil atualizar widgets quando algo acontece no aplicativo ou quando ocorre uma notificação por push ou periodicamente.
Nesta seção, você aprenderá a usar a API de Sincronização periódica em segundo plano para atualizar widgets periodicamente. Para obter mais informações sobre a API de Sincronização periódica em segundo plano, consulte Usar a API de Sincronização de Plano de Fundo Periódico para obter conteúdo recente regularmente.
No snippet de código a seguir, um ouvinte de eventos é usado para reagir a vários eventos de ciclo de vida do widget do aplicativo. Quando uma instalação de widget é detectada, uma sincronização periódica é registrada e quando uma remoção de widget é detectada, a sincronização periódica não é registrada.
Quando ocorrem eventos de sincronização periódica, as instâncias de widget são atualizadas usando a widgets.updateByTag
função.
self.addEventListener("widgetinstall", event => {
event.waitUntil(onWidgetInstall(event.widget));
});
self.addEventListener("widgetuninstall", event => {
event.waitUntil(onWidgetUninstall(event.widget));
});
async function onWidgetInstall(widget) {
// Register a periodic sync, if this wasn't done already.
// We use the same tag for the sync registration and the widget to
// avoid registering several periodic syncs for the same widget.
const tags = await self.registration.periodicSync.getTags();
if (!tags.includes(widget.definition.tag)) {
await self.registration.periodicSync.register(widget.definition.tag, {
minInterval: widget.definition.update
});
}
// And also update the instance.
await updateWidget(widget);
}
async function onWidgetUninstall(widget) {
// On uninstall, unregister the periodic sync.
// If this was the last widget instance, then unregister the periodic sync.
if (widget.instances.length === 1 && "update" in widget.definition) {
await self.registration.periodicSync.unregister(widget.definition.tag);
}
}
// Listen to periodicsync events to update all widget instances
// periodically.
self.addEventListener("periodicsync", async event => {
const widget = await self.widgets.getByTag(event.tag);
if (widget && "update" in widget.definition) {
event.waitUntil(updateWidget(widget));
}
});
async function updateWidget(widget) {
// Get the template and data URLs from the widget definition.
const templateUrl = widget.definition.msAcTemplate;
const dataUrl = widget.definition.data;
// Fetch the template text and data.
const template = await (await fetch(templateUrl)).text();
const data = await (await fetch(dataUrl)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
Aplicativo de demonstração
PWAmp é um aplicativo de demonstração PWA do player de música que define um widget. O widget PWAmp permite que os usuários visualizem a música atual e toquem as músicas anteriores ou próximas.
Se ainda não terminar, instale o WinAppSDK 1.2 e habilite o Modo de Desenvolvedor no Windows 11.
Acesse PWAmp e instale o aplicativo no Windows 11.
Abra o Windows 11 Widgets Board pressionando a tecla do logotipo do Windows + W.
Clique em Adicionar widgets para abrir a tela de configurações de widgets , role até o widget do mini player PWAmp e adicione-o.
Feche a tela de configurações de widgets . O mini player PWAmp agora é exibido no Widgets Board.
O widget PWAmp exibe a música e os botões atuais para reproduzir a música anterior ou a próxima.
Referência da API do Trabalho de Serviço
O objeto global do trabalho de serviço (ou ServiceWorkerGlobalScope) contém um widgets
atributo que expõe os seguintes métodos baseados em promessa:
Método | Descrição | Parâmetros | Valor de retorno |
---|---|---|---|
getByTag(tag) |
Obter um widget por marca | A marca widget | Uma Promessa que resolve para o objeto widget que corresponde à marca ou undefined . |
getByInstanceId(id) |
Obter um widget por ID da instância | A ID da instância do widget | Uma Promessa que resolve para o objeto widget correspondente ou undefined . |
getByHostId(id) |
Obter widgets por ID do host | A ID do host | Uma matriz de objetos widget encontrados nesse host. |
matchAll(options) |
Obter widgets por meio de opções correspondentes | Um objeto widgetOptions | Uma Promessa que se resolve para uma matriz de objetos widget que correspondem aos options critérios. |
updateByInstanceId(id, payload) |
Atualizar um widget por ID da instância | A ID da instância e um objeto widgetPayload | Uma Promessa que resolve para undefined ou Error . |
updateByTag(tag, payload) |
Atualizar um widget por marca | A marca do widget e um objeto widgetPayload | Uma Promessa que resolve para undefined ou Error . |
O objeto global do service worker também define os seguintes eventos:
widgetinstall
: disparado quando o host de widget está instalando um widget.widgetuninstall
: disparado quando o host widget está desinstalando um widget.widgetresume
: disparado quando o host de widget retoma a renderização de widgets instalados, o que pode acontecer depois que o host suspendeu a renderização de widgets para preservar recursos.widgetclick
: disparado quando o usuário executa uma das ações de widget.
Para obter mais informações sobre os objetos fornecidos com esses eventos, consulte o objeto widgetEvent e as definições de objeto widgetClickEvent abaixo.
objeto widget
Cada widget é representado como um widget
objeto, que contém as seguintes propriedades:
installable
: um booliano que indica se o widget é instalável.definition
: um objeto widgetDefinition.instances
: uma matriz de objetos widgetInstance que representam o estado atual de cada instância do widget.
objeto widgetOptions
Ao usar matchAll(options)
para obter vários widgets, um widgetOptions
objeto é necessário para filtrar quais widgets retornarão. O widgetOptions
objeto contém as seguintes propriedades, todas opcionais:
installable
: um booliano que indica se os widgets retornados devem ser instalados.installed
: um booliano indicando se os widgets retornados estão instalados no host de widget.tag
: uma cadeia de caracteres usada para filtrar os widgets retornados por marca.instanceId
: uma cadeia de caracteres usada para filtrar os widgets retornados por ID da instância.hostId
: uma cadeia de caracteres usada para filtrar os widgets retornados pela ID do host do widget.
objeto widgetPayload
Ao criar ou atualizar uma instância de widget, o trabalhador do serviço deve enviar o modelo e os dados necessários para preencher o widget. O modelo e os dados são chamados de carga. O widgetPayload
objeto contém as seguintes propriedades:
template
: o modelo, como uma cadeia de caracteres, a ser usado para renderizar o widget. Este será o JSON com cadeia de caracteres de um modelo de Cartão Adaptável.data
: os dados, como uma cadeia de caracteres, a serem usados com o modelo de widget. Esses dados podem ser dados JSON em cadeia de caracteres.
objeto widgetInstance
Este objeto representa uma determinada instância de um widget em um host widget e contém as seguintes propriedades:
id
: a cadeia de caracteres GUID interna usada para fazer referência à instância.host
: um ponteiro interno para o host de widget que instalou essa instância.updated
: umDate
objeto que representa a última vez que os dados foram enviados para a instância.payload
: um objeto widgetPayload que representa a última carga enviada para esta instância.
objeto widgetDefinition
Esse objeto representa a definição original do widget, encontrado no arquivo de manifesto PWA. As propriedades desse objeto correspondem às propriedades listadas em Definir widgets, acima.
objeto widgetEvent
Esse objeto é passado como um argumento para os ouvintes de eventos de widget do trabalho de serviço do tipo widgetinstall
, widgetuninstall
e widgetresume
.
Para os widgetinstall
tipos , widgetuninstall
e widgetresume
de eventos, o widgetEvent
objeto tem as seguintes propriedades:
Propriedade | Descrição | Tipo |
---|---|---|
widget |
A instância do widget que acionou o evento. | Widget |
instanceId |
A ID da instância do widget. | String |
hostId |
A ID do host do widget. | String |
objeto widgetClickEvent
Esse objeto é passado como um argumento para os ouvintes de eventos de widget do trabalho de serviço do tipo widgetclick
. Você pode abrir a janela do aplicativo em resposta ao widgetclick
evento usando clients.openWindow()
.
O widgetClickEvent
objeto tem as seguintes propriedades:
Propriedade | Descrição | Tipo |
---|---|---|
action |
A ação que acionou o evento, conforme definido nos actions.verb campos do modelo de widget. Consulte Definir ações de widget. |
String |
widget |
A instância do widget que acionou o evento. | widgetInstance |
hostId |
A ID do host do widget. | String |
instanceId |
A ID da instância do widget. | String |