PWA(Progressive Web App)作为网页应用的升级形式,能够提供类似原生应用的安装、离线使用和通知功能,而无需依赖应用商店。通过 Web App Manifest 配置安装提示,并结合 Service Worker 实现资源缓存、后台同步与推送通知,即可构建高度可靠的用户体验。本文聚焦工程实践,给出具体参数配置、代码清单和监控要点,帮助开发者快速落地。
Web App Manifest:安装提示的核心配置
PWA 的安装提示首先依赖有效的 Web App Manifest 文件。该 JSON 文件定义应用的名称、图标、启动 URL 和显示模式,是浏览器判断是否可安装的关键。
最小 Manifest 配置清单:
{
"name": "我的 PWA 应用",
"short_name": "PWA App",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"prefer_related_applications": false
}
- 必需字段:
name 或 short_name、icons(至少 192px 和 512px)、start_url、display(推荐 standalone 以隐藏浏览器 UI)。
- HTTPS 要求:应用必须在 HTTPS 或 localhost 下服务,否则无法触发安装。
- 浏览器触发条件:用户互动 ≥1 次、停留 ≥30 秒,且未安装过。满足后,浏览器显示地址栏安装按钮,或触发
beforeinstallprompt 事件。
自定义安装按钮:
监听 beforeinstallprompt 事件,提供应用内按钮:
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
showInstallButton();
});
installBtn.addEventListener('click', async () => {
if (deferredPrompt) {
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log(outcome);
}
});
此机制提升转化率,避免浏览器默认提示被忽略。
落地参数:
- 图标尺寸:优先 PNG,备 WebP;多尺寸覆盖(72x72、96x96、128x128、144x144、152x152、192x192、384x384、512x512)。
display 选项:standalone(推荐,原生感强)、minimal-ui(保留最小导航)。
- 测试工具:Chrome DevTools > Application > Manifest,验证 installability。
Service Worker:离线缓存与生命周期管理
Service Worker 是 PWA 的代理层,负责资源拦截、缓存和后台任务。安装阶段缓存核心资产,确保离线可用。
SW 注册与生命周期:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', { scope: '/' })
.then(reg => console.log('SW 注册成功', reg.scope));
}
SW 核心代码(sw.js):
const CACHE_NAME = 'pwa-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css',
'/script.js',
'/icons/icon-192.png',
'/icons/icon-512.png'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request)
.then(networkResponse => {
const responseClone = networkResponse.clone();
caches.open(CACHE_NAME).then(cache => cache.put(event.request, responseClone));
return networkResponse;
})
)
.catch(() => caches.match('/offline.html'))
);
});
缓存策略要点:
- Cache-First:静态资源优先缓存,动态 API 网络优先。
- 版本管理:CACHE_NAME 增量更新(如 'pwa-v2'),激活时删除旧版。
- 导航预加载:激活时启用
self.registration.navigationPreload.enable(),加速页面加载。
- 监控指标:Chrome DevTools > Application > Cache Storage,检查命中率;Lighthouse 审计离线分数 ≥90。
风险控制:
- 缓存上限:浏览器默认 ~50MB,避免 addAll 失败。
- 更新策略:检测新 SW 后,提示用户刷新(
registration.update())。
后台同步(Background Sync):离线数据可靠提交
后台同步允许离线操作,后续网络恢复时自动执行。适用于表单提交、消息同步。
注册同步:
navigator.serviceWorker.ready.then(reg => {
reg.sync.register('sync-data').then(() => console.log('同步注册'));
});
SW 处理:
self.addEventListener('sync', (event) => {
if (event.tag === 'sync-data') {
event.waitUntil(syncPendingData());
}
});
async function syncPendingData() {
const pending = await getPendingItems();
for (const item of pending) {
try {
await fetch('/api/sync', { method: 'POST', body: JSON.stringify(item) });
removePendingItem(item.id);
} catch (e) {
console.error('同步失败,重试');
}
}
}
参数配置:
- 标签唯一:'sync-messages'、'sync-orders'。
- 重试阈值:浏览器自动重试,失败后延迟指数退避(1s、2s、4s...)。
- 浏览器支持:Chrome/Edge 全支持,Firefox/iOS 有限。
推送通知(Push Notifications):后台唤醒用户
推送依赖 VAPID 密钥,实现服务器向客户端消息投递。
订阅:
navigator.serviceWorker.ready.then(reg => {
reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
}).then(sub => {
fetch('/api/subscribe', { method: 'POST', body: JSON.stringify(sub) });
});
});
SW 处理推送:
self.addEventListener('push', (event) => {
const data = event.data ? event.data.json() : { title: '默认标题' };
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192.png',
badge: '/icons/badge-72.png'
})
);
});
VAPID 生成(Node.js web-push):
web-push generate-vapid-keys
公钥嵌入前端,私钥服务器端加密 payload。
工程参数:
- TTL:推送有效期 4-7 天。
- 图标:badge 72x72 单色。
- 配额:Firefox 限 100/天(通知豁免),Chrome 无上限。
集成监控与回滚
Lighthouse 审计:
- PWA 分数 ≥100:安装、离线、快速启动。
- 监控:Chrome UX Report,First Input Delay <100ms。
回滚策略:
- SW 更新失败:保留旧版,日志 Sentry。
- Manifest 变更:增量图标,避免破坏安装。
通过以上配置,PWA 可实现 100% 离线可用、可靠同步和实时通知,媲美原生 app。实际部署中,从简单 Manifest + Cache-First 开始迭代。
资料来源:
- MDN: Making PWAs installable - 浏览器安装标准包括 HTTPS 和 Manifest 必需字段。
- MDN: Using Service Workers - SW 生命周期确保缓存一致性。
- web.dev: Install criteria - 用户互动 heuristics 为 30 秒停留。
(正文字数:1256)