Thông tin mới về Web In Play

Kể từ khi Hoạt động đáng tin cậy trên web được ra mắt vào năm ngoái, nhóm Chrome vẫn tiếp tục phát triển sản phẩm này, giúp sản phẩm này giúp bạn sử dụng dễ dàng hơn với Bubblewrap, bổ sung các tính năng mới như tính năng tích hợp Google Play Billing sắp ra mắt và cho phép sản phẩm này hoạt động trên nhiều nền tảng hơn, chẳng hạn như ChromeOS. Bài viết này sẽ tóm tắt các nội dung cập nhật mới nhất và sắp tới cho Hoạt động đáng tin cậy trên web.

Các tính năng mới như bong bóng trò chuyện và Hoạt động đáng tin cậy trên web

Bubblewrap giúp bạn tạo các ứng dụng chạy PWA trong một Hoạt động đáng tin cậy trên web mà không cần biết về công cụ dành riêng cho nền tảng.

Quy trình thiết lập được đơn giản hoá

Trước đây, để sử dụng Bubblewrap, bạn phải thiết lập Bộ phát triển Java và SDK Android theo cách thủ công, cả hai đều dễ gặp lỗi. Công cụ này hiện cho phép tự động tải các phần phụ thuộc bên ngoài xuống khi chạy lần đầu tiên.

Nếu muốn, bạn vẫn có thể chọn sử dụng bản cài đặt hiện có các phần phụ thuộc. Đồng thời, lệnh doctor mới sẽ giúp tìm các vấn đề và đề xuất bản sửa lỗi cho cấu hình. Bạn hiện có thể cập nhật cấu hình này qua dòng lệnh bằng lệnh updateConfig.

Trình hướng dẫn được cải tiến

Khi tạo một dự án bằng init, Bubblewrap cần thông tin để tạo ứng dụng Android. Công cụ này trích xuất các giá trị từ Tệp kê khai ứng dụng web và cung cấp các giá trị mặc định nếu có thể.

Bạn có thể thay đổi các giá trị đó khi tạo một dự án mới, nhưng trước đây ý nghĩa của từng trường chưa rõ ràng. Các hộp thoại khởi động đã được tạo lại với nội dung mô tả và kết quả xác thực tốt hơn cho từng trường đầu vào.

display: hỗ trợ toàn màn hình và hướng

Trong một số trường hợp, bạn có thể muốn ứng dụng sử dụng nhiều không gian màn hình nhất có thể. Khi tạo PWA, bạn có thể triển khai việc này bằng cách đặt trường display từ Tệp kê khai ứng dụng web thành fullscreen.

Khi phát hiện thấy tuỳ chọn toàn màn hình trong Tệp kê khai ứng dụng web, Bubblewrap sẽ định cấu hình ứng dụng Android để khởi chạy ở chế độ toàn màn hình, hay còn gọi là chế độ chìm, theo thuật ngữ cụ thể của Android.

Trường orientation từ Tệp kê khai ứng dụng web sẽ xác định xem nên khởi động ứng dụng ở chế độ dọc, chế độ ngang hay theo hướng mà thiết bị hiện đang sử dụng. Giờ đây, Bubblewrap sẽ đọc trường Tệp kê khai ứng dụng web và sử dụng trường này làm trường mặc định khi tạo ứng dụng Android.

Bạn có thể tuỳ chỉnh cả hai cấu hình trong quy trình bubblewrap init.

Kết quả đầu ra của AppBundle

Gói ứng dụng là một định dạng xuất bản cho các ứng dụng uỷ quyền việc tạo tệp APK cuối cùng và đăng nhập vào Play. Trên thực tế, điều này cho phép phân phát các tệp nhỏ hơn cho người dùng khi tải ứng dụng xuống từ cửa hàng.

Giờ đây, tính năng Bubblewrap sẽ đóng gói ứng dụng dưới dạng một App Bundle trong một tệp có tên là app-release-bundle.aab. Bạn nên ưu tiên sử dụng định dạng này khi phát hành ứng dụng lên Cửa hàng Play vì cửa hàng bắt buộc phải sử dụng định dạng này kể từ nửa cuối năm 2021.

Uỷ quyền vị trí địa lý

