
2026 年的 PWA:Service Worker、离线优先与现代安装体验
渐进式 Web 应用已经显著成熟。到 2026 年,PWA 在 Android 和 iOS 上都能提供与原生应用相媲美的能力。借助 Service Worker、后台同步、推送通知和文件系统访问,Web 与原生之间的界限持续模糊。
2026 年的 PWA 能力全景
现代 PWA 可以访问:
- 文件系统访问 API(File System Access API):在用户许可下读写文件
- Web Bluetooth 和 USB:连接硬件设备
- 后台同步(Background Sync):在连接恢复时排队执行操作
- 定期后台同步(Periodic Background Sync):定期更新数据(Android)
- Web 推送(Web Push):即使应用关闭也能发送通知
- 徽章 API(Badging API):应用图标徽章
- 共享目标 API(Share Target API):接收来自其他应用的共享内容

Web App Manifest 深入解析
{
"name": "My Production PWA",
"short_name": "MyPWA",
"display": "standalone",
"display_override": ["window-controls-overlay", "standalone", "browser"],
"background_color": "#ffffff",
"theme_color": "#6366f1",
"screenshots": [
{
"src": "/screenshots/desktop.png",
"sizes": "1280x800",
"type": "image/png",
"form_factor": "wide",
"label": "Desktop view"
}
],
"icons": [
{ "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
{ "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
],
"file_handlers": [
{
"action": "/open-file",
"accept": { "text/markdown": [".md"] }
}
],
"share_target": {
"action": "/share-target",
"method": "POST",
"enctype": "multipart/form-data",
"params": { "title": "title", "text": "text", "url": "url" }
}
}
高级 Service Worker 模式
Workbox 7.x 配置
import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';
import { BroadcastUpdatePlugin } from 'workbox-broadcast-update';
precacheAndRoute(self.__WB_MANIFEST);
cleanupOutdatedCaches();
// HTML - Network First
registerRoute(
({ request }) => request.destination === 'document',
new NetworkFirst({
cacheName: 'html-cache',
networkTimeoutSeconds: 3,
plugins: [new ExpirationPlugin({ maxAgeSeconds: 24 * 60 * 60 })],
})
);
// API - Network First with update notification
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new NetworkFirst({
cacheName: 'api-cache',
networkTimeoutSeconds: 5,
plugins: [
new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 5 * 60 }),
new BroadcastUpdatePlugin(),
],
})
);
// Images - Cache First, long expiry
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({
cacheName: 'image-cache',
plugins: [
new ExpirationPlugin({ maxEntries: 60, maxAgeSeconds: 30 * 24 * 60 * 60 }),
],
})
);

后台同步
const bgSyncPlugin = new BackgroundSyncPlugin('form-queue', {
maxRetentionTime: 24 * 60,
onSync: async ({ queue }) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
await fetch(entry.request);
} catch (error) {
await queue.unshiftRequest(entry);
throw error;
}
}
},
});
registerRoute(
({ url }) => url.pathname === '/api/submit',
new NetworkOnly({ plugins: [bgSyncPlugin] }),
'POST'
);
智能更新管理
class ServiceWorkerManager {
async register() {
if (!('serviceWorker' in navigator)) return;
this.registration = await navigator.serviceWorker.register('/sw.js', {
scope: '/',
updateViaCache: 'none',
});
setInterval(() => this.registration.update(), 60 * 60 * 1000);
this.registration.addEventListener('updatefound', () => {
const newWorker = this.registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
this.onUpdateAvailable?.();
}
});
});
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
}
skipWaiting() {
this.registration?.waiting?.postMessage({ type: 'SKIP_WAITING' });
}
}
推送通知

请求权限并订阅
async function subscribeToPush() {
const registration = await navigator.serviceWorker.ready;
const permission = await Notification.requestPermission();
if (permission !== 'granted') throw new Error('Permission denied');
const sub = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY),
});
await fetch('/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(sub.toJSON()),
});
return sub;
}
在 Service Worker 中处理推送
self.addEventListener('push', (event) => {
const data = event.data?.json() ?? {};
event.waitUntil(
self.registration.showNotification(data.title ?? 'New Update', {
body: data.body,
icon: '/icons/icon-192.png',
badge: '/icons/badge-72.png',
data: { url: data.url },
actions: [
{ action: 'open', title: 'Open App' },
{ action: 'dismiss', title: 'Dismiss' },
],
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'dismiss') return;
const url = event.notification.data?.url ?? '/';
event.waitUntil(
clients.matchAll({ type: 'window' }).then((clientList) => {
const existing = clientList.find(c => c.url === url);
if (existing) return existing.focus();
return clients.openWindow(url);
})
);
});
自定义安装提示
class PWAInstallManager {
private deferredPrompt = null;
constructor() {
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
this.deferredPrompt = e;
this.onInstallAvailable?.();
});
window.addEventListener('appinstalled', () => {
this.deferredPrompt = null;
analytics.track('pwa_installed');
});
}
get canInstall() { return !!this.deferredPrompt; }
async promptInstall() {
if (!this.deferredPrompt) return null;
this.deferredPrompt.prompt();
const { outcome } = await this.deferredPrompt.userChoice;
this.deferredPrompt = null;
return outcome;
}
}
定期后台同步
// Register periodic sync
async function registerPeriodicSync() {
const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
try {
await registration.periodicSync.register('update-feed', {
minInterval: 24 * 60 * 60 * 1000, // 24 hours
});
} catch (e) {
console.log('Periodic sync registration failed:', e);
}
}
}
// Handle in service worker
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'update-feed') {
event.waitUntil(updateFeedCache());
}
});
结论
2026 年的 PWA 是真正具备跨平台能力的应用。通过高级 Service Worker 策略、后台同步、推送通知和精心设计的安装体验,你可以通过 Web 提供应用商店级别的体验。对 PWA 架构的投入将在所有平台上同时获得回报。