用最小的代码和配置,让一个普通网页变成可安装的 PWA。目标是 15--30 分钟内看到"添加到主屏幕"提示(Android 上自动,iOS 上通过分享菜单)。
前提条件(2026 年视角):
- 你有一个基本的静态网站或 SPA(HTML + CSS + JS)。
- 用现代构建工具(如 Vite、Next.js、Create React App)最好;纯静态 HTML 也可以。
- 最终上线必须 HTTPS(本地开发可以用 localhost 或自签名证书)。
第一步:启用 HTTPS(本地开发必备)
PWA 必须在 HTTPS 下工作(localhost 除外)。2026 年推荐工具仍是 mkcert(零配置、本地信任 CA)。
-
安装 mkcert(跨平台):
- macOS:
brew install mkcert - Windows:用 Chocolatey 或 Scoop,或直接下载二进制
- Linux:从 GitHub 下载
- macOS:
-
初始化本地 CA(只需一次):
mkcert -install -
为 localhost 生成证书:
bashmkdir certs && cd certs mkcert localhost 127.0.0.1 ::1→ 生成
localhost.pem和localhost-key.pem -
用它启动服务器:
-
Vite(推荐,超快):vite 默认支持 HTTPS
ts// vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], server: { https: { key: './certs/localhost-key.pem', cert: './certs/localhost.pem', }, }, })运行
npm run dev→ https://localhost:5173 -
纯静态 或其他:用
http-server、live-server --https或 Node 的 https 模块。
-
访问 https://localhost:xxxx(忽略浏览器警告如果没信任 CA,但 mkcert 会自动信任)。
iOS Safari 测试 :用真机连同一 WiFi,访问你电脑的 IP(如 https://192.168.1.100:5173)。iOS 26+ 对 PWA 支持更好,默认 Home Screen 打开像 web app。
第二步:创建 Web App Manifest
在项目根目录创建 manifest.json(或 manifest.webmanifest),内容如下(最小 + 2026 年推荐字段):
json
{
"name": "我的第一个 PWA",
"short_name": "PWA Demo",
"description": "一个简单的渐进式 Web 应用示例",
"start_url": "/",
"display": "standalone",
"display_override": ["standalone", "minimal-ui"],
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"scope": "/",
"orientation": "any",
"prefer_related_applications": false
}
关键字段解释(2026 年现状):
display: "standalone"→ 像原生 App,无浏览器边框。icons→ 至少 192x192 和 512x512;iOS/Android 都认 maskable(自适应圆角)。theme_color/background_color→ 启动屏和状态栏颜色。start_url/scope→ 控制打开范围。
链接到 HTML(index.html 的 内):
html
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#000000">
<!-- iOS 老 fallback,2026 年 manifest 优先 -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
准备图标:用任意工具生成 192 和 512 的 PNG(推荐 maskable 形状:maskable.app/)放根目录。
第三步:注册基础 Service Worker
创建 sw.js(根目录):
js
// sw.js - 基础版:仅预缓存首页和核心文件
const CACHE_NAME = 'pwa-demo-v1';
const urlsToCache = [
'/',
'/index.html',
'/styles.css', // 你的 CSS
'/app.js', // 你的 JS
'/icon-192.png',
'/icon-512.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
// 缓存命中,返回缓存
if (response) {
return response;
}
// 否则发网络请求
return fetch(event.request);
})
);
});
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
在你的主 JS 文件(或 index.html 的 script)注册:
js
// main.js 或直接 <script> 内
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker 注册成功:', registration);
})
.catch(err => {
console.log('注册失败:', err);
});
});
}
测试你的第一个 PWA
- 运行 HTTPS 本地服务器 → 访问 https://localhost:xxxx
- Chrome DevTools → Application → Manifest:检查 manifest 是否加载。
- Application → Service Workers:看到 sw.js 已激活。
- Lighthouse(Chrome DevTools)跑 PWA 审计:应该看到 "Installable" 绿灯。
- Android:访问几次 → 自动弹出"添加到主屏幕" banner,或菜单 → 安装。
- iOS Safari(iOS 26+):分享 → "添加到主屏幕" → 会用 manifest 的图标和名称,standalone 打开(无地址栏)。
常见坑 & 快速修复:
- Manifest 404?→ 确认路径,Content-Type: application/manifest+json
- SW 不工作?→ 确保 scope 正确(根目录 sw 覆盖全部)
- iOS 不显示 standalone?→ 确认加到主屏幕后打开;Safari 26+ 默认 web app 模式好多了。
- 图标不圆?→ purpose: "maskable" + 用 maskable.app 测试。
恭喜!你已经有了第一个可安装 PWA!它能离线打开(因为预缓存了首页),以 App 形式出现。