Novedades de Web en Play

Desde que se presentó la Actividad web de confianza el año pasado, el equipo de Chrome sigue trabajando en el producto, lo que facilita su uso con Burbujas, agrega funciones nuevas, como la próxima integración con Facturación Google Play, y permite que funcione en más plataformas, como ChromeOS. En este artículo, se resumirán las actualizaciones más recientes y futuras de la actividad web de confianza.

Nuevas funciones de Burbuja y Actividad web de confianza

Bubblewrap te ayuda a crear apps que inicien tus AWP dentro de una actividad web de confianza, sin la necesidad de tener conocimientos sobre herramientas específicas de la plataforma.

Flujo de configuración simplificado

Anteriormente, para usar la función de burbujas, se debía configurar manualmente Java Development Kit y el SDK de Android, que son propensos a errores. Ahora, la herramienta ofrece descargar automáticamente las dependencias externas cuando se ejecutan por primera vez.

Puedes optar por usar una instalación existente de las dependencias, si prefieres hacerlo. El nuevo comando doctor ayuda a encontrar problemas y recomienda correcciones para la configuración, que ahora se puede actualizar desde la línea de comandos con el comando updateConfig.

Asistente mejorado

Cuando creas un proyecto con init, Burbujas necesita información para generar la app para Android. La herramienta extrae valores del manifiesto de apps 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 estaba claro. Los diálogos de inicialización se volvieron a compilar con mejores descripciones y la validación de cada campo de entrada.

pantalla: compatibilidad con pantalla completa y orientación

En algunos casos, recomendamos que tu aplicación use la mayor cantidad de pantalla posible. Cuando se compilen AWP, esto se implementa configurando el campo display del manifiesto de apps web como fullscreen.

Cuando la función Burbujas detecte la opción de pantalla completa en el manifiesto de apps web, configurará la app para Android de modo que también se inicie en pantalla completa, o en modo envolvente, según términos específicos de Android.

El campo orientation del manifiesto de apps web define si la aplicación debe iniciarse en modo vertical, horizontal o en la orientación que usa el dispositivo actualmente. Burbujas ahora lee el campo del manifiesto de apps web y lo usa como predeterminado cuando se crea la app para Android.

Puedes personalizar ambos parámetros de configuración como parte del flujo de bubblewrap init.

Salida de AppBundles

Los paquetes de aplicaciones son un formato de publicación para apps que delega la generación de APK final y la firma a Play. En la práctica, esto permite entregar archivos más pequeños a los usuarios cuando descargan la app desde la tienda.

Burbuja ahora empaqueta la aplicación como un paquete de aplicación, en un archivo llamado app-release-bundle.aab. Recomendamos que uses este formato cuando publiques apps en Play Store, ya que la tienda lo requerirá a partir de la segunda mitad de 2021.

Delegación de 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 de confianza, el permiso GeoLocation ahora se puede delegar al sistema operativo y, cuando se habilita, 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 con la función de Burbujas y, como agrega dependencias adicionales al proyecto de Android, solo debes habilitarla cuando la app web use el permiso de Ubicación geográfica.

Objetos binarios optimizados

Los dispositivos con almacenamiento limitado son comunes en ciertas áreas del mundo y sus propietarios, con frecuencia, prefieren aplicaciones más pequeñas. Las aplicaciones que usan la actividad web de confianza producen objetos binarios pequeños, lo que les quita algo de ansiedad a esos usuarios.

Para optimizar la función de Burbujas, se redujo la lista de bibliotecas de Android necesarias, lo que generó objetos binarios 800,000 más pequeños. En la práctica, es menos de la mitad del tamaño promedio generado por versiones anteriores. Para aprovechar los objetos binarios más pequeños, solo debes actualizar la app con la versión más reciente de Burbujas.

Cómo actualizar una app existente

Una aplicación generada por Burbujas está compuesta por una aplicación web y un wrapper ligero de Android que abre la AWP. Si bien 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 puede y debe actualizarse.

Debes actualizar tu app para asegurarte de que use la versión más reciente del wrapper, con las correcciones de errores y las funciones más recientes. Con la versión más reciente de Burbuja instalada, el comando update aplicará la última versión del wrapper a un proyecto existente:

npm update -g @bubblewrap/cli
bubblewrap update
bubblewrap build

Otra razón para actualizar esas aplicaciones es asegurarte de 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