Người dùng mong muốn các ứng dụng cài đặt trên thiết bị của họ hoạt động nhất quán, bất kể công nghệ. Khi được dùng trong một Hoạt động đáng tin cậy trên web, quyền GeoLocation hiện có thể được uỷ quyền cho Hệ điều hành. Khi được bật, người dùng sẽ thấy các hộp thoại tương tự như các ứng dụng được tạo bằng Kotlin hoặc Java, đồng thời tìm các chế độ điều khiển để quản lý quyền ở cùng một nơi.

Bạn có thể thêm tính năng này thông qua Bubblewrap và vì tính năng này thêm các phần phụ thuộc bổ sung vào dự án Android, nên bạn chỉ nên bật tính năng này khi ứng dụng web đang sử dụng quyền Định vị vị trí.

Tệp nhị phân được tối ưu hoá

Thiết bị có bộ nhớ hạn chế phổ biến ở một số khu vực trên thế giới và chủ sở hữu thiết bị đó thường thích các ứng dụng nhỏ hơn. Các ứng dụng sử dụng Hoạt động đáng tin cậy trên web tạo ra các tệp nhị phân nhỏ, giúp loại bỏ phần nào lo lắng của những người dùng đó.

Bubblewrap đã được tối ưu hoá bằng cách giảm danh sách các thư viện Android cần thiết, nhờ đó tạo ra các tệp nhị phân có kích thước nhỏ hơn 800k. Trên thực tế, kích thước đó chưa bằng một nửa kích thước trung bình do các phiên bản trước tạo ra. Để tận dụng các tệp nhị phân nhỏ hơn, bạn chỉ cần cập nhật ứng dụng của mình bằng phiên bản Bubblewrap mới nhất.

Cách cập nhật ứng dụng hiện có

Một ứng dụng do Bubblewrap tạo bao gồm một ứng dụng web và một trình bao bọc Android gọn nhẹ mở PWA. Mặc dù PWA được mở trong Hoạt động đáng tin cậy trên web tuân theo cùng chu kỳ cập nhật như mọi ứng dụng web khác, nhưng trình bao bọc gốc có thể và phải được cập nhật.

Bạn nên cập nhật ứng dụng của mình để đảm bảo ứng dụng đang sử dụng phiên bản trình bao bọc mới nhất, với các tính năng và bản sửa lỗi mới nhất. Khi đã cài đặt phiên bản mới nhất của Bubblewrap, lệnh update sẽ áp dụng phiên bản mới nhất của trình bao bọc cho một dự án hiện có:

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

Một lý do khác để cập nhật các ứng dụng đó là đảm bảo rằng các thay đổi đối với Tệp kê khai web đều được áp dụng cho ứng dụng. Hãy dùng lệnh merge mới để làm việc đó:

bubblewrap merge
bubblewrap update
bubblewrap build

Nội dung cập nhật đối với Tiêu chí chất lượng

Chrome 86 đã áp dụng các thay đổi đối với Tiêu chí chất lượng hoạt động đáng tin cậy trên web. Tiêu chí này được giải thích đầy đủ trong bài viết Các thay đổi về tiêu chí chất lượng đối với PWA sử dụng Hoạt động trên web đáng tin cậy.

Tóm tắt nhanh là bạn nên đảm bảo ứng dụng của mình xử lý được các tình huống sau đây để ngăn sự cố:

  • Không xác minh được đường liên kết đến tài sản kỹ thuật số khi chạy ứng dụng
  • Không trả về được HTTP 200 cho yêu cầu tài nguyên mạng ngoại tuyến
  • Trả về lỗi HTTP 404 hoặc 5xx trong ứng dụng.

Bên cạnh việc đảm bảo ứng dụng vượt qua quy trình xác thực Đường liên kết đến tài sản kỹ thuật số, một trình chạy dịch vụ có thể xử lý các trường hợp còn lại:

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

Hộp công việc xử lý các phương pháp hay nhất và loại bỏ mã nguyên mẫu khi sử dụng trình chạy dịch vụ. Ngoài ra, hãy cân nhắc sử dụng trình bổ trợ Workbox để xử lý các trường hợp đó:

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 Billing

