Frontend Development 28 min read

Implementing a Progressive Web App (PWA) for Sharee Mobile: Features, Architecture, and Lessons Learned

This article explains the concept of Progressive Web Apps, compares them with native and traditional web apps, details the implementation of core PWA features such as App Manifest, Service Worker, caching strategies, push notifications, and Workbox best practices, and shares metrics, challenges, and solutions encountered during the Sharee mobile project.

ByteFE
ByteFE
ByteFE
Implementing a Progressive Web App (PWA) for Sharee Mobile: Features, Architecture, and Lessons Learned

Background

Progressive Web Apps (PWA) were introduced by Google at I/O 2016 and landed in 2017 as a set of web technologies aimed at narrowing the gap between web and native apps, providing app‑like experiences. Major browsers (Chrome, Safari, Firefox, Edge) support PWA, and many sites (Twitter, Starbucks, Ele.me, Sina) have reported measurable benefits such as increased user time and revenue.

West Elm saw a 15% increase in usage time and 9% revenue growth after adopting PWA.

Flipkart’s user time tripled and interaction rate rose by 40%.

In theory, any web app can become a PWA by following the standards, offering high ROI due to relatively low implementation effort. However, compatibility issues and scattered documentation have limited large‑scale adoption.

Selection

Web apps suffer from slower load times on weak networks, lack of offline access, and UI constraints, while native apps have high development costs, multiple version maintenance, and limited SEO. PWA aims to bring native‑like features to web apps.

App Types

Four app categories are compared, showing that PWA remains a web app but performs closer to native apps. The goal is not to replace native apps but to enhance web apps for better user experience.

PWA (Progressive Web App)

The official definition is quoted:

Progressive Web Apps use modern web capabilities to deliver an app‑like user experience. They evolve from pages in browser tabs to immersive, top‑level apps, maintaining the web's low friction at every moment.

PWA is not a single technology but a combination of several web technologies that together provide native‑like advantages.

Characteristics

PWA is fast, reliable, and engaging. Fast through resource caching, reliable via offline support, and engaging via immersive UI, home‑screen icons, and push notifications.

Standard Support

According to "Can I use", key technologies such as App Manifest (57.43% support) and Service Worker (72.82% support) have good coverage across browsers and OSes.

App Manifest support: 57.43%

Service Worker support: 72.82%

Notifications API support: 43.3%

Push API support: 72.39%

Background Sync: supported in Chrome 49+

Objectives

The Sharee mobile PWA aims to improve user experience, increase retention, and boost traffic.

Provide a fallback page for offline failures.

Pre‑cache static assets to speed up cold starts.

Add a persistent home‑screen entry to reduce navigation depth.

Push notifications (not yet implemented).

Metrics

Key quantitative indicators include install prompt conversion rates, desktop‑icon traffic share, and static resource load time.

PWA install click / install / cancel rates.

Desktop‑icon (home‑screen) visit proportion.

Static resource load time.

Implementation Details

The following sections describe the technical details of the PWA implementation, covering App Manifest, Service Worker, Push & Notification APIs, and Workbox best practices.

App Manifest

App Manifest is a JSON file that configures icons, name, start URL, display mode, theme color, etc. It enables adding the site to the home screen and shows install prompts.

Screen‑Persistent Icon

Configuring icons and names in the manifest reduces entry depth and provides a native‑like full‑screen experience.

Implementation

Include the manifest in the <head> :

<link rel="manifest" href="/manifest.json">

Example manifest.json (truncated):

// manifest.json
{
  "name": "Sharee PWA",
  "short_name": "Sharee PWA",
  "icons": [
    {"src": "../logo/180.png", "sizes": "180x180", "type": "image/png"},
    {"src": "../logo/192.png", "sizes": "192x192", "type": "image/png"},
    {"src": "../logo/512.png", "sizes": "512x512", "type": "image/png"}
  ],
  "start_url": "/?from=homescreen",
  "scope": "/",
  "display": "standalone",
  "theme_color": "#FFF",
  "background_color": "#FFF"
}
// iOS fallback meta tags
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#fff">
<meta name="apple-mobile-web-app-title" content="Sharee PWA">
<link rel="apple-touch-icon" sizes="180x180" href="../logo/180.jpg">
<meta name="msapplication-TileColor" content="#fff">
<meta name="theme-color" content="#fff">

Install Prompt

When the manifest meets certain criteria, browsers may show an install prompt. The prompt can be intercepted via the beforeinstallprompt event.

Implementation

let appPromptEvent = null;
const installBtn = document.getElementById('install-btn');
self.addEventListener('beforeinstallprompt', function(e) {
  e.preventDefault();
  appPromptEvent = e;
  installBtn.classList.add('visible');
});
window.addEventListener('appinstalled', function() {
  console.log('App installed');
  installBtn.classList.remove('visible');
});
installBtn.addEventListener('click', function() {
  if (appPromptEvent) {
    appPromptEvent.prompt();
    appPromptEvent.userChoice.then(function(result) {
      if (result.outcome === 'accepted') {
        console.log('User accepted install');
      } else {
        console.log('User declined install');
      }
      appPromptEvent = null;
    });
  }
});