Chrome 86 introdujo cambios en los criterios de calidad de la actividad web de confianza, que se explican en su totalidad en Cambios en los criterios de calidad para AWP que usan actividad web de confianza.

Un resumen breve es que debes asegurarte de que tus aplicaciones manejen las siguientes situaciones para evitar que fallen:

  • No se verifican los vínculos de recursos digitales al iniciar la aplicación.
  • No se pudo mostrar HTTP 200 para una solicitud de recurso de red sin conexión
  • 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 integra las prácticas recomendadas y quita el código estándar cuando se usan service workers. Como alternativa, considera usar un complemento de Workbox para manejar 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,
    });
  }
}

Facturación Google Play

Además de permitir que tu app venda suscripciones y artículos digitales en Play Store, la Facturación Google Play ofrece herramientas para administrar el catálogo, los precios y las suscripciones, informes útiles y un flujo de confirmación de la compra con la tecnología de Play Store que tus usuarios ya conocen. También es un requisito para las aplicaciones publicadas en Play Store que venden artículos digitales.

Chrome 88 se lanzará con una prueba de origen en Android que habilita la integración de Trusted Web Activities, la API de Payment Request y la API de Digital Goods para implementar flujos de compra a través de la Facturación Google Play. Esperamos que esta prueba de origen también esté disponible para ChromeOS en la versión 89.

Importante: La API de Facturación Google Play tiene su propia terminología, que incluye componentes de cliente y de backend. En esta sección, solo se abarca una pequeña parte de la API que es específica para el uso de la API de Digital Goods y Trusted Web Activity. Asegúrate de leer la documentación de Facturación Google Play y comprender sus conceptos antes de integrarla a una aplicación de producción.

El flujo básico

Menú de Play Console

Para proporcionar artículos digitales a través de Play Store, deberás configurar el catálogo en Play Store y conectar Play Store como una forma de pago desde tu AWP.

Cuando tengas todo listo para configurar el catálogo, busca la sección Productos en el menú lateral izquierdo de Play Console:

Aquí encontrarás la opción de ver tus suscripciones y productos integrados en la aplicación existentes, y el botón de creación para agregar nuevos.

Productos integrados en la aplicación

Detalles del producto

Para crear un nuevo producto integrado en la aplicación, necesitarás un ID, un nombre, una descripción y un precio del producto. Es importante crear IDs de productos significativos y fáciles de recordar, ya que los necesitarás más adelante y no se pueden cambiar después de crearlos.

Cuando crees suscripciones, también deberás especificar un período de facturación. Puedes enumerar los beneficios de tu suscripción y agregar funciones, como si tienes una prueba gratuita, un precio de lanzamiento, un período de gracia y la opción para volver a suscribirte.

Después de crear cada producto, actívalos para que estén disponibles en la app.

Si lo prefieres, puedes agregar tus productos mediante la API de Play Developers.

Una vez que hayas configurado el catálogo, el siguiente paso es configurar el flujo de confirmación de la compra desde la AWP. Para ello, usarás una combinación de la API de Digital Goods y la API de Payment Request.

Recupera el precio de un producto con la API de Digital Goods

Cuando uses la Facturación Google Play, asegúrate de que el precio que se muestra a los usuarios coincida con el del ficha de Play Store. No sería posible mantener sincronizados esos precios de forma manual, por lo que la API de Digital Goods proporciona una forma para que la aplicación web consulte los precios al proveedor de pagos subyacente:

// The SKU for the product, as defined in the Play Store interface
async function populatePrice(sku) {
  try {
    // Check if the Digital Goods API is supported by the browser.
    if (window.getDigitalGoodsService) {
      // The Digital Goods API can be supported by other Payments provider.
      // In this case, we're retrieving the Google Play Billing provider.
      const service =
          await window.getDigitalGoodsService("https://play.google.com/billing");

      // Fetch product details using the `getDetails()` method.
      const details = await service.getDetails([sku]);

      if (details.length === 0) {
        console.log(`Could not get SKU: "${sku}".`);
        return false;
      }

      // The details will contain both the price and the currenncy.
      item = details[0];
      const value = item.price.value;
      const currency = item.price.currency;

      const formattedPrice = new Intl.NumberFormat(navigator.language, {
        style: 'currency', currency: currency }).format(value);

      // Display the price to the user.
      document.getElementById("price").innerHTML = formattedPrice;
    } else {
      console.error("Could not get price for SKU \"" + sku + "\".");
    }
  } catch (error) {
    console.log(error);
  }
  return false;
}