Ngoài việc cho phép ứng dụng bán hàng hoá kỹ thuật số và gói thuê bao trên Cửa hàng Play, Google Play Billing còn cung cấp các công cụ để quản lý danh mục, giá và gói thuê bao, báo cáo hữu ích, cũng như quy trình thanh toán đã quen thuộc với người dùng của bạn trên Cửa hàng Play. Đây cũng là yêu cầu đối với các ứng dụng xuất bản trên Cửa hàng Play bán hàng hoá kỹ thuật số.

Chrome 88 sẽ ra mắt với bản dùng thử theo nguyên gốc trên Android cho phép tích hợp Hoạt động đáng tin cậy trên web, API yêu cầu thanh toánAPI hàng hoá kỹ thuật số để triển khai quy trình mua qua Google Play Billing. Chúng tôi dự kiến bản dùng thử này cũng sẽ áp dụng cho ChromeOS từ phiên bản 89.

Lưu ý quan trọng: API Google Play Billing có thuật ngữ riêng, đồng thời bao gồm các thành phần ứng dụng khách và phần phụ trợ. Phần này chỉ đề cập đến một phần nhỏ của API dành riêng cho việc sử dụng API Hàng hoá kỹ thuật số và Hoạt động trên web đáng tin cậy. Hãy nhớ đọc tài liệu về Google Play Billing và hiểu rõ các khái niệm của tài liệu đó trước khi tích hợp vào ứng dụng chính thức.

Quy trình cơ bản

Trình đơn Play Console

Để cung cấp hàng hoá kỹ thuật số qua Cửa hàng Play, bạn cần định cấu hình danh mục trên Cửa hàng Play, cũng như kết nối Cửa hàng Play làm phương thức thanh toán qua PWA của bạn.

Khi bạn đã sẵn sàng định cấu hình danh mục của mình, hãy bắt đầu bằng cách tìm phần Sản phẩm ở trình đơn bên trái trên Play Console:

Tại đây, bạn sẽ thấy tuỳ chọn xem các gói thuê bao và sản phẩm trong ứng dụng hiện có, cũng như nút tạo để thêm sản phẩm và gói thuê bao mới.

Sản phẩm trong ứng dụng

Chi tiết sản phẩm

Để tạo một sản phẩm mới trong ứng dụng, bạn cần có mã sản phẩm, tên, nội dung mô tả và giá. Điều quan trọng là bạn phải tạo các mã sản phẩm có ý nghĩa và dễ nhớ. Sau này, bạn sẽ cần dùng các mã này và bạn không thể thay đổi mã nhận dạng sau khi tạo.

Khi tạo gói thuê bao, bạn cũng sẽ phải chỉ định kỳ thanh toán. Bạn có thể liệt kê các lợi ích của gói thuê bao và thêm các tính năng như có dùng thử miễn phí, giá ưu đãi, thời gian ân hạn và lựa chọn đăng ký lại hay không.

Sau khi tạo từng sản phẩm, hãy kích hoạt các sản phẩm đó trong ứng dụng của bạn.

Nếu muốn, bạn có thể thêm sản phẩm qua API Nhà phát triển Play.

Sau khi định cấu hình danh mục, bước tiếp theo là định cấu hình quy trình thanh toán qua PWA. Bạn sẽ sử dụng kết hợp Digital Merchandise APIPayment Request API (API Yêu cầu thanh toán) để đạt được mục tiêu này.

Tìm nạp giá sản phẩm bằng Digital Merchandise API

Khi sử dụng Google Play Billing, bạn cần đảm bảo rằng giá mà người dùng nhìn thấy khớp với giá tại trang thông tin trên Cửa hàng Play. Sẽ không thể đồng bộ hoá những mức giá đó theo cách thủ công, vì vậy, Digital Merchandise API cung cấp một cách để ứng dụng web truy vấn nhà cung cấp dịch vụ thanh toán cơ bản về giá:

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

Bạn có thể phát hiện khả năng hỗ trợ Digital Merchandise API bằng cách kiểm tra xem getDigitalGoodsService() có trên đối tượng window hay không.

Sau đó, hãy gọi window.getDigitalGoodsService() bằng giá trị nhận dạng Google Play Billing làm thông số. Thao tác này sẽ trả về một bản sao dịch vụ cho Google Play Billing và các nhà cung cấp khác có thể triển khai tính năng hỗ trợ cho Digital Merchandise API và sẽ có các giá trị nhận dạng khác nhau.

