This article was originally published at github.com/bigo-fronte… Welcome attention, reprint.

Bigo Likee overseas products to find new growth breakthrough, in the technical side to try THE PWA program, but also gained a lot of experience, now summary to share.

1. What is PWA?

PWA (Progressive Web Apps) uses modern Web apis as well as traditional Progressive enhancement strategies to create cross-platform Web applications.

How do you understand progressive?

  • Build incrementally. The standards that make up the PWA all come from Web technologies that are backward compatible with browsers and have no additional runtime costs. Therefore, any Web page developed in an existing framework can be transformed into a PWA, without a complete refactoring of the existing code, and can be gradually migrated and improved.
  • Incremental enhancement. Browser manufacturers will gradually provide support for THE PWA-related APIS, and users of modern browsers will benefit over time, without breaking anything for users of older browsers.

2. What can PWA do?

  • Installation Adds a desktop icon
  • Provide front-end network proxy
  • The response is cached using the cache API
  • Sending push Notifications

Receiving server push

3. How PWA works

The PWA implements the above functions by relying on the capabilities provided by the service worker.

A service worker is a type of Web worker, which is JS code that runs in a separate thread. The full lifecycle of a service worker is shown in the figure below.

To use a service worker, follow these basic steps:

  • Service worker through serviceWorkerContainer URL. The register () to obtain and registration.
  • If registered successfully, the service worker runs in the ServiceWorkerGlobalScope environment. This is a special type of worker context running environment that is independent of the main running thread (execution script) and has no DOM access capability.
  • The service worker can now handle events.

The page controlled by the service worker opens and attempts to install the service worker. The first event sent to the service worker is the installation event.

  • When the onInstall event handler finishes executing, the service worker installation is considered complete.
  • The next step is activation. When the service worker is installed, it receives an activate Event. The main purpose of onActivate is to clean up resources used in the previous version of the service Worker script.
  • The service worker can now control the page, but only the page that opens after register() succeeds.

The example code is as follows:

navigator.serviceWorker.register(opts.url).then(function(registration) {
  console.log("Service worker successfully registered.");
})
Copy the code

4. Basic encapsulation methods for processing services

To handle business, we encapsulate the basic methods associated with service workers

The main thread js is encapsulated as follows:

/**
 * service worker sdk
 * 
 * @param {string} Opts.url [required] Address of the SW file *@param {function} Opts.onready [optional] SW Registration succeeded *@param {function} Opts. OnBeforeInstallPrompt [optional] not installed pwa event trigger *@param {function} Click install opts. OnClickInstallPrompt [optional] confirmation popup window *@param {function} Opts.oninstalled [optional] This function is triggered when the PWA is successfully installed@param {function} Opts. OnNotificationPermission [optional] * * / authorized confirmation popup window click on the notification
export function SWSdk(opts) {
  /** * Initialize sw */
  /** * sw registration succeeded */
  /** * PWA event trigger is not installed */
  /** * Triggers when the pWA is successfully installed
  /** * The installation confirmation window is displayed */
  /** * Listen for sw events */
  /** * Triggers the SW event */
  /** * The notification authorization confirmation window is displayed */
  /** * Send a notification */
  /** * Cache resources */
  /** * Delete cache resources */
}
Copy the code

The sw thread js package is as follows:

/**
 * SW
 * 
 * @param {string} Opts.CACHE_NAME [optional] Cache namespace. You are advised to name each application independently@param {number} Opts. TickTime [Optional] Interval of each tick, in ms. The default value is 1000 x@param {function} Opts. OnTick [Optional] Calls * at an interval@param {function} Opts. OnProxy [optional] Proxy network request *@param {function} Opts.oninstall [optional] Callback to the installation event *@param {function} Opts. OnActivate [Optional] Callback to activate an event *@param {function} Opts. OnPush [optional] Callback for receiving an event from the server *@param {function} Opts. NotificationOnClick [Optional] Click callback */ for a push notification
var SW = function (opts) {
  /** * Initialize sw */
  /** * Listen for window events */
  /** * Triggers window events */
  /** * Set cache */
  /** * Get cache */
  /** * Send a notification */
};
Copy the code

The encapsulation of the Service Worker API allows us to focus more on business.

The basic methods of encapsulation are:

A. Inter-thread communication. Frequent communication is required between the main thread and the service worker thread, so a friendly communication method needs to be encapsulated

The main thread:

/** * Listen for sw events **@param {string} EventName [required] eventName *@param {function} Handler [required] The handler function */
this.on = function(eventName, handler) {
  this.eventListener.push({
    eventName: eventName,
    handler: handler
  })
};
/** * Triggers the SW event **@param {string} EventName [required] eventName *@param {any} Payload [optional] Specifies the data to be passed
this.emit = function(eventName, payload) {
  const data = {
    eventName: eventName,
    payload: payload
  };
  try {
    if (navigator.serviceWorker.controller) {
      navigator.serviceWorker.controller.postMessage(data);
    } else {
      navigator.serviceWorker.addEventListener("controllerchange".() = >{ navigator.serviceWorker.controller.postMessage(data); }); }}catch(err) {
    console.error(err); }}Copy the code

Service worker thread:

/** listen for window events **@param {string} EventName [required] eventName *@param {function} Handler [required] The handler function */
this.on = function(eventName, handler) {
  this.eventListener.push({
    eventName: eventName,
    handler: handler
  })
};
/** * Triggers window events **@param {string} EventName [required] eventName *@param {any} Payload [optional] Specifies the data to be passed
this.emit = function(eventName, payload) {
  clients.matchAll({
    type: 'window'.includeUncontrolled: true
  }).then(function(matchClient) {
    matchClient.forEach(function(client) {
      client.postMessage({
        eventName: eventName,
        payload: payload }); })}); };Copy the code

B. Local storage. In the service worker thread, we cannot use cookie, localStorage, and sessionStorage. We can only use the Cache API or indexDB as the carrier for storing key-value data.

/** * Set cache **@param {string} Key Cache key *@param {any} Value Cache value */
this.setCache = function (key, value) {
  try {
    return caches.open(this.CACHE_NAME).then(function(cache) {
      return cache.put(key, newResponse(value)); })}catch (err) {
    const that = this;
    return new Promise(function(resolve) {
      if(! that.cacheStorage[that.CACHE_NAME]) { that.cacheStorage[that.CACHE_NAME] = {}; } that.cacheStorage[that.CACHE_NAME][key] = value; resolve(); })}};/** * Get cache **@param {string} Key Cache key */
this.getCache = function(key) {
  try {
    return caches.open(this.CACHE_NAME).then(function(cache) {
      return cache.match(key);
    }).then(function(response) {
      return response ? response.text() : ' '; })}catch (err) {
    const that = this;
    return new Promise(function(resolve) {
      resolve(new String(that.cacheStorage[that.CACHE_NAME][key])); })}};Copy the code

The Cache API does not store key-value data directly. It can only store URL-response data. We use a few tricks to make it store key-value data

C. inform

The main thread applies for authorization

/** * The notification authorization confirmation window is displayed */
this.requestNotificationPermission = function() {
  Notification.requestPermission().then((result) = > {
    that.onNotificationPermission.bind(that)(result);
  });
};
Copy the code

The service worker thread sends notifications

/** * Send a notification **@param {object} params [required]
 * @param {string} Params.title [required] Title *@param {string} Params.desc [optional] Description *@param {string} Params. icon [optional] Icon *@param {any} Params.data [optional] Pass parameter *@param {string} Params. url [optional] Click */
this.showNotification = function(params) {
  try {
    self.registration.showNotification(params.title, {
      body: params.desc,
      icon: params.icon,
      image: params.image,
      data: Object.assign({ url: params.url }, params.data)
    })
  } catch (err) {
    console.log(err); }};Copy the code

5. Business needs and countermeasures

This section is too much content, do not expand in detail, interested in private chat

A. Install the desktop shortcut

  • Uninstalled Events
  • A pop-up query is displayed asking you to install the popover API

B. Local push notifications

  • Ask the authorization notification API
  • Send a notification

C. SW buried point

  • Fetch api
  • Request data construction

D. Pull the PWA on the desktop

  • You need to install the Google Play service
  • Redirect redirect needs to be initiated from pages in different domains
  • Links that are in the same domain as the PWA can pull up the PWA, and the PWA displays jump links, not those specified in the start_URL
  • Page transfer Strategy

E. Video preloading

  • Using the cache API

F. Identify whether the user accesses a Web page or a desktop PWA

  • Desktop entry pull live
  • Links to pull live

6. Problems encountered

A. Compatibility issues

The compatibility of PWA is poor. Almost every API has compatibility problems and needs to be adapted to different devices. Many of these compatibility problems were discovered by looking at online statistics

B. Statistics

In order to count the pWA conversion effect, we need to identify whether the user visits the Web page or the pWA of the desktop. However, we can only count the users whose desktop icon is opened and the PWA users whose link is pulled. We cannot identify the scenes of push and pull by the third-party app.

Welcome to leave a message and discuss, I wish a smooth work, happy life!

I’m bigo front end, see you next time.