網頁版 Google Play 的新功能'

自去年推出受信任的網路活動以來,Chrome 團隊持續在 產品,讓 Bubblewrap 使用起來更方便,同時添加了即將推出的 Google Play 等新功能 整合帳單功能,可在 ChromeOS 等更多平台上運作。本文將 總結「受信任的網路活動」的最新與即將推出的更新

全新 Bubblewrap 和「信任的網路活動」功能

Bubblewrap 可協助您建立應用程式,以便在「信任的網路活動」內啟動 PWA 且需具備平台專屬工具的相關知識

簡化設定流程

先前使用 Bubblewrap 必須手動設定 Java Development Kit 和 Android 兩種都很容易出錯這項工具現在提供自動下載 依附元件和依附元件

如有需要,您仍可選擇使用現有的依附元件安裝項目 新的 doctor 指令可協助您找出問題及建議修正設定 現在透過指令列使用 updateConfig 指令更新

更強大的精靈

使用 init 建立專案時,Bubblewrap 需要相關資訊才能產生 Android 應用程式。 工具會從 Web 應用程式資訊清單中擷取值,並盡可能提供預設值。

您可以在建立新專案時變更這些值,但之前每個欄位的意義皆無法 清除。系統已重新建構初始化對話方塊,為每個指令提供更完善的說明和驗證 輸入欄位

螢幕:支援全螢幕和方向

在某些情況下,您可能希望應用程式盡可能使用螢幕。 建構 PWA,做法是將網頁應用程式資訊清單的 display 欄位設為 fullscreen

當 Bubblewrap 在「網頁應用程式資訊清單」中偵測到全螢幕選項時,就會設定 Android 然後以全螢幕模式 (或沉浸模式) 啟動應用程式。

網頁應用程式資訊清單的 orientation 欄位會定義應用程式應該在以下位置啟動: 直向模式、橫向模式,或是裝置目前使用的螢幕方向。立即進行 Bubblewrap 讀取「網頁應用程式資訊清單」欄位,並在建立 Android 應用程式時將其做為預設值使用。

您可以在 bubblewrap init 流程中自訂這兩項設定。

AppBundles 輸出內容

應用程式套件是一種發布格式,會委派最終產生的 APK 和 。如此一來,當使用者下載較小的檔案時 下載自己的應用程式

Bubblewrap 現在將應用程式以 App Bundle 形式封裝,並在名為 app-release-bundle.aab。將應用程式發布到 Play 商店時,建議您採用這種格式 因為商店將於 2021 下半年開始規定

地理位置委派

無論如何 技術。在受信任的網路活動中使用時,GeoLocation 權限現在可以 委派給作業系統;啟用後,使用者就會看到與建構的應用程式相同的對話方塊 Kotlin 或 Java,並找到用來管理權限的控制項。

您可以透過 Bubblewrap 新增這項功能,並因為會為 Android 添加額外的依附元件, 專案,建議只在網頁應用程式使用「地理位置」權限時啟用。

最佳化二進位檔

儲存空間有限的裝置通常於全球特定地區,且擁有者是這些裝置的擁有者 也經常偏好使用小型的應用程式使用受信任的網路活動的應用程式很少 這可以減少這些使用者的焦慮

縮減所需的 Android 程式庫清單,因此系統對 Bubblewrap 進行了最佳化調整,因此 並將產生的二進位檔縮小為 80 萬實務上,低於平均大小的一半 產生的呼叫。只需更新 您的應用程式。

如何更新現有應用程式

Bubblewrap 產生的應用程式是由網頁應用程式和輕量化的 Android 裝置組成 即可開啟 PWA。即使在受信任的網路活動中開啟 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 驗證之外,剩下的 可由 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 能以最佳做法烘焙,並在使用 Service Worker 時移除樣板。 或者,您也可以考慮使用 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,
    });
  }
}

Google Play 帳款服務

除了允許應用程式在 Play 商店中販售數位商品和訂閱項目外, Google Play 帳款服務提供實用工具,協助您管理目錄、價格和訂閱項目, 以及採用 Play 商店技術支援的結帳流程。這項服務 在 Play 商店上發布販售數位商品的應用程式,也必須遵循這項規定。

Chrome 第 88 版將提供 Android 來源試用服務,讓您可以整合 受信任的網路活動Payment Request APIDigital Goods API 給 導入購買流程我們希望這項來源試用方案也能提供 。

重要事項:Google Play Billing API 有專屬的術語,其中包含用戶端和 後端元件本節僅涵蓋 API 的一小部分,且專門針對如何使用 Digital Goods API 和受信任的網路活動請務必詳閱 參閱 Google Play 帳款服務說明文件並瞭解相關概念,再整合至 實際工作環境應用程式

