Co nowego w aplikacjach internetowych w Google Play

Data publikacji: 2 grudnia 2020 r.

Od czasu wprowadzenia zaufanej aktywności w internecie zespół Chrome ułatwił korzystanie z Bubblewrap. Dodaliśmy dodatkowe funkcje, takie jak integracja z systemem płatności Google Play, i uruchomiliśmy ją na większej liczbie platform, np. na ChromeOS.

Funkcje Bubblewrap i zaufanej aktywności w internecie

Bubblewrap pomaga tworzyć aplikacje, które uruchamiają PWA w ramach zaufanej aktywności internetowej, bez konieczności znajomości narzędzi do obsługi poszczególnych platform.

Uproszczony proces konfiguracji

Wcześniej korzystanie z Bubblewrap wymagało ręcznej konfiguracji pakietu Java Development Kit i pakietu SDK Androida, które są podatne na błędy. Narzędzie umożliwia teraz automatyczne pobieranie zewnętrznych zależności podczas pierwszego uruchomienia.

Jeśli chcesz, możesz nadal używać dotychczasowej instalacji zależności. Nowe polecenie doctor pomaga znajdować problemy i zaleca poprawki konfiguracji, którą można teraz aktualizować z poziomu wiersza poleceń za pomocą polecenia updateConfig.

Ulepszone kreator

Podczas tworzenia projektu za pomocą init Bubblewrap potrzebuje informacji, aby wygenerować aplikację na Androida. Narzędzie wyodrębnia wartości z pliku manifestu aplikacji internetowej i w miarę możliwości podaje wartości domyślne.

Wartości te możesz zmienić podczas tworzenia nowego projektu, ale wcześniej znaczenie poszczególnych pól nie było jasne. Okna inicjowania zostały przebudowane, aby zawierały lepsze opisy i sprawdzanie poprawności dla każdego pola danych.

Obsługa trybu pełnoekranowego i orientacji

W niektórych przypadkach możesz chcieć, aby aplikacja zajmowała jak najwięcej miejsca na ekranie. W przypadku tworzenia aplikacji PWA można to zaimplementować, ustawiając pole display w pliku manifestu aplikacji internetowej na fullscreen.

Gdy Bubblewrap wykryje opcję pełnego ekranu w pliku manifestu aplikacji internetowej, skonfiguruje aplikację na Androida tak, aby uruchamiała się również w trybie pełnoekranowym (w terminologii Androida: trybie pełnoekranowym).

Pole orientation w pliku manifestu aplikacji internetowej określa, czy aplikacja ma być uruchamiana w orientacji pionowej, poziomej czy w orientacji urządzenia. Bubblewrap odczytuje teraz pole pliku manifestu aplikacji internetowej i użyje go jako domyślnego podczas tworzenia aplikacji na Androida.

Obie konfiguracje możesz dostosować w ramach procesu bubblewrap init.

Dane wyjściowe pakietu aplikacji

Pakiety aplikacji to format publikowania aplikacji, który deleguje generowanie i podpisywanie ostatecznego pliku APK do Google Play. W praktyce oznacza to, że użytkownicy otrzymują mniejsze pliki podczas pobierania aplikacji ze sklepu.

Bubblewrap pakuje teraz aplikację jako pakiet aplikacji w pliku o nazwie app-release-bundle.aab. Ten format powinieneś preferować podczas publikowania aplikacji w Sklepie Play, ponieważ jest on wymagany przez sklep od 2021 roku.

Delegowanie geolokalizacji

Użytkownicy oczekują, że aplikacje zainstalowane na ich urządzeniach będą działać w sposób spójny, niezależnie od technologii. W ramach zaufanej aktywności w internecie uprawnienia GeoLocation można teraz delegować do systemu operacyjnego. Gdy są włączone, użytkownicy widzą te same okna dialogowe co w przypadku aplikacji napisanych w językach Kotlin lub Java. W tym samym miejscu mogą też zarządzać tymi uprawnieniami.

Funkcję można dodać za pomocą Bubblewrap. Ponieważ powoduje ona dodatkowe zależności w projekcie na Androida, należy ją włączyć tylko wtedy, gdy aplikacja internetowa używa uprawnienia Lokalizacja geograficzna.

Zoptymalizowane pliki binarne

Urządzenia z ograniczoną ilością pamięci są popularne w niektórych regionach świata, a ich właściciele często preferują mniejsze aplikacje. Aplikacje korzystające z zaufanej aktywności w internecie generują małe pliki binarne, co zmniejsza obawy użytkowników.

Bubblewrap został zoptymalizowany przez zmniejszenie listy potrzebnych bibliotek Androida, co spowodowało, że wygenerowane pliki binarne są mniejsze o 800 kB. W praktyce jest to mniej niż połowa średniego rozmiaru generowanego przez poprzednie wersje. Aby korzystać z mniejszych plików binarnych, wystarczy zaktualizować aplikację za pomocą najnowszej wersji Bubblewrap.

Jak zaktualizować istniejącą aplikację

Aplikacja wygenerowana przez Bubblewrap składa się z aplikacji internetowej i lekkiego opakowania na Androida, które otwiera PWA. Mimo że PWA otwierana w ramach zaufanej aktywności w przeglądarce podlega tym samym cyklom aktualizacji co inne aplikacje internetowe, natywny kontent można i należy aktualizować.

Zaktualizuj aplikację, aby mieć pewność, że korzysta ona z najnowszej wersji oprawy z najnowszymi poprawkami i funkcjami. Po zainstalowaniu najnowszej wersji Bubblewrap polecenie update stosuje najnowszą wersję oprogramowania do pakowania do istniejącego projektu:

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

Kolejnym powodem aktualizacji tych aplikacji jest zapewnienie, że zmiany w pliku manifestu internetowego zostaną zastosowane w aplikacji. Użyj nowego polecenia merge:

bubblewrap merge
bubblewrap update
bubblewrap build

Zmiany kryteriów jakości

W Chrome 86 wprowadzono zmiany w kryteriach jakości zaufanej aktywności internetowej. Więcej informacji znajdziesz w artykule Zmiany kryteriów jakości aplikacji PWA korzystających z zaufanej aktywności internetowej.

Aby zapobiec awariom aplikacji, musisz się upewnić, że obsługują one te scenariusze:

  • Nie udało się zweryfikować linków do zasobów cyfrowych podczas uruchamiania aplikacji
  • Niemożność zwrócenia kodu 200 HTTP w przypadku żądania zasobu sieciowego w trybie offline
  • zwracanie w aplikacji błędu HTTP 404 lub 5xx;

Oprócz sprawdzania, czy aplikacja przechodzi weryfikację Digital Asset Links, pozostałe scenariusze mogą być obsługiwane przez service workera:

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 wykorzystuje sprawdzone metody i eliminuje powtarzające się fragmenty kodu podczas korzystania z usług działających w tle. Możesz też skorzystać z wtyczki Workbox, aby obsłużyć te scenariusze:

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