Novità di Web in Play

Da quando l'Attività web attendibile è stata introdotta l'anno scorso, il team di Chrome continua a lavorare al prodotto, semplificando l'utilizzo con Bubblewrap, aggiungendo nuove funzionalità come l'imminente integrazione della Fatturazione Google Play e consentendone il funzionamento su più piattaforme, come ChromeOS. Questo articolo riassume gli aggiornamenti più recenti e futuri relativi all'Attività web attendibile.

Nuove funzionalità Bubble wrap e Attività web attendibile

Il wrapping di bolle ti consente di creare app che avviano le tue PWA all'interno di un'attività web attendibile, senza richiedere la conoscenza di strumenti specifici per la piattaforma.

Flusso di configurazione semplificato

In precedenza, l'utilizzo di Bubblewrap richiedeva la configurazione manuale del kit di sviluppo Java e dell'SDK Android, entrambi soggetti a errori. Lo strumento ora offre il download automatico delle dipendenze esterne quando viene eseguito per la prima volta.

Puoi comunque scegliere di utilizzare un'installazione esistente delle dipendenze, se preferisci farlo. Inoltre, il nuovo comando doctor consente di individuare i problemi e consiglia le correzioni della configurazione, che ora può essere aggiornata dalla riga di comando utilizzando il comando updateConfig.

Procedura guidata migliorata

Quando crei un progetto con init, Bubblewrap ha bisogno di informazioni per generare l'app per Android. Lo strumento estrae i valori dal file manifest dell'app web e fornisce valori predefiniti, ove possibile.

Puoi modificare questi valori durante la creazione di un nuovo progetto, ma in precedenza il significato di ogni campo non era chiaro. Le finestre di dialogo di inizializzazione sono state ricostruite con descrizioni e convalida migliori per ogni campo di input.

display: supporto per schermo intero e orientamento

In alcuni casi, potresti volere che l'applicazione utilizzi la maggior quantità di schermo possibile e, durante la creazione di PWA, questo viene implementato impostando il campo display dal manifest dell'app web su fullscreen.

Quando Bubblewrap rileva l'opzione per la modalità a schermo intero nel manifest dell'app web, configura l'applicazione Android in modo che venga avviata anche in modalità a schermo intero, o modalità immersiva, in termini specifici di Android.

Il campo orientation del file manifest dell'app web definisce se l'applicazione deve essere avviata in modalità verticale, orizzontale o nell'orientamento attualmente in uso sul dispositivo. Bubblewrap ora legge il campo Manifest per app web e lo utilizza come impostazione predefinita durante la creazione dell'app per Android.

Puoi personalizzare entrambe le configurazioni nell'ambito del flusso bubblewrap init.

Output AppBundles

App Bundle è un formato di pubblicazione per le app che delega la generazione degli APK finali e la firma su Google Play. In pratica, ciò consente di pubblicare file più piccoli per gli utenti quando scaricano l'app dallo store.

Bubblewrap ora pacchettizza l'applicazione come app bundle, in un file denominato app-release-bundle.aab. Dovresti preferire questo formato per la pubblicazione di app sul Play Store, in quanto sarà obbligatorio per lo store a partire dalla seconda metà del 2021.

Delega di geolocalizzazione

Gli utenti si aspettano che le applicazioni installate sui loro dispositivi funzionino in modo coerente, indipendentemente dalla tecnologia. Se utilizzata all'interno di un'attività web attendibile, l'autorizzazione GeoLocation ora può essere delegata al sistema operativo e, se abilitata, gli utenti vedranno le stesse finestre di dialogo delle app create con Kotlin o Java e troveranno i controlli per gestire l'autorizzazione dalla stessa posizione.

La funzionalità può essere aggiunta tramite il wrapping di bolle e, poiché aggiunge ulteriori dipendenze al progetto Android, dovresti abilitarla solo quando l'app web utilizza l'autorizzazione di geolocalizzazione.

Programmi binari ottimizzati

I dispositivi con spazio di archiviazione limitato sono comuni in determinate aree del mondo e i proprietari di questi dispositivi spesso preferiscono le applicazioni più piccole. Le applicazioni che usano Attività web attendibili producono piccoli file binari, eliminando in parte l'ansia di questi utenti.

Il wrapping di bolle è stato ottimizzato riducendo l'elenco delle librerie Android necessarie, con conseguente generazione di programmi binari di 800 kB più piccoli. In pratica, si tratta di meno della metà delle dimensioni medie generate dalle versioni precedenti. Per sfruttare i programmi binari più piccoli, devi solo aggiornare l'app utilizzando l'ultima versione di Bubblewrap.

