Criar widgets baseados em PWA
Vários sistemas operativos têm dashboards de widgets que permitem aos utilizadores ler conteúdos e realizar tarefas. Exemplos disto incluem widgets do Ecrã Principal do Android, dashboard do macOS e widgets de Painel de Hoje, Apple Touch Bar, Cartões Diários da Samsung, widgets de Mini-Aplicação e complementos de aplicações de relógio inteligente.
No Windows 11, os widgets são apresentados no Quadro de Widgets, que abre a partir do lado esquerdo da barra de tarefas:
No Windows 11, as Aplicações Web Progressivas (PWAs) podem definir widgets, atualizá-los e lidar com interações do utilizador dentro dos mesmos.
Requer a criação de um widget personalizado para o PWA
Um PWA existente não pode simplesmente ser colocado no dashboard do widget tal como está, como pode fazer com a Barra Lateral do Microsoft Edge. Em vez disso, tem de criar uma experiência de widget personalizada adequada para o anfitrião de widget, que atualmente é o Quadro de Widgets do Windows 11. (Poderão existir outros anfitriões widget no futuro.) O Quadro de Widgets do Windows 11 requer que os widgets sejam criados com modelos de Cartão Adaptável em vez de HTML e JavaScript, pelo que o widget tem de ser concebido separadamente do resto da IU da aplicação.
Veja também:
Para criar um widget baseado em PWA e entregá-lo através da Microsoft Store, não é necessário nenhum código C++/C#. Depois de produzir o widget e conseguir instalar e executar o widget com êxito a partir de um ponto final público, pode empacotar a aplicação com PWABuilder.com e enviar a aplicação para a Microsoft Store sem precisar de código adicional. O widget PWA que suporta o widget tem de ser instalável a partir de um ponto final público, uma vez que PWABuilder.com não suporta aplicações de embalagem do localhost.
Veja também:
Instalar o WinAppSDK e ativar o Modo de Programador
Para ativar o desenvolvimento e teste de widgets no seu computador local:
Instale o WinAppSDK 1.2.
Ativar o Modo de Programador no Windows 11:
Abra Definições.
Na caixa de texto Localizar uma definição , introduza
developer
e, em seguida, clique em Utilizar funcionalidades de programador.Ativar Modo de Programador:
Definir widgets
Os widgets são definidos no ficheiro de manifesto do PWA com o membro do widgets
manifesto. Este membro do 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, uma aplicação de leitor de música define um widget de mini player. Uma definição de widget no manifesto da aplicação Web tem os seguintes campos obrigatórios e opcionais:
Campo | Descrição | Obrigatório |
---|---|---|
name |
O título do widget, apresentado aos utilizadores. | Sim |
short_name |
Uma versão abreviada alternativa do nome. | Não |
description |
Uma descrição do que o widget faz. | Sim |
icons |
Uma matriz de ícones a utilizar para o widget. Se estiver em falta, é utilizado o membro do icons manifesto. Os ícones maiores do que 1024x1024 são ignorados. |
Não |
screenshots |
Uma matriz de capturas de ecrã que mostram o aspeto do widget. Análogo ao membro do screenshot manifesto. O platform campo de um item de captura de ecrã suporta os Windows valores e any . As imagens com mais de 1024x1024 pixels são ignoradas. Para obter os requisitos de captura de ecrã específicos do Quadro de Widgets do Windows 11, consulte Requisitos de imagem de captura de ecrã em Integrar com o seletor de widget. |
Sim |
tag |
Uma cadeia utilizada para referenciar o widget na função de trabalho do serviço PWA. | Sim |
template |
O modelo a utilizar para apresentar o widget no dashboard de widgets do sistema operativo. Nota: atualmente, esta propriedade é apenas informativa e não é utilizada. Veja ms_ac_template abaixo. |
Não |
ms_ac_template |
O URL do modelo cartões ajustáveis personalizado a utilizar para apresentar o widget no dashboard de widgets do sistema operativo. Veja Definir um modelo de widget abaixo. | Sim |
data |
O URL com o qual os dados para preencher o modelo podem ser encontrados. Se estiver presente, este URL é necessário para devolver JSON válido. | Não |
type |
O tipo de MIME para os dados do widget. | Não |
auth |
Um booleano que indica se o widget requer autenticação. | Não |
update |
A frequência, em segundos, na qual o widget será atualizado. O código na sua função de trabalho de serviço tem de efetuar a atualização; o widget não é atualizado automaticamente. Veja Access widget instances at runtime (Aceder a instâncias de widget no runtime). | Não |
multiple |
Um booleano que indica se deve permitir várias instâncias do widget. O padrão é true |
Não |
Definir um modelo de widget
Para facilitar a criação e adaptação de widgets a vários dashboards de widgets do sistema operativo, estes são apresentados através de modelos. Existem dois tipos de modelos:
- Modelos genéricos, definidos pelos respetivos nomes com o
template
campo . - Modelos personalizados, definidos pelos respetivos URLs através de um campo de modelo personalizado.
Por enquanto, só são suportados modelos de Cartões Ajustáveis personalizados. Os Cartões Ajustáveis são um formato de troca de cartões aberto que pode ser utilizado para trocar conteúdos de IU de forma comum e consistente. Veja Descrição Geral dos Cartões Ajustáveis.
Para definir um modelo de Cartões Ajustáveis personalizado no Windows 11, utilize o ms_ac_template
campo na definição de widget que está no manifesto da sua aplicação Web. Embora template
não seja atualmente utilizado, é um campo obrigatório.
{
...
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player.json",
...
}
O ms_ac_template
valor do campo deve ser um URL válido de um ficheiro de modelo.
Eis um exemplo de um modelo de Cartões Ajustá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, veja Templating de Cartões Adaptáveis.
Em seguida, tem de vincular os dados ao seu modelo.
Vincular dados ao seu modelo
O modelo declara a interface de utilizador de um widget. Em seguida, os dados preenchem esta interface de utilizador.
Para vincular dados ao modelo, utilize o data
campo na definição do widget. Este campo deve ser definido como um URL que devolve dados JSON válidos.
O modelo definido na secção anterior contém duas variáveis: song
e artist
, que estão incluídas na sintaxe da expressão de enlace: ${}
. Os dados devolvidos pelo data
URL na definição do widget devem conter valores para estas variáveis.
Eis um exemplo do que o data
URL pode devolver:
{
"song": "I Will Always Love You",
"artist": "Whitney Houston"
}
Definir ações de widget
Se quiser que o widget permita que os utilizadores executem tarefas, defina um modelo que suporte ações.
Eis um exemplo de uma ação definida num modelo de Cartões Ajustáveis personalizado:
{
"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"
}
Tenha em atenção o verb
campo no modelo JSON acima. Será utilizado ao processar ações de widget no seu código de trabalho de serviço. Veja Processar ações de widget.
Aceder a instâncias de widget no runtime
Pode aceder a widgets e atualizá-los a partir do código de trabalho do serviço PWA. Aceder a widgets no runtime é útil em casos como:
- Compor widgets na instalação.
- A atualizar widgets nas atualizações da função de trabalho de serviço.
- Processar ações do utilizador em widgets.
- A atualizar widgets quando a aplicação é alterada.
Uma função de trabalho de serviço tem acesso ao self.widgets
objeto e a vários eventos de widget que, em conjunto, constituem uma API que utiliza para reagir a alterações e aceder a widgets no runtime.
As secções seguintes fornecem exemplos de código. Para obter uma referência da API, veja a referência da API de trabalho de serviço.
Compor widgets na instalação
Quando um PWA é instalado, os widgets que a aplicação define no seu manifesto são adicionados ao dashboard de widgets, mas ainda não estão instalados. Um widget só é instalado quando o utilizador opta por adicionar o widget a partir do dashboard.
Quando um widget é instalado, não é composto automaticamente com os ms_ac_template
campos e data
da definição do widget.
Para compor o widget, ouça o widgetinstall
evento na sua função de trabalho de serviço e atualize o widget com 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 nas atualizações da função de trabalho de serviço
Quando o código da função de trabalho de serviço é alterado num PWA, o browser deteta essa alteração, instala a nova função de trabalho de serviço e, posteriormente, ativa a função de trabalho de serviço.
Quando isto acontece, é importante atualizar quaisquer instâncias de widget que possam já estar em execução. Os widgets podem ter sido instalados antes de o evento de trabalho de serviço activate
ser emitido. Para evitar apresentar widgets vazios, atualize os 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});
}
Processar ações de widget
Se o modelo de widget contiver ações, os utilizadores podem executar essas ações ao clicar em botões no widget composto. Para obter informações sobre como definir ações num modelo, veja Definir ações de widget.
Quando um utilizador executa uma ação de widget, é acionado um widgetclick
evento na função de trabalho do serviço PWA. Para processar a ação do utilizador, 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;
}
});
Por questões de brevidade, o código da aplicação real não é apresentado no fragmento de código acima. Quando as ações previous-song
ou next-song
são recebidas, é provável que seja necessário enviar uma mensagem para a aplicação através de Client.postMessage para informar a aplicação de que deve começar a reproduzir as músicas anteriores ou seguintes.
Tenha em atenção que a action
propriedade do widgetEvent
objeto transmitido para o serviço de escuta de eventos acima corresponde à cadeia definida no action.verb
campo do modelo de widget.
Para obter mais informações sobre o widgetclick
evento e as informações a que pode aceder a partir do mesmo, veja Referência da API de Trabalho de Serviço, abaixo.
Atualizar widgets sobre alterações de aplicações
Nas secções anteriores, aprendeu a atualizar widgets quando ocorreram eventos específicos de widget, ações de widget e atualizações da função de trabalho de serviço. Também pode ser útil atualizar widgets quando algo acontece na aplicação, quando ocorre uma notificação push ou periodicamente.
Nesta secção, irá aprender a utilizar a API de Sincronização de Fundo Periódica para atualizar os widgets periodicamente. Para obter mais informações sobre a API de Sincronização de Fundo Periódica, veja Utilizar a API de Sincronização de Fundo Periódica para obter regularmente conteúdos novos.
No fragmento de código seguinte, é utilizado um serviço de escuta de eventos para reagir a vários eventos de ciclo de vida do widget da aplicação. Quando é detetada uma instalação de widget, é registada uma sincronização periódica e, quando é detetada uma remoção de widget, a sincronização periódica não é registada.
Quando ocorrem eventos de sincronização periódica, as instâncias de widget são atualizadas com 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});
}
Aplicação de demonstração
PWAmp é uma aplicação de demonstração PWA do leitor de música que define um widget. O widget PWAmp permite que os utilizadores visualizem a música atual e reproduzam as músicas anteriores ou seguintes.
Se ainda não tiver terminado, instale o WinAppSDK 1.2 e ative o Modo de Programador no Windows 11.
Aceda a PWAmp e instale a aplicação no Windows 11.
Abra a Placa Widgets do Windows 11 ao premir a tecla do logótipo do Windows + W.
Clique em Adicionar widgets para abrir o ecrã de definições de widgets, desloque-se para o widget mini player PWAmp e adicione-o.
Feche o ecrã de definições de widgets . O mini player PWAmp é agora apresentado no Widgets Board.
O widget PWAmp apresenta a música e os botões atuais para reproduzir a música anterior ou seguinte.
Referência da API de trabalho de serviço
O objeto global da função de trabalho de serviço (ou ServiceWorkerGlobalScope) contém um widgets
atributo que expõe os seguintes métodos baseados em Promessas:
Método | Descrição | Parâmetros | Valor de retorno |
---|---|---|---|
getByTag(tag) |
Obtém um widget por etiqueta. | A etiqueta de widget | Uma Promessa que é resolvida para o objeto widget que corresponde à etiqueta ou undefined . |
getByInstanceId(id) |
Obtém um widget por ID de instância. | O ID da instância do widget | Uma Promessa que é resolvida para o objeto widget correspondente ou undefined . |
getByHostId(id) |
Obtém widgets por ID de anfitrião. | O ID do anfitrião | Uma matriz de objetos widget encontrados nesse anfitrião. |
matchAll(options) |
Obtém widgets através de opções correspondentes. | Um objeto widgetOptions | Uma Promessa que é resolvida para uma matriz de objetos widget que correspondem aos options critérios. |
updateByInstanceId(id, payload) |
Atualiza um widget por ID de instância. | O ID da instância e um objeto widgetPayload | Uma Promessa que resolve para undefined ou Error . |
updateByTag(tag, payload) |
Atualiza um widget por etiqueta. | A etiqueta widget e um objeto widgetPayload | Uma Promessa que resolve para undefined ou Error . |
O objeto global da função de trabalho de serviço também define os seguintes eventos:
-
widgetinstall
: acionado quando o anfitrião do widget está a instalar um widget. -
widgetuninstall
: acionado quando o anfitrião de widget está a desinstalar um widget. -
widgetresume
: acionado quando o anfitrião de widget retoma a composição de widgets instalados, o que pode ocorrer após o anfitrião suspender a composição de widgets para preservar os recursos. -
widgetclick
: acionado quando o utilizador executa uma das ações do widget.
Para obter mais informações sobre os objetos fornecidos com estes eventos, veja o objeto widgetEvent e o objeto widgetClickEvent, abaixo.
objeto widget
Cada widget é representado como um widget
objeto, que contém as seguintes propriedades:
-
installable
: um booleano 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 utilizar matchAll(options)
para obter vários widgets, é necessário um widgetOptions
objeto para filtrar os widgets a devolver. O widgetOptions
objeto contém as seguintes propriedades, todas opcionais:
-
installable
: um booleano que indica se os widgets devolvidos devem ser instaláveis. -
installed
: um booleano que indica se os widgets devolvidos estão instalados no anfitrião do widget. -
tag
: uma cadeia utilizada para filtrar os widgets devolvidos por etiqueta. -
instanceId
: uma cadeia utilizada para filtrar os widgets devolvidos por ID de instância. -
hostId
: uma cadeia utilizada para filtrar os widgets devolvidos pelo ID do anfitrião do widget.
objeto widgetPayload
Ao criar ou atualizar uma instância de widget, a função de trabalho de serviço tem de enviar o modelo e os dados necessários para preencher o widget. O modelo e os dados são denominados payload. O widgetPayload
objeto contém as seguintes propriedades:
-
template
: o modelo, como uma cadeia, a utilizar para compor o widget. Este será o JSON com cadeias de carateres de um modelo de Cartão Ajustável. -
data
: os dados, como uma cadeia, a utilizar com o modelo de widget. Estes dados podem ser dados JSON com cadeias de carateres.
objeto widgetInstance
Este objeto representa uma determinada instância de um widget num anfitrião widget e contém as seguintes propriedades:
-
id
: a cadeia GUID interna utilizada para referenciar a instância. -
host
: um ponteiro interno para o anfitrião de widget que instalou esta 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 o último payload que foi enviado para esta instância.
objeto widgetDefinition
Este objeto representa a definição original do widget, que se encontra no ficheiro de manifesto do PWA. As propriedades deste objeto correspondem às propriedades listadas em Definir widgets, acima.
objeto widgetEvent
Este objeto é transmitido como um argumento para os serviços de escuta de eventos de widget de trabalho de serviço do tipo widgetinstall
, widgetuninstall
e widgetresume
.
Para os widgetinstall
tipos , widgetuninstall
e widgetresume
eventos, o widgetEvent
objeto tem as seguintes propriedades:
Propriedade | Descrição | Tipo |
---|---|---|
widget |
A instância do widget que acionou o evento. | widget |
instanceId |
O ID da instância do widget. | String |
hostId |
O ID do anfitrião do widget. | String |
widgetClickEvent object
Este objeto é transmitido como um argumento para os serviços de escuta de eventos de widget de trabalho de serviço do tipo widgetclick
. Pode abrir a janela da sua aplicação em resposta ao widgetclick
evento, utilizando 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. Veja Definir ações de widget. |
String |
widget |
A instância do widget que acionou o evento. | widgetInstance |
hostId |
O ID do anfitrião do widget. | String |
instanceId |
O ID da instância do widget. | String |