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 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
- Open browser dev tools
- Navigate to Application tab
- Check Service Worker status
- Simulate offline mode using Network tab
- Verify cache storage contents
Note: Use
ionic serve for local testing with PWA features enabled.
10. Deploying PWA
| 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);
});
});
}