Aggiornare un'app esistente

Un'applicazione generata da Bubblewrap è composta da un'applicazione web e da un wrapper Android leggero che apre la PWA. Anche se la PWA aperta all'interno di un'attività web attendibile segue gli stessi cicli di aggiornamento di qualsiasi app web, il wrapper nativo può e deve essere aggiornato.

Devi aggiornare l'app per assicurarti che utilizzi la versione più recente del wrapper, con le correzioni di bug e le funzionalità più recenti. Con la versione più recente di Bubblewrap installata, il comando update applicherà la versione più recente del wrapper a un progetto esistente:

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

Un altro motivo per aggiornare queste applicazioni è garantire che le modifiche al manifest web vengano applicate all'applicazione. Usa il nuovo comando merge per farlo:

bubblewrap merge
bubblewrap update
bubblewrap build

Aggiornamenti ai criteri di qualità

Chrome 86 ha introdotto delle modifiche ai criteri di qualità delle attività web attendibili, spiegate per intero nella sezione Modifiche ai criteri di qualità per le PWA che utilizzano l'attività web attendibile.

Un breve riepilogo è che devi assicurarti che le tue applicazioni gestiscano i seguenti scenari per evitare che si arrestino in modo anomalo:

  • Mancata verifica dei link agli asset digitali al lancio dell'applicazione
  • Impossibile restituire HTTP 200 per una richiesta di risorsa di rete offline
  • Restituzione di un errore HTTP 404 o 5xx nell'applicazione.

Oltre ad assicurarsi che l'applicazione superi la convalida di Digital Asset Links, gli scenari rimanenti possono essere gestiti da un service worker:

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 sforna le best practice e rimuove il boilerplate quando si utilizzano i service worker. In alternativa, puoi utilizzare un plug-in Workbox per gestire questi scenari:

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,
    });
  }
}

Fatturazione Google Play

Oltre a consentire alla tua app di vendere prodotti digitali e abbonamenti sul Play Store, la fatturazione di Google Play offre strumenti per la gestione di catalogo, prezzi e abbonamenti, report utili e un flusso di pagamento basato sul Play Store che i tuoi utenti conoscono già. È inoltre un requisito per le applicazioni pubblicate sul Play Store che vendono beni digitali.

Chrome 88 verrà lanciato con una prova dell'origine su Android che consentirà l'integrazione di Attività web attendibili, dell'API Payment Request e dell'API Digital Goods per implementare i flussi di acquisto tramite Fatturazione Google Play. Prevediamo che questa prova dell'origine sia disponibile anche per ChromeOS nella versione 89.

Importante: l'API Fatturazione Google Play ha una propria terminologia e include componenti client e di backend. Questa sezione riguarda solo una piccola parte dell'API specifica per l'utilizzo dell'API Digital Goods e dell'Attività web attendibile. Assicurati di leggere la documentazione relativa alla fatturazione Google Play e di comprendere i concetti prima di integrare la funzionalità in un'applicazione di produzione.

Il flusso di base

Menu di Play Console

Per fornire prodotti digitali tramite il Play Store, dovrai configurare il tuo catalogo sul Play Store, nonché collegare il Play Store come metodo di pagamento dalla tua PWA.

Quando è tutto pronto per configurare il catalogo, inizia cercando la sezione Prodotti nel menu a sinistra di Play Console:

Qui troverai l'opzione per visualizzare i prodotti in-app e gli abbonamenti esistenti, nonché il pulsante Crea per aggiungerne di nuovi.

Prodotti in-app

Dettagli del prodotto

Per creare un nuovo prodotto in-app ti serviranno un ID prodotto, un nome, una descrizione e un prezzo. È importante creare ID prodotto significativi e facili da ricordare, ti serviranno in un secondo momento e gli ID non potranno essere modificati una volta creati.

Quando crei gli abbonamenti, devi anche specificare un periodo di fatturazione. Puoi elencare i vantaggi dell'abbonamento e aggiungere funzionalità, ad esempio la prova senza costi, un prezzo di lancio, un periodo di tolleranza e un'opzione per riabbonarti.

Dopo aver creato ciascun prodotto, rendilo disponibile nella tua app attivandolo.

Se preferisci, puoi aggiungere i tuoi prodotti tramite l'API Play Developers.

