Compilación de widgets controlados por PWA
Varios sistemas operativos tienen paneles de widgets que permiten a los usuarios leer contenido y realizar tareas. Entre los ejemplos de esto se incluyen widgets de la pantalla principal de Android, widgets de panel de macOS y panel de hoy, apple touch bar, tarjetas diarias samsung, widgets de mini aplicación y complementos de aplicaciones de reloj inteligente.
En Windows 11, los widgets aparecen en el Panel de widgets, que se abre desde el lado izquierdo de la barra de tareas:
En Windows 11, Las aplicaciones web progresivas (PPA) pueden definir widgets, actualizarlos y controlar las interacciones del usuario dentro de ellos.
Requiere la creación de un widget personalizado para la PWA.
Una PWA existente no se puede colocar simplemente en el panel del widget tal como está, como puede hacer con la barra lateral de Microsoft Edge. En su lugar, debe crear una experiencia de widget personalizada que sea adecuada para el host del widget, que actualmente es el panel de widgets de Windows 11. (Puede haber otros hosts de widget en el futuro). El panel de widgets de Windows 11 requiere que los widgets se compilen mediante plantillas de tarjeta adaptable en lugar de HTML y JavaScript, por lo que el widget debe diseñarse por separado del resto de la interfaz de usuario de la aplicación.
Vea también:
Para compilar un widget controlado por PWA y entregarlo a través de Microsoft Store, no se requiere código de C++/C#. Una vez que haya generado el widget y pueda instalar y ejecutar correctamente el widget desde un punto de conexión público, puede empaquetar la aplicación mediante PWABuilder.com y enviar la aplicación a Microsoft Store sin necesidad de código adicional. La copia de seguridad de PWA del widget debe ser instalable desde un punto de conexión público, ya que PWABuilder.com no admite el empaquetado de aplicaciones desde localhost.
Vea también:
Instalar WinAppSDK y habilitar el modo de desarrollador
Para habilitar el desarrollo y la prueba de widgets en el equipo local:
Instale WinAppSDK 1.2.
Habilitar el modo de desarrollador en Windows 11:
Abra Configuración.
En el cuadro de texto Buscar una configuración , escriba
developer
y, a continuación, haga clic en Usar características para desarrolladores.Habilitar modo de desarrollador:
Definición de widgets
Los widgets se definen en el archivo de manifiesto PWA mediante el miembro del widgets
manifiesto. Este miembro de manifiesto es una matriz que puede contener varias definiciones 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 de la widgets
matriz contiene varios campos, como se muestra a continuación:
{
...
"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
}
]
}
En el ejemplo anterior, una aplicación de reproductor de música define un widget de mini reproductor. Una definición de widget en el manifiesto de aplicación web tiene los siguientes campos obligatorios y opcionales:
Campo | Descripción | Obligatorio |
---|---|---|
name |
Título del widget, presentado a los usuarios. | Yes |
short_name |
Una versión abreviada alternativa del nombre. | No |
description |
Descripción de lo que hace el widget. | Yes |
icons |
Matriz de iconos que se usarán para el widget. Si falta, se usa el miembro del icons manifiesto en su lugar. Los iconos mayores que 1024x1024 se omiten. |
No |
screenshots |
Matriz de capturas de pantalla que muestran el aspecto del widget. Análogo al miembro del screenshot manifiesto. El platform campo de un elemento de captura de pantalla admite los Windows valores y any . Las imágenes de más de 1024 x 1024 píxeles se omiten. Para conocer los requisitos de captura de pantalla específicos del panel de widgets de Windows 11, consulta Requisitos de imagen de captura de pantalla en Integrar con el selector de widgets. |
Yes |
tag |
Cadena que se usa para hacer referencia al widget en el trabajo del servicio PWA. | Yes |
template |
Plantilla que se va a usar para mostrar el widget en el panel de widgets del sistema operativo. Nota: Esta propiedad es actualmente solo informativa y no se usa. Vea ms_ac_template a continuación. |
No |
ms_ac_template |
Dirección URL de la plantilla de tarjetas adaptables personalizada que se va a usar para mostrar el widget en el panel de widgets del sistema operativo. Consulte Definición de una plantilla de widget a continuación. | Yes |
data |
Dirección URL con la que se pueden encontrar los datos con los que se va a rellenar la plantilla. Si está presente, esta dirección URL es necesaria para devolver json válido. | No |
type |
Tipo MIME para los datos del widget. | No |
auth |
Boolean que indica si el widget requiere autenticación. | No |
update |
Frecuencia, en segundos, en la que se actualizará el widget. El código del trabajo de servicio debe realizar la actualización; el widget no se actualiza automáticamente. Consulte Acceso a instancias de widget en tiempo de ejecución. | No |
multiple |
Un valor booleano que indica si se van a permitir varias instancias del widget. Valores predeterminados de true . |
No |
Definición de una plantilla de widget
Para que los widgets sean fáciles de crear y adaptar a varios paneles de widgets del sistema operativo, se muestran mediante plantillas. Existen dos tipos de plantillas:
- Plantillas genéricas, definidas por sus nombres mediante el
template
campo . - Plantillas personalizadas, definidas por sus direcciones URL mediante un campo de plantilla personalizado.
Por el momento, solo se admiten plantillas de tarjetas adaptables personalizadas. Tarjetas adaptables es un formato de intercambio de tarjetas abiertas que se puede usar para intercambiar contenido de la interfaz de usuario de una manera común y coherente. Consulte Introducción a las tarjetas adaptables.
Para definir una plantilla personalizada de tarjetas adaptables en Windows 11, usa el ms_ac_template
campo de la definición de widget que se encuentra en el manifiesto de la aplicación web. Aunque template
no se usa actualmente, es un campo obligatorio.
{
...
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player.json",
...
}
El valor del ms_ac_template
campo debe ser una dirección URL válida de un archivo de plantilla.
Este es un ejemplo de una plantilla de tarjetas adaptables:
{
"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 más información, consulte Plantillas de tarjetas adaptables.
A continuación, debe enlazar datos a la plantilla.
Enlace de datos a la plantilla
La plantilla declara la interfaz de usuario de un widget. A continuación, los datos rellenan esta interfaz de usuario.
Para enlazar datos a la plantilla, use el campo en la data
definición del widget. Este campo debe establecerse en una dirección URL que devuelva datos JSON válidos.
La plantilla definida en la sección anterior contiene dos variables: song
y artist
, que se incluyen en la sintaxis de la expresión de enlace: ${}
. Los datos devueltos por la dirección URL de la data
definición del widget deben contener valores para estas variables.
Este es un ejemplo de lo que podría devolver la data
dirección URL:
{
"song": "I Will Always Love You",
"artist": "Whitney Houston"
}
Definir acciones de widget
Si desea que el widget permita a los usuarios realizar tareas, defina una plantilla que admita acciones.
Este es un ejemplo de una acción definida en una plantilla personalizada de tarjetas adaptables:
{
"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"
}
Anote el verb
campo de la plantilla JSON anterior. Se usará al controlar las acciones del widget en el código de trabajo del servicio. Consulte Controlar acciones de widget.
Acceso a instancias de widget en tiempo de ejecución
Puede acceder a widgets y actualizarlos desde el código de trabajo del servicio PWA. El acceso a widgets en tiempo de ejecución es útil en casos como:
- Representación de widgets en la instalación.
- Actualizar widgets en las actualizaciones de service worker.
- Control de acciones de usuario en widgets.
- Actualizar widgets cuando cambia la aplicación.
Un trabajador del servicio tiene acceso al objeto y a self.widgets
varios eventos de widget que, juntos, constituyen una API que se usa para reaccionar a los cambios y acceder a los widgets en tiempo de ejecución.
En las secciones siguientes se proporcionan ejemplos de código. Para obtener una referencia de la API, consulte la referencia de api de trabajo de servicio.
Representación de widgets en la instalación
Cuando se instala un PWA, los widgets que define la aplicación en su manifiesto se agregan al panel de widgets, pero aún no están instalados. Un widget solo se instala cuando el usuario elige agregar el widget desde el panel.
Cuando se instala un widget, no se representa automáticamente mediante los ms_ac_template
campos y data
de la definición del widget.
Para representar el widget, escuche el evento en el widgetinstall
trabajo de servicio y actualice el widget mediante la widgets.updateByTag
función :
// 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});
}
Actualización de widgets en las actualizaciones de service worker
Cuando el código de trabajo del servicio cambia en un PWA, el explorador detecta ese cambio, instala el nuevo trabajo de servicio y, a continuación, activa el trabajo de servicio.
Cuando esto sucede, es importante actualizar las instancias de widget que ya se estén ejecutando. Es posible que se hayan instalado widgets antes de que se emita el evento de trabajo activate
del servicio. Para evitar mostrar widgets vacíos, actualice los widgets cuando se produzca el activate
evento.
// 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});
}
Controlar acciones de widget
Si la plantilla de widget contiene acciones, los usuarios pueden ejecutar esas acciones haciendo clic en los botones del widget representado. Para obtener información sobre cómo definir acciones en una plantilla, vea Definir acciones de widget.
Cuando un usuario ejecuta una acción de widget, se desencadena un widgetclick
evento en el trabajo del servicio PWA. Para controlar la acción del usuario, escuche el 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 mayor brevedad, el código de aplicación real no se muestra en el fragmento de código anterior. Cuando se reciben las previous-song
acciones o next-song
, es probable que deba enviarse un mensaje a la aplicación mediante Client.postMessage para que la aplicación sepa que debe empezar a reproducir las canciones anteriores o siguientes.
Tenga en cuenta que la action
propiedad del widgetEvent
objeto pasado al agente de escucha de eventos anterior coincide con la cadena definida en el action.verb
campo de la plantilla de widget.
Para obtener más información sobre el widgetclick
evento y la información a la que puede acceder desde él, consulte Referencia de la API de service worker a continuación.
Actualización de widgets en los cambios de la aplicación
En las secciones anteriores, ha aprendido a actualizar widgets cuando se han producido eventos de widget específicos, acciones de widget y actualizaciones de service worker. También puede ser útil actualizar widgets cuando ocurre algo en la aplicación, o cuando se produce una notificación push, o periódicamente.
En esta sección, aprenderá a usar la API de sincronización en segundo plano periódica para actualizar los widgets periódicamente. Para obtener más información sobre la API de sincronización en segundo plano periódico, consulte Uso de la API de sincronización en segundo plano periódica para obtener contenido nuevo periódicamente.
En el siguiente fragmento de código, se usa un agente de escucha de eventos para reaccionar a varios eventos de ciclo de vida del widget de aplicación. Cuando se detecta una instalación de widget, se registra una sincronización periódica y, cuando se detecta una eliminación de widget, se anula el registro de la sincronización periódica.
Cuando se producen eventos de sincronización periódicos, las instancias de widget se actualizan mediante la widgets.updateByTag
función .
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});
}
Aplicación de demostración
PWAmp es una aplicación de demostración de PWA de reproductor de música que define un widget. El widget PWAmp permite a los usuarios visualizar la canción actual y reproducir las canciones anteriores o siguientes.
Si aún no lo ha hecho, instale WinAppSDK 1.2 y habilite el modo de desarrollador en Windows 11.
Vaya a PWAmp e instale la aplicación en Windows 11.
Abra el Panel de widgets de Windows 11 presionando la tecla del logotipo de Windows + W.
Haga clic en Agregar widgets para abrir la pantalla de configuración de widgets , desplácese hasta el widget de mini reproductor PWAmp y agréguelo.
Cierre la pantalla de configuración de widgets . El mini-reproductor PWAmp ahora se muestra en el Panel de widgets.
El widget PWAmp muestra la canción actual y los botones para reproducir la canción anterior o siguiente.
Referencia de api de trabajo de servicio
El objeto global de trabajo de servicio (o ServiceWorkerGlobalScope) contiene un widgets
atributo que expone los siguientes métodos basados en Promise:
Método | Descripción | Parameters | Valor devuelto |
---|---|---|---|
getByTag(tag) |
Obtiene un widget por etiqueta. | La etiqueta de widget | Promesa que se resuelve en el objeto de widget que coincide con la etiqueta o undefined . |
getByInstanceId(id) |
Obtiene un widget por identificador de instancia. | Identificador de instancia del widget | Promesa que se resuelve en el objeto de widget correspondiente, o undefined . |
getByHostId(id) |
Obtiene widgets por identificador de host. | El identificador de host | Matriz de objetos de widget que se encuentran en ese host. |
matchAll(options) |
Obtiene widgets mediante opciones coincidentes. | Un objeto widgetOptions | Promesa que se resuelve en una matriz de objetos de widget que coinciden con los options criterios. |
updateByInstanceId(id, payload) |
Actualiza un widget por identificador de instancia. | El identificador de instancia y un objeto widgetPayload | Promesa que se resuelve en undefined o Error . |
updateByTag(tag, payload) |
Actualiza un widget por etiqueta. | La etiqueta de widget y un objeto widgetPayload | Promesa que se resuelve en undefined o Error . |
El objeto global del trabajo de servicio también define los siguientes eventos:
-
widgetinstall
: se desencadena cuando el host del widget instala un widget. -
widgetuninstall
: se desencadena cuando el host del widget desinstala un widget. -
widgetresume
: se desencadena cuando el host del widget reanuda la representación de widgets instalados, lo que puede ocurrir después de que el host suspendiera la representación de widgets para conservar los recursos. -
widgetclick
: se desencadena cuando el usuario ejecuta una de las acciones del widget.
Para obtener más información sobre los objetos que se proporcionan con estos eventos, vea widgetEvent object y widgetClickEvent object, a continuación.
widget (objeto)
Cada widget se representa como un widget
objeto, que contiene las siguientes propiedades:
-
installable
: un valor booleano que indica si el widget se puede instalar. -
definition
: un objeto widgetDefinition. -
instances
: matriz de objetos widgetInstance que representa el estado actual de cada instancia del widget.
widgetOptions (objeto)
Cuando se usa matchAll(options)
para obtener varios widgets, es necesario un widgetOptions
objeto para filtrar qué widgets devolver. El widgetOptions
objeto contiene las siguientes propiedades, todas las cuales son opcionales:
-
installable
: un valor booleano que indica si los widgets devueltos deben ser instalables. -
installed
: un valor booleano que indica si los widgets devueltos están instalados en el host del widget. -
tag
: cadena que se usa para filtrar los widgets devueltos por etiqueta. -
instanceId
: cadena que se usa para filtrar los widgets devueltos por identificador de instancia. -
hostId
: cadena que se usa para filtrar los widgets devueltos por el identificador de host del widget.
widgetPayload (objeto)
Al crear o actualizar una instancia de widget, el trabajador del servicio debe enviar la plantilla y los datos necesarios para rellenar el widget. La plantilla y los datos se denominan carga útil. El widgetPayload
objeto contiene las siguientes propiedades:
-
template
: la plantilla, como una cadena, que se va a usar para representar el widget. Este será el JSON con cadena de una plantilla de tarjeta adaptable. -
data
: los datos, como una cadena, que se van a usar con la plantilla de widget. Estos datos pueden ser datos JSON con cadena.
widgetInstance (objeto)
Este objeto representa una instancia determinada de un widget en un host de widget y contiene las siguientes propiedades:
-
id
: cadena GUID interna que se usa para hacer referencia a la instancia. -
host
: puntero interno al host de widget que ha instalado esta instancia. -
updated
Date
: objeto que representa la última vez que se enviaron datos a la instancia. -
payload
: un objeto widgetPayload que representa la última carga que se envió a esta instancia.
widgetDefinition (objeto)
Este objeto representa la definición original del widget, que se encuentra en el archivo de manifiesto PWA. Las propiedades de este objeto coinciden con las propiedades que aparecen en Definir widgets, anteriormente.
widgetEvent (objeto)
Este objeto se pasa como argumento a los agentes de escucha de eventos de widget de trabajo de servicio de tipo widgetinstall
, widgetuninstall
y widgetresume
.
Para los widgetinstall
tipos de eventos , widgetuninstall
y widgetresume
, el widgetEvent
objeto tiene las siguientes propiedades:
Propiedad | Descripción | Tipo |
---|---|---|
widget |
Instancia del widget que desencadenó el evento. | widget |
instanceId |
Identificador de instancia del widget. | String |
hostId |
Identificador de host del widget. | String |
widgetClickEvent (objeto)
Este objeto se pasa como argumento a los agentes de escucha de eventos de widget de trabajo de servicio de tipo widgetclick
. Puede abrir la ventana de la aplicación en respuesta al widgetclick
evento mediante clients.openWindow()
.
El widgetClickEvent
objeto tiene las siguientes propiedades:
Propiedad | Descripción | Tipo |
---|---|---|
action |
Acción que desencadenó el evento, tal como se define en los actions.verb campos de la plantilla de widget. Consulte Definir acciones de widget. |
String |
widget |
Instancia del widget que desencadenó el evento. | widgetInstance |
hostId |
Identificador de host del widget. | String |
instanceId |
Identificador de instancia del widget. | String |