The beforeinstallprompt event has limited browser support; many browsers do not allow programmatic triggering.

Launch Animation

When launched from a home‑screen icon, the browser displays a splash screen based on manifest settings, smoothing the transition from white screen to content.

Service Worker

Service Worker runs in a separate thread, enabling offline capabilities, caching, and background sync.

Offline Page

Cache a fallback page during installation and serve it when network requests fail.

Implementation

const CACHE_NAME = 'sharee-v1';
const FILES_TO_CACHE = ['offline.html'];
self.addEventListener('install', e => {
  console.log('[Service Worker] Install');
  e.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      self.skipWaiting();
      return cache.addAll(FILES_TO_CACHE);
    })
  );
});
self.addEventListener('fetch', e => {
  e.respondWith(
    caches.match(e.request).then(r => {
      return r || fetch(e.request).then(response => {
        return caches.open(CACHE_NAME).then(cache => {
          cache.put(e.request, response.clone());
          return response;
        });
      });
    })
  );
});
self.addEventListener('activate', function(e) {
  e.waitUntil(
    caches.keys().then(keyList => {
      return Promise.all(
        keyList.map(key => {
          if (CACHE_NAME.indexOf(key) === -1) {
            return caches.delete(key);
          }
        })
      );
    })
  );
});

Resource Caching

Static assets (CSS/JS) are cached using regex matching and a CacheFirst strategy with expiration plugins.

const cacheList = ['/static/css/', '/static/js'];
self.addEventListener('fetch', e => {
  const cached = cacheList.find(c => e.request.url.indexOf(c) !== -1);
  if (cached) {
    e.respondWith(
      caches.match(e.request).then(r => {
        return r || fetch(e.request).then(response => {
          return caches.open(CACHE_NAME).then(cache => {
            if (cached) cache.put(e.request.url, response.clone());
            return response;
          });
        });
      })
    );
  }
});

Push API & Notification API

PWA can send push notifications using the Push API and display them via the Notification API, both built on Service Worker.

Notification Example

self.registration.showNotification('PWA-Book-Demo test actions', {
  body: 'Like button clickable',
  actions: [{action: 'like', title: 'Like', icon: '/assets/images/like-icon.png'}]
});
self.addEventListener('notificationclick', function(e) {
  e.notification.close();
  if (e.action === 'like') {
    console.log('Like button clicked');
  } else {
    console.log('Notification clicked');
  }
});

Push Example

self.addEventListener('push', function(e) {
  if (!e.data) return;
  let payload = e.data.text();
  let promise = self.registration.showNotification(payload.title, {
    body: payload.body,
    icon: payload.icon,
    data: {url: payload.url}
  });
  e.waitUntil(promise);
});
self.addEventListener('notificationclick', function(e) {
  e.notification.close();
  e.waitUntil(self.clients.openWindow(e.data.url));
});

Workbox Best Practices

Workbox simplifies Service Worker development by providing libraries for precaching, routing, and caching strategies.

Import Workbox

importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.2.0/workbox-sw.js');

Precaching

workbox.core.setCacheNameDetails({prefix: 'sharee', suffix: 'v1', precache: 'precache', runtime: 'runtime'});
workbox.routing.precacheAndRoute([
  {url: '/index.html', revision: 'asdf'},
  '/index.abc.js',
  '/index.bcd.css'
]);

Routing & Strategies

Register routes with matching rules (string, RegExp, or custom function) and apply strategies such as CacheFirst, NetworkFirst, StaleWhileRevalidate, etc.

workbox.routing.registerRoute(/\.(jpe?g|png)/, new workbox.strategies.CacheFirst({
  cacheName: 'image-runtime-cache',
  plugins: [new workbox.expiration.Plugin({maxAgeSeconds: 7*24*60*60, maxEntries: 10})],
  fetchOptions: {mode: 'cors'}
}));

Testing PWA

Use Chrome Lighthouse (Audits → Progressive Web App) to generate a report covering installability, offline support, performance, and best‑practice compliance.

Production Issues

Common problems include cache failures due to cross‑origin requests and SecurityError when drawing tainted images onto a canvas. Solutions involve ensuring CORS headers, using crossOrigin="anonymous" on images, and updating cached assets with new version identifiers.

Join Us

The ByteDance Internationalization team works on a wide range of front‑end technologies, including PWA, SSR, micro‑frontends, serverless, and edge computing. They invite engineers to apply via [email protected] with the email subject "Name - Experience Years - Frontend Internationalization".

References

Can I use – https://caniuse.com/

Add Manifest – https://web.dev/add-manifest/

Install criteria – https://web.dev/install-criteria/

Notifications API – https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API

Push API – https://developer.mozilla.org/en-US/docs/Web/API/Push_API

Service Worker API – https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

Workbox Expiration Plugin – https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-expiration.ExpirationPlugin

Google PWA demo – https://airhorner.com/

iOS compatibility – https://github.com/GoogleChromeLabs/pwacompat/

Workbox repository – https://github.com/GoogleChrome/workbox/

Welcome to follow ByteFront ByteFE!

Contact: [email protected]

frontendJavaScriptPWAservice-workerWeb App
ByteFE
Written by

ByteFE

Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.