Una volta configurato il catalogo, il passaggio successivo è configurare il flusso di pagamento dalla PWA. A tal fine, utilizzerai una combinazione dell'API Digital Goods e dell'API Payment Request.

Recuperare il prezzo di un prodotto con l'API Digital Goods

Quando utilizzi Fatturazione Google Play, vorrai assicurarti che il prezzo mostrato agli utenti corrisponda a quello indicato nella scheda dello Store. Mantenere manualmente sincronizzati i prezzi sarebbe impossibile, pertanto l'API Digital Goods fornisce un modo per consentire all'applicazione web di richiedere i prezzi al fornitore di servizi di pagamento sottostante:

// 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;
}

Puoi rilevare il supporto per l'API Digital Goods controllando se getDigitalGoodsService() è disponibile nell'oggetto window.

Quindi chiama window.getDigitalGoodsService() con l'identificatore di fatturazione di Google Play come parametro. Verrà restituita un'istanza di servizio per Fatturazione Google Play e altri fornitori possono implementare il supporto per l'API Digital Goods e avranno identificatori diversi.

Infine, chiama getDetails() per il riferimento all'oggetto Fatturazione Google Play che trasmette lo SKU dell'elemento come parametro. Il metodo restituisce un oggetto dettaglio contenente sia il prezzo sia la valuta dell'elemento che può essere mostrato all'utente.

Avviare il flusso di acquisto

L'API Payment Request consente i flussi di acquisto sul web e viene utilizzata anche per l'integrazione di Fatturazione Google Play. Per saperne di più se non hai mai utilizzato l'API Payment Request, consulta l'articolo Come funziona l'API Payment Request.

Per utilizzare l'API con Fatturazione Google Play, dovrai aggiungere uno strumento di pagamento che abbia un metodo supportato chiamato https://play.google.com/billing e aggiungere lo SKU come parte dei dati dello strumento:

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

Quindi, crea un oggetto PaymentRequest come di consueto e utilizza l'API come di consueto

const request = new PaymentRequest(supportedInstruments, details);

Conferma l'acquisto

Una volta completata la transazione, dovrai utilizzare l'API Digital Goods per confermare il pagamento. L'oggetto risposta da PaymentRequest conterrà un token che userai per confermare la transazione:

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');

L'API Digital Goods e l'API Payment Request non sono a conoscenza dell'identità dell'utente. Di conseguenza, spetta a te associare l'acquisto all'utente nel tuo backend e assicurarti che abbia accesso agli articoli acquistati. Quando associ l'acquisto a un utente, ricordati di salvare il token di acquisto, in quanto potresti doverlo verificare per verificare se l'acquisto è stato annullato o rimborsato oppure se un abbonamento è ancora attivo. Controlla l'API Real Time Developer Notifications e l'API Google Play Developer perché forniscono gli endpoint per la gestione di questi casi nel tuo backend.

Verificare la presenza di diritti esistenti

Un utente potrebbe aver utilizzato un codice promozionale o avere già un abbonamento al prodotto. Per verificare che l'utente disponga dei diritti appropriati, puoi chiamare il comando listPurchases() sul servizio di beni digitali. Verranno restituiti tutti gli acquisti effettuati dal tuo cliente nella tua app. Qui potrai anche confermare gli acquisti non confermati per garantire che l'utente utilizzi correttamente i propri diritti.

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

Carica nel Play Store di ChromeOS

Le attività web attendibili sono disponibili anche a partire da Chrome 85 nel Play Store di ChromeOS. La procedura per elencare la tua app nello store è la stessa per ChromeOS e per Android.

Una volta creato l'app bundle, Play Console ti guiderà nei passaggi richiesti per elencare l'app sul Play Store. Nella documentazione di Play Console puoi trovare assistenza per creare la scheda dell'app, gestire i file APK e altre impostazioni, nonché istruzioni per testare e rilasciare in modo sicuro la tua app.

Per limitare l'applicazione solo ai Chromebook, aggiungi il flag --chromeosonly durante l'inizializzazione dell'applicazione in Bubblewrap:

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

Quando crei la tua applicazione manualmente, senza eseguire il wrapping di bolle, aggiungi un flag uses-feature al file manifest Android:

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

Se la tua scheda è condivisa con un'app per Android, la versione del pacchetto solo per ChromeOS dovrà essere sempre superiore a quella del pacchetto app per Android. Puoi impostare la versione del bundle ChromeOS su un numero notevolmente maggiore rispetto alla versione Android, in modo da non dover aggiornare entrambe le versioni a ogni release.