Fecha de publicación: 2 de diciembre de 2020
Desde que se presentó la actividad web confiable, el equipo de Chrome facilitó su uso con Bubblewrap. Agregamos funciones adicionales, como la integración de la Facturación Google Play, y habilitamos que funcione en más plataformas, como ChromeOS.
Funciones de Bubblewrap y Trusted Web Activity
Bubblewrap te ayuda a crear apps que inician tus AWP dentro de una actividad web confiable, sin necesidad de conocer las herramientas específicas de la plataforma.
Flujo de configuración simplificado
Anteriormente, usar Bubblewrap requería configurar manualmente el kit de desarrollo de Java y el SDK de Android, que son propensos a errores. La herramienta ahora ofrece descargar automáticamente las dependencias externas cuando se ejecuta por primera vez.
Si lo prefieres, puedes usar una instalación existente de las dependencias. El nuevo comando doctor
ayuda a encontrar problemas y recomienda correcciones en la configuración, que ahora se puede actualizar desde la línea de comandos con el comando updateConfig
.
Asistente mejorado
Cuando se crea un proyecto con init
, Bubblewrap necesita información para generar la app para Android. La herramienta extrae valores del manifiesto de la app web y proporciona valores predeterminados cuando es posible.
Puedes cambiar esos valores cuando creas un proyecto nuevo, pero antes el significado de cada campo no era claro. Los diálogos de inicialización se volvieron a compilar con mejores descripciones y validaciones para cada campo de entrada.
Cómo mostrar compatibilidad con pantalla completa y orientación
En algunos casos, es posible que desees que tu aplicación use la mayor parte de la pantalla posible y, cuando compilas PWAs, esto se implementa configurando el campo display
del manifiesto de la app web en fullscreen
.
Cuando Bubblewrap detecta la opción de pantalla completa en el manifiesto de la app web, configura la aplicación para Android de modo que también se inicie en pantalla completa o en modo envolvente, en términos específicos de Android.
El campo orientation
del manifiesto de la app web define si la aplicación se debe iniciar en modo vertical, horizontal o en la orientación que el dispositivo está usando actualmente. Bubblewrap ahora
lee el campo del manifiesto de la app web y lo usa como predeterminado cuando creas la app para Android.
Puedes personalizar ambas configuraciones como parte del flujo bubblewrap init
.
Salida de AppBundles
App Bundles es un formato de publicación para apps que delega la generación y firma de APK final a Play. En la práctica, esto permite que se entreguen archivos más pequeños a los usuarios cuando descargan la app de la tienda.
Bubblewrap ahora empaqueta la aplicación como un paquete de aplicación, en un archivo llamado app-release-bundle.aab
. Debes preferir este formato cuando publiques apps en Play Store, ya que es obligatorio a partir de 2021.
Delegación de la ubicación geográfica
Los usuarios esperan que las aplicaciones instaladas en sus dispositivos se comporten de manera coherente, independientemente de la tecnología. Cuando se usa dentro de una actividad web confiable, el permiso GeoLocation ahora se puede delegar al sistema operativo y, cuando está habilitado, los usuarios ven los mismos diálogos que las apps compiladas con Kotlin o Java, y encuentran controles para administrar el permiso en el mismo lugar.
La función se puede agregar a través de Bubblewrap y, como agrega dependencias adicionales al proyecto de Android, solo debes habilitarla cuando la app web use el permiso de Geolocalización.
Objetos binarios optimizados
Los dispositivos con almacenamiento limitado son comunes en ciertas áreas del mundo, y los propietarios de esos dispositivos a menudo prefieren aplicaciones más pequeñas. Las aplicaciones que usan la Actividad web confiable producen objetos binarios pequeños, lo que quita parte de la ansiedad de esos usuarios.
Bubblewrap se optimizó reduciendo la lista de bibliotecas de Android necesarias, lo que genera objetos binarios que son 800,000 más pequeños. En la práctica, eso es menos de la mitad del tamaño promedio que generaban las versiones anteriores. Para aprovechar los objetos binarios más pequeños, solo debes actualizar tu app con la versión más reciente de Bubblewrap.
Cómo actualizar una app existente
Una aplicación generada por Bubblewrap se compone de una aplicación web y un wrapper ligero de Android que abre la AWP. Aunque la AWP que se abre dentro de una Actividad web de confianza sigue los mismos ciclos de actualización que cualquier app web, el wrapper nativo se puede y se debe actualizar.
Debes actualizar la app para asegurarte de que use la versión más reciente del wrapper, con las funciones y correcciones de errores más recientes. Con la versión más reciente de Bubblewrap instalada, el comando update
aplica la versión más reciente del wrapper a un proyecto existente:
npm update -g @bubblewrap/cli
bubblewrap update
bubblewrap build
Otro motivo para actualizar esas aplicaciones es garantizar que los cambios en el manifiesto web se apliquen a la aplicación. Para ello, usa el nuevo comando merge
:
bubblewrap merge
bubblewrap update
bubblewrap build
Actualizaciones de los criterios de calidad
En Chrome 86, se introdujeron cambios en los criterios de calidad de la actividad web de confianza, que se explican en detalle en Cambios en los criterios de calidad para las AWP que usan actividad web de confianza.
En resumen, debes asegurarte de que tus aplicaciones controlen las siguientes situaciones para evitar que fallen:
- No se pudieron verificar los vínculos de recursos digitales en el lanzamiento de la aplicación
- No se muestra el estado HTTP 200 para una solicitud de recurso de red sin conexión
- Se muestra un error HTTP 404 o 5xx en la aplicación.
Además de garantizar que la aplicación pase la validación de Vínculos de recursos digitales, un service worker puede controlar las situaciones restantes:
self.addEventListener('fetch', event => {
event.respondWith((async () => {
try {
return await fetchAndHandleError(event.request);
} catch {
// Failed to load from the network. User is offline or the response
// has a status code that triggers the Quality Criteria.
// Try loading from cache.
const cachedResponse = await caches.match(event.request);
if (cachedResponse) {
return cachedResponse;
}
// Response was not found on the cache. Send the error / offline
// page. OFFLINE_PAGE should be pre-cached when the service worker
// is activated.
return await caches.match(OFFLINE_PAGE);
}
})());
});
async function fetchAndHandleError(request) {
const cache = await caches.open(RUNTIME_CACHE);
const response = await fetch(request);
// Throw an error if the response returns one of the status
// that trigger the Quality Criteria.
if (response.status === 404 ||
response.status >= 500 && response.status < 600) {
throw new Error(`Server responded with status: ${response.status}`);
}
// Cache the response if the request is successful.
cache.put(request, response.clone());
return response;
}
Workbox incorpora prácticas recomendadas y quita el texto de referencia cuando se usan trabajadores del servicio. Como alternativa, considera usar un complemento de Workbox para controlar esas situaciones:
export class FallbackOnErrorPlugin {
constructor(offlineFallbackUrl, notFoundFallbackUrl, serverErrorFallbackUrl) {
this.notFoundFallbackUrl = notFoundFallbackUrl;
this.offlineFallbackUrl = offlineFallbackUrl;
this.serverErrorFallbackUrl = serverErrorFallbackUrl;
}
checkTrustedWebActivityCrash(response) {
if (response.status === 404 || response.status >= 500 && response.status <= 600) {
const type = response.status === 404 ? 'E_NOT_FOUND' : 'E_SERVER_ERROR';
const error = new Error(`Invalid response status (${response.status})`);
error.type = type;
throw error;
}
}
// This is called whenever there's a network response,
// but we want special behavior for 404 and 5**.
fetchDidSucceed({response}) {
// Cause a crash if this is a Trusted Web Activity crash.
this.checkTrustedWebActivityCrash(response);
// If it's a good response, it can be used as-is.
return response;
}
// This callback is new in Workbox v6, and is triggered whenever
// an error (including a NetworkError) is thrown when a handler runs.
handlerDidError(details) {
let fallbackURL;
switch (details.error.details.error.type) {
case 'E_NOT_FOUND': fallbackURL = this.notFoundFallbackUrl; break;
case 'E_SERVER_ERROR': fallbackURL = this.serverErrorFallbackUrl; break;
default: fallbackURL = this.offlineFallbackUrl;
}
return caches.match(fallbackURL, {
// Use ignoreSearch as a shortcut to work with precached URLs
// that have _WB_REVISION parameters.
ignoreSearch: true,
});
}
}