Skip to main content

Building Progressive Web Apps

1. Enabling PWA Support

To enable Progressive Web App (PWA) support in an Ionic application, you need to ensure that your app is properly configured to take advantage of PWA features such as service workers, caching strategies, and offline capabilities.

Configuration File Property Value Description
ionic.config.json pwa true Enables PWA support in the Ionic project.
angular.json build.options.serviceWorker true Enables service worker for Angular-based Ionic apps.
vite.config.ts build.serviceWorker true Enables service worker for Vite-based Ionic apps.

Example: Enabling PWA in ionic.config.json

{
  "name": "myApp",
  "pwa": true
}

Example: Enabling Service Worker in angular.json

{
  "build": {
    "options": {
      "serviceWorker": true
    }
  }
}
Note: Service workers are essential for PWA functionality, enabling features like background sync and offline access.

2. Configuring Service Worker

Configuration Option Description Default Value Notes
workbox Workbox configuration object {} Used to customize caching strategies and behavior
skipWaiting Whether to skip waiting for service worker activation false Set to true to immediately activate new service worker
clientsClaim Whether to claim all clients immediately false Enables immediate control of clients once service worker is activated

Example: Service Worker Configuration in Ionic

const workboxConfig = {
  skipWaiting: true,
  clientsClaim: true,
  runtimeCaching: [
    {
      urlPattern: /^https:\/\/api\.example\.com\/.*/,
      handler: 'CacheFirst',
      options: {
        cacheName: 'api-cache',
        expiration: {
          maxEntries: 10,
          maxAgeSeconds: 300
        }
      }
    }
  ]
};

module.exports = {
  workbox: workboxConfig
};
Note: The service worker configuration is typically defined in angular.json or ionic.config.json depending on the project setup.

3. Setting Up Web Manifest

Property Value Description
name "My Ionic App" Display name of the app
short_name "IonicApp" Short name for app icon
start_url "/" URL to open when launching the app
display "standalone" How the app should be displayed
background_color "#ffffff" Background color for the app
theme_color "#000000" Theme color for the browser UI
icons [{ src: 'assets/icon/icon-192.png', sizes: '192x192', type: 'image/png' }] Array of icon objects for different sizes

Example: web app manifest configuration

{
  "name": "My Ionic App",
  "short_name": "IonicApp",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#000000",
  "icons": [
    {
      "src": "assets/icon/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ]
}
Note: The web app manifest file is typically named manifest.json and placed in the root of your project.

4. Implementing Cache Strategies (cacheFirst, networkFirst)

Strategy Description Use Case Code Example
cacheFirst Cache is checked first, and if the resource is not in cache, it's fetched from network. Static assets that don't change often (e.g., icons, images). const cacheFirst = new workbox.strategies.CacheFirst();
networkFirst Resource is fetched from network first, and if that fails, it falls back to the cache. Dynamic content that needs to be up-to-date (e.g., API responses). const networkFirst = new workbox.strategies.NetworkFirst();
Note: Strategies are part of the Workbox library, which is used for service worker caching in PWA development.

5. Handling Service Worker Updates (SwUpdate)

Property Description Values
versionUpdates Observable that emits when a new version of the app is available VersionEvent
versionDetected Observable that emits when a new version is detected but not yet activated VersionEvent
versionInstall Observable that emits when a new version is installed and ready to be activated VersionEvent

Example: Subscribe to Service Worker Updates

import { SwUpdate } from '@angular/service-worker';

constructor(private swUpdate: SwUpdate) {
  if (swUpdate.isEnabled) {
    swUpdate.versionUpdates.subscribe(event => {
      console.log('New version available:', event);
    });
  }
}

Example: Prompt User to Update

import { SwUpdate } from '@angular/service-worker';
import { AlertController } from 'ionic-angular';

constructor(
  private swUpdate: SwUpdate,
  private alertCtrl: AlertController
) {}

updateApp() {
  const alert = this.alertCtrl.create({
    title: 'Update Available',
    message: 'A new version of the app is available. Would you like to update now?',
    buttons: [
      {
        text: 'Later',
        role: 'cancel'
      },
      {
        text: 'Update Now',
        handler: () => {
          window.location.reload();
        }
      }
    ]
  });
  alert.present();
}
Note: Ensure that the app is properly configured with a service worker and that SwUpdate is enabled in the Angular app.

6. Adding Install Prompt (beforeinstallprompt)

The beforeinstallprompt event is fired when a Progressive Web App (PWA) is ready to be installed on the user's device. This event allows developers to prompt users to install the app, providing a better user experience and increasing adoption.

Event Description Notes
beforeinstallprompt Fired when the PWA is ready to be installed Can be used to show a custom install prompt

Example: Handling beforeinstallprompt Event

let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  // Prevent the mini-infobar from appearing on mobile
  e.preventDefault();
  // Stash the event so it can be triggered later
  deferredPrompt = e;
  // Show the install button or prompt
  document.getElementById('installButton').style.display = 'block';
});

