網頁版 Google Play 的新功能'

發布日期:2020 年 12 月 2 日

自從推出Trusted Web Activity 後,Chrome 團隊已簡化 Bubblewrap 的使用方式。我們新增了其他功能,例如Google Play 帳款服務整合,並讓這項服務能夠在更多平台上運作,例如 ChromeOS

Bubblewrap 和 Trusted Web Activity 功能

Bubblewrap 可協助您建立應用程式,在信任的網頁活動中啟動 PWA,無須瞭解特定平台的工具。

簡化設定流程

先前,使用 Bubblewrap 需要手動設定 Java Development Kit 和 Android SDK,這兩者都容易發生錯誤。這項工具現在會在首次執行時自動下載外部依附元件。

您仍可選擇使用現有的依附元件安裝作業 (如果您偏好這樣做),而新的 doctor 指令可協助找出問題,並建議修正設定,現在您可以透過指令列使用 updateConfig 指令更新設定。

改善精靈

使用 init 建立專案時,Bubblewrap 需要產生 Android 應用程式所需的資訊。這項工具會從 Web App 資訊清單擷取值,並在可行時提供預設值。

您可以在建立新專案時變更這些值,但先前各欄位的含義並不明確。我們重新建構了初始化對話方塊,為每個輸入欄位提供更完善的說明和驗證機制。

顯示全螢幕和螢幕方向支援

在某些情況下,您可能希望應用程式盡可能使用螢幕的所有空間,在建構 PWA 時,您可以將 display 欄位從網頁應用程式資訊清單設為 fullscreen,實現這項功能。

當 Bubblewrap 在 Web 應用程式資訊清單中偵測到全螢幕選項時,就會將 Android 應用程式設為以全螢幕模式 (或以 Android 專屬術語來說,就是「沉浸式模式」) 啟動。

網頁應用程式資訊清單中的 orientation 欄位會定義應用程式應以直向模式、橫向模式,還是裝置目前使用的方向啟動。Bubblewrap 現已讀取網頁應用程式資訊清單欄位,並在建立 Android 應用程式時將其用作預設值。

您可以自訂這兩種設定,並納入 bubblewrap init 流程中。

AppBundles 輸出內容

App Bundle 是一種應用程式發布格式,可將產生及簽署最終 APK 的作業委派給 Play。實際上,這可讓使用者在從商店下載應用程式時,取得較小的檔案。

Bubblewrap 會將應用程式封裝為應用程式軟體包,並儲存在名為 app-release-bundle.aab 的檔案中。發布應用程式至 Play 商店時,建議您使用這個格式,因為 商店自 2021 年起就要求使用這個格式。

地理位置委派

無論技術為何,使用者都希望在裝置上安裝的應用程式能夠一致運作。在信任的 Web Activity 中使用時,現在可以將 GeoLocation 權限委派給作業系統,這樣一來,使用者啟用權限後,就會看到與 Kotlin 或 Java 建構的應用程式相同的對話方塊,並在同一個位置找到用於管理權限的控制項。

這項功能可透過 Bubblewrap 新增,但由於它會為 Android 專案新增額外依附元件,因此您應僅在網頁應用程式使用地理位置權限時啟用這項功能。

最佳化二進位檔

在某些地區,儲存空間有限的裝置很常見,而這些裝置的使用者通常偏好較小的應用程式。使用信任的網路活動的應用程式會產生小型二進位檔,可消除使用者的部分疑慮。

Bubblewrap 已經過最佳化,減少所需 Android 程式庫的清單,產生的二進位檔因此縮小了 800k。實際上,這比先前版本產生的平均大小還要小一半。如要充分利用較小的二進位檔,您只需使用最新版本的 Bubblewrap 更新應用程式即可。

如何更新現有應用程式

Bubblewrap 產生的應用程式由網頁應用程式和可開啟 PWA 的輕量 Android 包裝函式組成。雖然在可信任的網頁活動中開啟的 PWA 會遵循與任何網頁應用程式相同的更新週期,但原生包裝函式可以且應進行更新。

您應更新應用程式,確保應用程式使用的是最新版的包裝函式,並包含最新的錯誤修正和功能。安裝最新版的 Bubblewrap 後,update 指令會將最新版的包裝函式套用至現有專案:

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

更新這些應用程式的另一個原因,是為了確保網頁資訊清單的變更會套用至應用程式。請使用新的 merge 指令:

bubblewrap merge
bubblewrap update
bubblewrap build

品質標準更新

Chrome 86 對受信任網路活動品質標準做出了變更,詳情請參閱「透過受信任網路活動整合 PWA 時的品質標準有所變更」一文。

簡單來說,您必須確保應用程式能夠處理下列情況,以免發生當機情形:

  • 無法在應用程式啟動時驗證數位資產連結
  • 無法針對離線網路資源要求傳回 HTTP 200
  • 應用程式傳回 HTTP 404 或 5xx 錯誤。

除了確保應用程式通過Digital Asset Links 驗證之外,服務工作者還可以處理下列其他情況:

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 會採用最佳做法,並在使用服務工作者時移除常用程式碼。或者,您也可以考慮使用 Workbox 外掛程式來處理這些情況:

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