Cuối cùng, hãy gọi getDetails() trên tham chiếu đến đối tượng Google Play Billing chuyển SKU cho mặt hàng dưới dạng tham số. Phương thức này sẽ trả về một đối tượng chi tiết chứa cả giá và đơn vị tiền tệ của mặt hàng có thể hiển thị cho người dùng.

Bắt đầu quy trình mua

API yêu cầu thanh toán cho phép các quy trình mua hàng trên web và cũng được dùng để tích hợp Google Play Billing. Hãy xem bài viết Cách hoạt động của API yêu cầu thanh toán để tìm hiểu thêm nếu bạn mới sử dụng API yêu cầu thanh toán.

Để sử dụng API này với Google Play Billing, bạn cần thêm một phương thức thanh toán có một phương thức thanh toán được hỗ trợ tên là https://play.google.com/billing và thêm SKU dưới dạng một phần dữ liệu cho phương thức này:

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

Sau đó, tạo đối tượng PaymentRequest như bình thường và sử dụng API như bình thường

const request = new PaymentRequest(supportedInstruments, details);

Xác nhận giao dịch mua

Sau khi giao dịch hoàn tất, bạn cần sử dụng Digital Merchandise API để xác nhận giao dịch thanh toán. Đối tượng phản hồi từ PaymentRequest sẽ chứa mã thông báo mà bạn sẽ dùng để xác nhận giao dịch:

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 Merchandise API và Payment Request API không biết danh tính của người dùng. Do đó, bạn phải liên kết giao dịch mua với người dùng trong phần phụ trợ và đảm bảo họ có quyền truy cập vào các mặt hàng đã mua. Khi liên kết giao dịch mua hàng với một người dùng, hãy nhớ lưu mã thông báo giao dịch mua, vì bạn có thể cần mã này để xác minh xem giao dịch mua đã bị huỷ hoặc được hoàn tiền hay chưa, hay gói thuê bao vẫn đang hoạt động. Hãy xem API Thông báo theo thời gian thực dành cho nhà phát triểnAPI Nhà phát triển Google Play vì chúng cung cấp các điểm cuối để xử lý những trường hợp đó trong phần phụ trợ.

Kiểm tra các quyền hiện có

Người dùng có thể đã sử dụng mã khuyến mãi hoặc có thể đang dùng gói thuê bao sản phẩm của bạn. Để xác thực rằng người dùng có các quyền thích hợp, bạn có thể gọi lệnh listPurchases() trên dịch vụ hàng hoá kỹ thuật số. Thao tác này sẽ trả về tất cả các giao dịch mua mà khách hàng đã thực hiện trong ứng dụng của bạn. Đây cũng sẽ là nơi xác nhận mọi giao dịch mua chưa được xác nhận nhằm đảm bảo rằng người dùng sử dụng đúng các quyền của họ.

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

Tải lên Cửa hàng Play của ChromeOS

Hoạt động đáng tin cậy trên web cũng được cung cấp kể từ Chrome 85 trong Cửa hàng Play của ChromeOS. Quy trình đăng ứng dụng của bạn trong cửa hàng trên ChromeOS giống như quy trình cho Android.

Sau khi bạn tạo gói ứng dụng, Play Console sẽ hướng dẫn bạn thực hiện các bước bắt buộc để đưa ứng dụng lên Cửa hàng Play. Trong tài liệu của Play Console, bạn có thể tìm thấy thông tin trợ giúp để tạo trang thông tin ứng dụng, quản lý tệp APK và các chế độ cài đặt khác, cũng như hướng dẫn kiểm thử và phát hành ứng dụng một cách an toàn.

Để hạn chế ứng dụng chỉ chạy trên Chromebook, hãy thêm cờ --chromeosonly khi khởi chạy ứng dụng trong Bubblewrap:

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

Khi tạo ứng dụng theo cách thủ công mà không có Bubblewrap, hãy thêm một cờ uses-feature vào tệp kê khai Android:

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

Nếu trang thông tin của bạn được chia sẻ với một ứng dụng Android, thì phiên bản gói chỉ dành cho ChromeOS sẽ luôn phải cao hơn phiên bản gói ứng dụng Android. Bạn có thể thiết lập phiên bản gói ChromeOS ở số lượng cao hơn so với phiên bản Android, nhờ đó, bạn không phải cập nhật cả hai phiên bản với mỗi bản phát hành.