document.getElementById('installButton').addEventListener('click', () => {
  // Hide the install button
  document.getElementById('installButton').style.display = 'none';
  // Show the install prompt
  deferredPrompt.prompt();
  // Wait for the user to respond to the prompt
  deferredPrompt.userChoice.then((choiceResult) => {
    if (choiceResult.outcome === 'accepted') {
      console.log('User accepted the install prompt');
    } else {
      console.log('User dismissed the install prompt');
    }
    // Clear the deferred prompt
    deferredPrompt = null;
  });
});
Note: The beforeinstallprompt event is only available in browsers that support PWA installation. It's recommended to check for browser support before attempting to use this event.

7. Implementing Push Notifications (Web Push)

Property Description Values
serviceWorkerPath Path to the service worker file /sw.js
vapidPublicKey Public key for Web Push protocol BNk...

Example: Registering for Push Notifications

const registerPush = async () => {
  const sw = await navigator.serviceWorker.register("/sw.js");
  const subscription = await sw.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: "BNk..."
  });
  return subscription;
};

Example: Sending Push Message

const sendPush = async (subscription, payload) => {
  const response = await fetch("/api/send-push", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ subscription, payload })
  });
  return response.json();
};
Note: Web Push requires a valid VAPID key and secure HTTPS context.
Warning: Push notifications must be user-initiated to comply with browser policies.

8. Configuring PWA Icons (icon sizes)

Icon Type Sizes File Format Notes
favicon 16x16, 32x32 .ico, .png Used for browser tabs and bookmarks
apple-touch-icon 57x57, 60x60, 72x72, 76x76, 114x114, 120x120, 144x144, 152x152, 180x180 .png Used on iOS Safari and Home Screen
mask-icon 16x16 .svg Used for Safari pinned tabs; requires mask-icon in manifest
msapplication-TileImage 144x144 .png Used for Windows 8/10 Start Screen tiles
msapplication-Config 150x150 .json Configuration file for Windows 10 tile layout

Example: PWA Icon Configuration in Ionic

{
  "name": "MyApp",
  "short_name": "MyApp",
  "icons": [
    {
      "src": "assets/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "splash": {
    "src": "assets/splash/splash.png",
    "sizes": "1024x1024"
  }
}

9. Testing PWA Features

Example: Service Worker Registration Test

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(registration => {
        console.log('SW registered: ', registration);
      })
      .catch(error => {
        console.log('SW registration failed: ', error);
      });
  });
}
Feature Description Testing Method Status
Service Worker Background script for PWA functionality Check registration and scope NEW
Push Notifications Send notifications to users Simulate push event via browser dev tools EXPERIMENTAL
Cache Storage Store assets for offline use Inspect cache in Application tab DEPRECATED

Testing Workflow

  1. Open browser dev tools
  2. Navigate to Application tab
  3. Check Service Worker status
  4. Simulate offline mode using Network tab
  5. Verify cache storage contents
Note: Use ionic serve for local testing with PWA features enabled.

10. Deploying PWA

Example: Building and Deploying Ionic PWA

ionic build --prod --release
Command Description Notes
ionic build --prod --release Builds the app for production with PWA optimizations Generates files in www/ directory
ionic build --prod --release --cordova Builds with Cordova support for hybrid apps Includes cordova.js in build
Note: Ensure your ionic.config.json has proper PWA configuration.

Example: Service Worker Registration

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then((registration) => {
        console.log('SW registered: ', registration);
      })
      .catch((error) => {
        console.log('SW registration failed: ', error);
      });
  });
}

Deployment Steps

  • Run ionic build --prod --release
  • Deploy www/ directory to your hosting provider
  • Ensure manifest.json and sw.js are served correctly
  • Test PWA features using Lighthouse or Chrome DevTools

Was this article helpful?