Puedes detectar la compatibilidad con la API de Digital Goods si verificas si getDigitalGoodsService() está disponible en el objeto window.

Luego, llama a window.getDigitalGoodsService() con el identificador de Facturación Google Play como parámetro. Se mostrará una instancia de servicio para la Facturación Google Play, y otros proveedores podrán implementar la compatibilidad con la API de artículos digitales y tendrán identificadores diferentes.

Por último, llama a getDetails() en la referencia al objeto de la Facturación Google Play y pasa el SKU del elemento como parámetro. El método mostrará un objeto de detalles que contiene el precio y la moneda del elemento que se puede mostrar al usuario.

Inicia el flujo de compra

La API de Payment Request habilita los flujos de compra en la Web y también se usa para la integración de la Facturación Google Play. Consulta Cómo funciona la API de Payment Request para obtener más información si no estás familiarizado con la API de Payment Request.

Para usar la API con la Facturación Google Play, deberás agregar un instrumento de pago que tenga un método compatible llamado https://play.google.com/billing y agregar el SKU como parte de los datos del instrumento:

const supportedInstruments = [{
  supportedMethods: "https://play.google.com/billing",
  data: {
    sku: sku
  }
}];

Luego, compila un objeto PaymentRequest como de costumbre y usa la API como de costumbre.

const request = new PaymentRequest(supportedInstruments, details);

Confirma la compra

Una vez que se complete la transacción, deberás usar la API de artículos digitales para confirmar el pago. El objeto de respuesta de PaymentRequest contendrá un token que utilizarás para confirmar la transacción:

const response = await request.show();
const token = response.details.token;
const service =
          await window.getDigitalGoodsService("https://play.google.com/billing");
await service.acknowledge(token, 'onetime');

Las APIs de Digital Goods y Payment Request no tienen conocimiento de la identidad del usuario. Como resultado, depende de ti asociar la compra al usuario en tu backend y asegurarte de que tenga acceso a los artículos comprados. Cuando asocies la compra a un usuario, recuerda guardar el token de compra, ya que es posible que lo necesites para verificar si la compra se canceló o se reembolsó, o si la suscripción aún está activa. Consulta la API de notificaciones para desarrolladores en tiempo real y la API de Google Play Developer, que ofrecen extremos para manejar esos casos en tu backend.

Verifica los derechos existentes

Un usuario puede haber canjeado un código promocional o tener una suscripción existente a tu producto. Para validar que el usuario tiene los derechos correspondientes, puedes llamar al comando listPurchases() en el servicio de artículos digitales. Esto mostrará todas las compras que el cliente haya realizado en tu app. También será el lugar para confirmar las compras no confirmadas, a fin de garantizar que el usuario canjee correctamente sus derechos.

const purchases = await itemService.listPurchases();
for (p of purchases) {
  if (!p.acknowledged) {
    await itemService.acknowledge(p.purchaseToken, 'onetime');
  }
}

Subir contenido a Play Store de ChromeOS

A partir de Chrome 85, las funciones web de confianza también están disponibles en Play Store de ChromeOS. El proceso para publicar tu app en la tienda es el mismo para ChromeOS que para Android.

Una vez que hayas creado tu paquete de aplicación, Play Console te guiará por los pasos necesarios para publicar la app en Play Store. En la documentación de Play Console, puedes encontrar ayuda para crear la ficha de tu app, administrar los archivos APK y otros parámetros de configuración, así como instrucciones para realizar pruebas y lanzar tu app de forma segura.

Para restringir tu aplicación solo a Chromebooks, agrega la marca --chromeosonly cuando inicialices la aplicación en Burbujas:

bubblewrap init --manifest="https://example.com/manifest.json" --chromeosonly

Cuando compiles tu aplicación manualmente, sin Burbujas, agrega una marca uses-feature a tu manifiesto de Android:

<uses-feature  android:name="org.chromium.arc" android:required="true"/>

Si tu ficha se comparte con una app para Android, la versión del paquete exclusivo de ChromeOS siempre deberá ser superior a la versión del paquete de la app para Android. Puedes configurar la versión del paquete de ChromeOS en un número mucho más alto que la versión de Android, por lo que no necesitas actualizar ambas versiones con cada versión.