Wat is er nieuw voor Web in Play?

Gepubliceerd: 2 december 2020

Sinds de introductie van Vertrouwde webactiviteit heeft het Chrome-team het makkelijker gemaakt om deze functie te gebruiken met Bubblewrap. We hebben extra functies toegevoegd, zoals integratie met Google Play Billing, en hebben de app geschikt gemaakt voor meer platforms, zoals ChromeOS.

Bubblewrap- en Vertrouwde webactiviteit-functies

Met Bubblewrap kun je apps maken die je PWA's starten in een vertrouwde webactiviteit, zonder dat je kennis nodig hebt van platformspecifieke tools.

Vereenvoudigd instelproces

Eerder moest je voor het gebruik van Bubblewrap de Java Development Kit en de Android SDK handmatig instellen. Beide zijn foutgevoelig. De tool biedt nu aan om de externe afhankelijkheden automatisch te downloaden wanneer deze voor het eerst wordt uitgevoerd.

U kunt nog steeds een bestaande installatie van de afhankelijkheden gebruiken als u dat wilt. Met de nieuwe opdracht doctor kunt u problemen vinden en aanbevolen oplossingen voor de configuratie krijgen. U kunt de configuratie nu updaten vanaf de opdrachtregel met de opdracht updateConfig.

Verbeterde wizard

Als je een project maakt met init, heeft Bubblewrap informatie nodig om de Android-app te genereren. De tool haalt waarden op uit het web-app-manifest en biedt waar mogelijk standaardwaarden.

Je kunt die waarden wijzigen als je een nieuw project maakt, maar eerder was de betekenis van elk veld niet duidelijk. De initialisatiedialoogvensters zijn opnieuw opgebouwd met betere beschrijvingen en validatie voor elk invoerveld.

Ondersteuning voor weergave op volledig scherm en schermstand

In sommige gevallen wil je dat je app zoveel mogelijk van het scherm gebruikt. Als je PWA's maakt, implementeer je dit door het veld display in het web-app-manifest in te stellen op fullscreen.

Als Bubblewrap de optie voor volledig scherm in het web-app-manifest vindt, wordt de Android-app ingesteld om ook op volledig scherm te worden gestart, of in de immersieve modus, in Android-specifieke termen.

Het veld orientation in het web-app-manifest bepaalt of de app moet worden gestart in de portretmodus, de liggende modus of de stand die het apparaat op dat moment gebruikt. Bubblewrap leest nu het veld Web-app-manifest en gebruikt dit als standaard bij het maken van de Android-app.

Je kunt beide configuraties aanpassen als onderdeel van het bubblewrap init-proces.

Uitvoer van AppBundles

App-bundels is een publicatie-indeling voor apps die de uiteindelijke APK-generatie en -ondertekening delegeert aan Play. In de praktijk kunnen gebruikers hierdoor kleinere bestanden downloaden als ze de app downloaden via de store.

Bubblewrap verpakt de app nu als een app-bundel in een bestand met de naam app-release-bundle.aab. We raden je aan deze indeling te gebruiken als je apps publiceert in de Play Store, omdat dit sinds 2021 vereist is door de Store.

Machtiging voor geolocatie

Gebruikers verwachten dat apps die op hun apparaten zijn geïnstalleerd, zich consistent gedragen, ongeacht de technologie. Als de rechten voor GeoLocation worden gebruikt in een vertrouwde webactiviteit, kunnen ze nu worden gedelegeerd aan het besturingssysteem. Als deze optie aanstaat, zien gebruikers dezelfde dialoogvensters als bij apps die zijn gemaakt met Kotlin of Java en vinden ze bedieningselementen om de rechten op dezelfde plaats te beheren.

De functie kan worden toegevoegd via Bubblewrap. Omdat deze extra afhankelijkheden toevoegt aan het Android-project, moet je deze alleen aanzetten als de web-app het recht Geolocatie gebruikt.

Geoptimaliseerde binaire bestanden

Apparaten met beperkte opslagruimte komen vaak voor in bepaalde delen van de wereld en eigenaren van die apparaten geven vaak de voorkeur aan kleinere apps. Apps die gebruikmaken van vertrouwde webactiviteit, produceren kleine binaire bestanden, waardoor gebruikers zich minder zorgen hoeven te maken.

Bubblewrap is geoptimaliseerd door de lijst met vereiste Android-bibliotheken te verkleinen, wat resulteert in gegenereerde binaire bestanden die 800 kB kleiner zijn. In de praktijk is dat minder dan de helft van de gemiddelde grootte die door eerdere versies werd gegenereerd. Als je de kleinere binaire bestanden wilt gebruiken, hoef je je app alleen maar te updaten met de nieuwste versie van Bubblewrap.

Een bestaande app updaten

Een app die door Bubblewrap wordt gegenereerd, bestaat uit een web-app en een lichte Android-wrapper die de PWA opent. Hoewel de PWA die in een vertrouwde webactiviteit wordt geopend, dezelfde updatecycli volgt als elke web-app, kan en moet de native wrapper worden geüpdatet.

Update je app om te zorgen dat deze de nieuwste versie van de wrapper gebruikt, met de nieuwste bugfixes en functies. Als de nieuwste versie van Bubblewrap is geïnstalleerd, past de opdracht update de nieuwste versie van de wrapper toe op een bestaand project:

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

Een andere reden om deze apps te updaten, is om te zorgen dat wijzigingen in het webmanifest worden toegepast op de app. Gebruik daarvoor de nieuwe opdracht merge:

bubblewrap merge
bubblewrap update
bubblewrap build

Updates van de kwaliteitscriteria

In Chrome 86 zijn wijzigingen aangebracht in de kwaliteitscriteria voor vertrouwde webactiviteiten. Deze worden volledig uitgelegd in Wijzigingen in de kwaliteitscriteria voor PWA's die vertrouwde webactiviteiten gebruiken.

Kort samengevat moet je ervoor zorgen dat je apps de volgende scenario's afhandelen om te voorkomen dat ze crashen:

  • Kan links naar digitale items niet verifiëren bij de lancering van de app
  • Er wordt geen HTTP 200 geretourneerd voor een offline netwerkbronverzoek
  • Retournering van een HTTP 404- of 5xx-fout in de app.

Naast zorgen dat de app de Digital Asset Links-validatie doorstaat, kunnen de resterende scenario's worden afgehandeld door een servicemedewerker:

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 bevat best practices en verwijdert boilerplate bij het gebruik van serviceworkers. Je kunt ook een Workbox-plug-in gebruiken om die scenario's af te handelen:

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