当一个 PWA 被安装后,Service Worker 就会在后台运行,成为应用的一部分,检测 Service Worker 是否处于 "activated"(激活)状态,是判断 PWA 是否被安装的最可靠方法。

(图片来源网络,侵删)
下面我将分步详细解释如何实现,并提供完整的代码示例。
核心原理
- Service Worker (SW):PWA 的核心技术,它是一个在浏览器后台运行的脚本,可以处理网络请求、实现离线缓存、推送通知等,当一个 PWA 被安装后,它的 Service Worker 就会被注册并激活。
- 检测方法:我们可以通过
navigator.serviceWorkerAPI 来查询当前活动的 Service Worker。- 如果存在一个已注册且处于激活状态的 Service Worker,那么就可以认为该 PWA 已经被安装。
- 如果不存在,则说明 PWA 还未被安装。
实现步骤与代码
我们将创建一个简单的网页,它有两个按钮:“安装应用”和“检测安装状态”,并实时显示当前状态。
第 1 步:创建 PWA 清单文件 (manifest.json)
这是 PWA 的“身份证”,定义了应用的名称、图标、启动画面等,并告诉浏览器这是一个可安装的应用。
创建一个 manifest.json 文件,内容如下:

(图片来源网络,侵删)
{
"name": "我的第一个 PWA",
"short_name": "MyPWA",
"description": "一个演示 PWA 安装检测的示例应用。",
"start_url": ".",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3367d6",
"icons": [
{
"src": "icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
注意:你需要在项目根目录下提供 icon-192.png 和 icon-512.png 这两个图标文件。
第 2 步:注册 Service Worker (通常在 index.js 或主 HTML 文件中)
Service Worker 的注册代码通常放在你的主 JavaScript 文件中。
// 在你的主 JS 文件中 (app.js)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('ServiceWorker 注册成功: ', registration.scope);
})
.catch(err => {
console.log('ServiceWorker 注册失败: ', err);
});
});
}
第 3 步:编写 Service Worker 文件 (sw.js)
这个文件负责缓存资源,是实现 PWA 离线功能的关键,即使我们不实现复杂的缓存逻辑,也需要一个空的 sw.js 文件来让注册成功。
创建一个 sw.js 文件,可以简单到只包含一个 'use strict';。

(图片来源网络,侵删)
// sw.js
'use strict';
// 在这里可以添加缓存逻辑,
// self.addEventListener('install', event => {
// event.waitUntil(
// caches.open('my-cache-v1').then(cache => {
// return cache.addAll([
// '/',
// '/index.html',
// '/style.css',
// // ... 其他需要缓存的文件
// ]);
// })
// );
// });
第 4 步:编写检测安装状态的 JavaScript 逻辑
这是核心部分,我们将创建一个函数来检测状态,并根据结果更新 UI。
// 在你的主 JS 文件中 (app.js)
const checkInstallationButton = document.getElementById('check-install');
const installButton = document.getElementById('install-btn');
const statusDisplay = document.getElementById('status');
// --- 核心检测函数 ---
function isPwaInstalled() {
// 检查是否存在已激活的 Service Worker
return !!navigator.serviceWorker &&
navigator.serviceWorker.controller !== null;
}
// --- 更新UI状态的函数 ---
function updateUI() {
if (isPwaInstalled()) {
statusDisplay.textContent = '✅ PWA 已安装';
statusDisplay.style.color = 'green';
installButton.style.display = 'none'; // 如果已安装,隐藏安装按钮
} else {
statusDisplay.textContent = '❌ PWA 未安装';
statusDisplay.style.color = 'red';
installButton.style.display = 'inline-block'; // 如果未安装,显示安装按钮
}
}
// --- 检测按钮点击事件 ---
checkInstallationButton.addEventListener('click', () => {
updateUI();
});
// --- 安装按钮点击事件 (处理浏览器的安装提示) ---
installButton.addEventListener('beforeinstallprompt', (e) => {
// 阻止浏览器默认的安装提示
e.preventDefault();
// 保存事件,以便稍后手动触发
deferredPrompt = e;
// 显示我们的安装按钮
installButton.style.display = 'block';
installButton.textContent = '安装应用';
});
let deferredPrompt = null;
installButton.addEventListener('click', () => {
if (deferredPrompt) {
// 显示浏览器安装提示
deferredPrompt.prompt();
// 等待用户的选择
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('用户接受了安装提示');
} else {
console.log('用户拒绝了安装提示');
}
// 重置 deferredPrompt
deferredPrompt = null;
});
}
});
// --- 监听 Service Worker 的变化 ---
navigator.serviceWorker.addEventListener('controllerchange', () => {
console.log('Service Worker 已更新');
updateUI(); // 当 SW 变化时,重新检测状态
});
// 页面加载时,先检测一次状态
window.addEventListener('load', () => {
updateUI();
});
第 5 步:编写 HTML 文件
将所有部分组合起来。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">PWA 安装检测示例</title>
<link rel="manifest" href="manifest.json">
<!-- 关键:让浏览器知道这是一个 PWA -->
<meta name="apple-mobile-web-app-capable" content="yes">
<style>
body { font-family: sans-serif; text-align: center; padding-top: 50px; }
button { padding: 10px 20px; font-size: 16px; cursor: pointer; margin: 10px; }
#status { font-size: 18px; font-weight: bold; margin-top: 20px; }
</style>
</head>
<body>
<h1>我的第一个 PWA</h1>
<p>这是一个演示如何检测 PWA 是否已安装的网页。</p>
<button id="check-install">检测安装状态</button>
<button id="install-btn" style="display: none;">安装应用</button>
<div id="status">正在检测...</div>
<!-- 引入主 JS 文件 -->
<script src="app.js"></script>
</body>
</html>
总结与注意事项
- HTTPS 是必须的:Service Worker 和 PWA 功能必须在
https协议下才能正常工作(在localhost上开发除外)。 beforeinstallprompt事件:这是浏览器在认为你的应用“可安装”时触发的事件,你需要监听它,并阻止默认行为,然后保存事件对象 (deferredPrompt),以便在用户点击你的自定义安装按钮时手动调用prompt()方法。- 用户体验:
- 不要滥用:不要频繁弹窗提示用户安装,这会非常烦人,通常只在用户多次访问或在特定操作后提示。
- 提供入口:提供一个明确的按钮(如“安装到主屏幕”)让用户主动发起安装流程。
- 提供反馈:明确告诉用户当前是“已安装”还是“未安装”状态。
- Safari 的特殊性:Safari 对 PWA 的支持相对较弱,其安装体验和检测逻辑可能与 Chrome/Edge 等浏览器有所不同,上述代码在现代浏览器中是通用的,但可能需要针对 Safari 进行微调。
通过以上步骤,你就可以成功地在一个网页中实现检测 PWA 是否已安装的功能了。