基本流程

Play 管理中心選單

如要透過 Play 商店提供數位商品,請在 Google Play 設定目錄 儲存,並將 Play 商店連結至 PWA 中的付款方式。

準備設定目錄時,請先找出左側的「產品」部分 Play 管理中心的側邊選單:

這裡有查看現有應用程式內商品和訂閱項目的選項,您也可以查看 找到新增按鈕的建立按鈕

應用程式內產品

產品詳細資料

您需要提供產品 ID、名稱、說明和價格,才能建立新的應用程式內商品。是 建立簡單好記的產品 ID 時,您稍後需要使用這些 ID 和 ID 建立後即無法變更。

建立訂閱項目時,您必須指定帳單週期。您可以選擇 列出訂閱福利及新增功能,例如提供免費試用期、 新用戶優惠、寬限期和重新訂閱選項。

建立每項產品後,只要啟用產品,即可在應用程式中加以使用。

如果想透過 Play Developers API 新增產品,

目錄設定完成後,下一步是設定 PWA 的結帳流程。個人中心 將搭配使用 Digital Goods APIPayment Request API 而負責任的 AI 技術做法 有助於達成這項目標

使用 Digital Goods API 擷取產品價格

使用 Google Play 帳款服務時,請確保使用者看到的價格與實際價格一致 商店資訊中的價格我們無法手動讓價格同步 Digital Goods API 可讓網頁應用程式查詢基本款項 供應商價格:

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

您可以檢查 getDigitalGoodsService() 是否為 可用在 window 物件上取得。

然後使用 Google Play 帳款服務 ID 做為參數來呼叫 window.getDigitalGoodsService()。 這項操作會傳回 Google Play 帳款服務的服務執行個體,其他供應商則可導入支援服務 和各種 ID 都不同

最後,請對傳遞 SKU 的 Google Play 帳款服務物件參照呼叫 getDetails() 將商品做為參數使用此方法會傳回包含價格和 商品要向使用者顯示的幣別

啟動購買流程

Payment Request API 會啟用網路上的購買流程,也會用於 Google Play 帳單整合。請參閱 Payment Request API 的運作方式,進一步瞭解您是否第一次使用 Payment Request API。

如要透過 Google Play 帳款服務使用 API,您必須新增付款方式 具有名為 https://play.google.com/billing 的支援指標,並將 SKU 加入資料中 對該樂器來說:

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

接著,照常建構 PaymentRequest 物件,並照常使用 API

const request = new PaymentRequest(supportedInstruments, details);

確認購買交易

交易完成後,您必須使用 Digital Goods API 才能確認 付款。PaymentRequest 的回應物件會包含權杖 確認交易:

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

Digital Goods API 和 Payment Request API 沒有使用者的身分資訊。身為 結果,您可以自行決定要在後端將購買紀錄與使用者建立關聯,並確保 購買商品的存取權。將購買交易與使用者建立關聯時,請記得將 購買憑證,以便您確認交易是否已取消或退款,或 訂閱項目依然有效。查看 Real Time Developer Notifications APIGoogle Play Developer API 會提供端點,以便在後端處理這些情況。

檢查現有授權

使用者可能已兌換促銷代碼,或是目前已訂閱您的產品。於 才能驗證使用者擁有適當的授權,您可以呼叫 listPurchases() 指令。這樣就會傳回您 如果有任何未經通知,我也想在這裡確認 ,確保使用者正確兌換授權。

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

上傳至 ChromeOS Play 商店

自 Chrome 第 85 版起,我們也已在 ChromeOS Play 商店推出「信任的網路活動」。流程 應用程式,在 Chrome OS 和 Android 上的做法相同。

建立應用程式套件後,Play 管理中心會引導您完成所有必要步驟 步驟,在 Play 商店列出應用程式您可以在 Play 管理中心說明文件中尋求協助 建立應用程式資訊、管理您的 APK 檔案和其他設定,以及操作說明 ,用於測試及安全發布應用程式

如果只要應用程式只能在 Chromebook 上使用,請在初始化時新增 --chromeosonly 標記 也就是 Bubblewrap 中的應用程式步驟:

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

在不使用 Bubblewrap 的情況下手動建構應用程式時,請將 uses-feature 標記新增至 Android 資訊清單:

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

如果商店資訊已與 Android 應用程式分享,則僅限 ChromeOS 的套件版本會有以下版本: 必須高於 Android 應用程式套件版本。您可以將 ChromeOS 套件版本設為 因此您不必分別更新 版本。