文章目录
-
- 第一部分 认知篇:PWA 到底是什么
-
- 1.1 先看三份官方文档给出的定义
-
- MDN Web Docs 的定义
- Microsoft Learn 的定义
- web.dev 的定义
- 1.2 三类应用的正面比较:网站 vs 平台特定应用 vs PWA
-
- 传统网站
- 平台特定应用(原生应用)
- PWA:两全其美
- 1.3 PWA 的技术底座:它依然需要一个浏览器引擎
- 1.4 PWA 的三大技术支柱
-
- 支柱一:Web 应用程序清单(Web App Manifest)
- 支柱二:Service Worker
- 支柱三:安全上下文(HTTPS)
- 1.5 PWA 与单页应用(SPA)的关系
- 1.6 \”渐进式\”三个字的真正含义:渐进增强
- 第二部分 价值篇:为什么要用 PWA
-
- 2.1 微软官方归纳的 PWA 四大权益
-
- 权益一:类似本机的体验
- 权益二:高级功能
- 权益三:与 Web 相关的优势
- 权益四:降低开发成本
- 2.2 缩小 Web 与原生之间的差距
- 2.3 真实商业案例:数据不说谎
-
- 微软引用的三个案例
- web.dev 引用的四个案例
- 大厂的采用情况
- 流媒体与云游戏:PWA 能力的极限展示
- 2.4 兼容性全景:这不是\”未来技术\”,而是\”现在就能用\”
-
- 桌面平台兼容性明细
- 移动平台兼容性明细
- 一个高频踩坑点:应用内浏览器
- 其他设备
- 2.5 官方也坦诚的两大挑战
-
- 挑战一:跨浏览器兼容性
- 挑战二:对 PWA 的认知度
- 兼容性的正确心态
- 第三部分 环境准备篇:把本地跑通链路打通
-
- 3.1 你需要准备什么
- 3.2 三种本地起服务的方式
- 3.3 DevTools 调试面板速查
- 3.4 快速自检清单(在写代码之前先记住)
- 第四部分 实战篇:从 0 到 1 手写一个 TodoPWA
-
- 4.1 项目目录结构
- 4.2 Step 1:HTML 骨架(index.html)
- 4.3 Step 2:样式(styles.css)
- 4.4 Step 3:Web 应用清单(manifest.webmanifest)
-
- 4.4.1 清单成员逐项精讲
-
- A 类:Chromium 浏览器要求的可安装必需成员
- B 类:素材中明确提及的可选成员
- C 类:需要谨慎对待的成员
- 4.4.2 icons 成员完全解析
- 4.4.3 清单的部署细节
- 4.5 Step 4:准备图标
- 4.6 Step 5:Service Worker(sw.js)
-
- 4.6.1 缓存策略怎么选?MDN 的官方说法
- 4.6.2 为什么一定要 `clone()`
- 4.6.3 更新机制与删除旧缓存
- 4.6.4 导航预加载(可选增强)
- 4.7 Step 6:离线回退页面(offline.html)
- 4.8 Step 7:主应用逻辑(app.js)
- 4.9 运行与验证
- 第五部分 进阶篇:让 PWA 真正\”像\”原生应用
-
- 5.1 独立窗口与显示模式(display)
- 5.2 主题色与背景色
- 5.3 应用图标徽章(Badging API)
-
- 平台支持矩阵(MDN 原文,非常重要)
- 四条最佳实践(MDN 原文)
- 后台更新徽章的完整示例(MDN 官方代码)
- 5.4 应用快捷方式(shortcuts)
- 5.5 应用间数据共享
-
- 5.5.1 分享出去:Web Share API
- 5.5.2 接收分享:share_target 清单成员
- 5.6 文件关联(file_handlers)
- 5.7 通知与推送(Push API + Notifications API)
-
- 推送消息的完整链路(MDN 原文九步)
- 5.8 后台同步(Background Synchronization API)
- 5.9 周期性后台同步(Web Periodic Background Synchronization API)
- 5.10 后台获取(Background Fetch API)
- 5.11 权限与限制总表
- 5.12 Service Worker 与其他 API 的完整能力地图
-
- 与应用进行通信
- 离线操作
- 后台操作
- 其他 Web API
- Service Worker 事件全表(MDN 原文)
- 第六部分 质量篇:MDN 官方最佳实践清单逐条落地
-
- 6.1 适配所有浏览器
- 6.2 适配所有设备
- 6.3 提供离线体验
-
- 层次一:自定义离线页面(最低要求)
- 层次二:离线操作(更进一步)
- 层次三:支持深链接
- 6.4 提供快速的体验
- 6.5 提供无障碍体验
- 6.6 提供类似应用的体验
-
- 6.6.1 与操作系统集成
- 6.6.2 应用的外观和感觉
- 6.7 上线前的完整自查表
- 第七部分 发布篇:把作品推向用户
-
- 7.1 部署:先解决 HTTPS
- 7.2 用 PWABuilder 打包
- 7.3 四大应用商店
- 7.4 用户在 Edge 中如何安装(便于你写引导文案)
- 第八部分 常见问题 FAQ(25 问)
-
- A. 概念类
- B. 清单(Manifest)类
- C. Service Worker 类
- D. 安装与分发类
- 第九部分 总结与学习路径
-
- 9.1 一图回顾 PWA 技术全景
- 9.2 三句话记住 PWA
第一部分 认知篇:PWA 到底是什么
1.1 先看三份官方文档给出的定义
MDN Web Docs 的定义
渐进式 Web 应用(Progressive Web App,PWA)是一个使用 web 平台技术构建的应用程序,但它提供的用户体验就像一个特定平台的应用程序。
它像网站一样,PWA 可以通过一个代码库在多个平台和设备上运行。它也像一个特定平台的应用程序一样,可以安装在设备上,可以离线和在后台运行,并且可以与设备和其他已安装的应用程序集成。
MDN 的定义里有一个非常关键的句式——“像……一样,也像……一样”。它点出了 PWA 的本质:PWA 不是第三种东西,而是\”网站\”与\”平台特定应用\”两种特性的叠加。
Microsoft Learn 的定义
渐进式 Web 应用 (PWA) 是使用 Web 技术生成的应用程序,可以从一个代码库安装并可在所有设备上运行。
PWA 在支持设备上为用户提供类似于本机的体验。它们适应每个设备支持的功能,还可以在 Web 浏览器(如网站)中运行。
微软的定义突出了两点:一个代码库与能力自适应。\”适应每个设备支持的功能\”这一句,其实就是\”渐进增强(Progressive Enhancement)\”的另一种说法。
web.dev 的定义
渐进式 Web 应用 (PWA) 是一种 Web 应用,它使用渐进式增强功能为用户提供更可靠的体验,使用新功能提供更集成的体验,并且可以安装。由于它是一款 Web 应用,因此只需一个代码库,即可让任何人随时随地通过任何设备访问。
web.dev 的定义更进一步,明确了安装之后 PWA 具体\”长什么样\”。安装后,PWA 看起来就像任何其他应用,具体而言:
这五条非常实用——它们其实就是一份\”PWA 验收清单\”。你做完一个 PWA 之后,可以逐条对照检查。
1.2 三类应用的正面比较:网站 vs 平台特定应用 vs PWA
要真正理解 PWA,必须先理解它要超越的两个对象。
传统网站
传统上,网站更像是\”用户访问的地方\”,而不是\”用户拥有的东西\”。通常,一个网站:
- 在用户不访问它时,在用户的设备上没有存在感;
- 只能通过用户打开浏览器并导航到该网站来访问;
- 高度依赖网络连接。
但网站相比平台特定应用有两个巨大优势:
| 单一代码库 | 因为 web 本身就是跨平台的,一个网站可以从一个代码库运行在不同的操作系统和设备类别上 |
| 通过 web 分发 | 网站被搜索引擎索引,并且可以通过 URL 来分享和访问;一个网站可以分发而无需注册任何供应商的应用商店 |
web.dev 对 Web 平台的评价非常高:
网络是一个不可思议的平台。它兼具跨设备和操作系统的通用性、以用户为中心的安全模型,并且没有任何一家公司控制其规范或实现,这使其成为一个强大的软件交付平台。
结合网络固有的链接性,您可以搜索网络上的所有内容,并与世界各地的任何人分享您发现的内容。每当您访问某个网站时,您看到的都是发布商部署的最新版本,并且您对该网站的体验可以是临时的,也可以是永久性的,由您决定。
Web 应用可以通过单个代码库面向任何人、在任何位置、通过任何设备提供服务。对于开发者而言,Web 还提供了透明且简单明了的部署机制。无需打包,无需额外的内容审核,也不会延迟更新。
“无需打包,无需额外的内容审核,也不会延迟更新”——这三句话是 Web 分发模式相对应用商店模式最核心的竞争力,请务必记住。
平台特定应用(原生应用)
移动设备和桌面设备上的平台特定应用以功能丰富且可靠著称:
- 它们会一直出现在主屏幕、基座和任务栏中;
- 无论网络连接如何,它们都可以运行,并且以独立方式启动;
- 它们可以从本地文件系统中读取和写入文件,访问通过 USB、串行或蓝牙连接的硬件,以及与存储在设备上的数据(例如联系人和日历活动)互动;
- 您可以在其他应用中拍照、播放主屏幕上列出的歌曲,或控制媒体播放。
MDN 将其优势归纳为五条:
| 用户易于访问 | 在设备上有自己的图标,使用户容易找到和打开 |
| 离线和后台操作 | 在用户没有与之交互和设备离线时也能运行 |
| 专用 UI | 可以实现自己独特的、沉浸式的 UI |
| 操作系统集成 | 可以注册为分享目标、访问相机 / GPS / 加速度计等设备特性 |
| 应用商店集成 | 通过应用商店分发,给用户一个单一的地方来找到它们 |
但平台特定应用也有两个绕不开的挑战。web.dev 给出了非常直白的提醒:
注意:在新型移动操作系统中,平台特定应用主要通过应用商店安装,并且有针对用户可以发布的内容和发布者身份的规则和限制。这些应用通常作为一个大的、不可分割的软件包发布,每项更新都需要重新打包、重新签名、重新审批以及在设备上重新安装。
特定于平台的应用面临的一个挑战是,它们与多个平台和设备不兼容,因此,如果不从头开始创建新应用,将 Android 应用移植到 iOS 或将 iOS 应用移植到 Windows 或 ChromeOS 并不容易。
PWA:两全其美
web.dev 用一张对比表把这件事说透了。如果从功能和覆盖面两个维度来考虑,平台应用代表\”最出色的功能\”,Web 应用代表\”最广泛的覆盖面\”,而 PWA 二者兼得:
Web 侧:
- 可关联性
- 默认可访问
- 无处不在
- 易于部署
- 易于更新
- 所有人都可以发布
平台应用侧:
- 支持离线
- 高性能
- 设备集成
- 独立体验
- \”已安装\”图标
- 丰富且可靠
注意(web.dev 原文提醒):人们往往会将渐进式 Web 应用视为用户可以通过浏览器(而非应用商店)安装的应用。不过,现在,PWA 可以作为可选分发渠道在许多应用商店中上架,包括 Google Play 商店(适用于 Android 和 ChromeOS)、Microsoft 商店(适用于 Windows 10 和 11)以及 Apple AppStore(适用于 iOS、iPadOS 和 macOS)。在这些情况下,您必须遵循所有商店规则和要求,但您仍将获得 PWA 的一些优势。
这一点非常容易被误解,请特别注意:\”PWA\”与\”上架应用商店\”并不互斥。
1.3 PWA 的技术底座:它依然需要一个浏览器引擎
这是很多初学者的认知盲区。MDN 解释得很清楚:
PWA 通常看起来像平台特定应用程序——它们通常是在没有浏览器 UI 环绕的情况下显示的——但从技术上讲,它们仍然是网站。这意味着它们需要一个浏览器引擎,如 Chrome 或 Firefox 中的引擎,来管理和运行它们。对于平台特定应用程序,平台操作系统管理这个应用程序,提供其运行的环境。对于 PWA,浏览器引擎执行这一后台角色,就像它对普通网站所做的一样。
例如,我们可能会说,\”当收到推送通知时,浏览器会启动 PWA 的 service worker。\”在这种情况下,浏览器的活动完全在后台。从 PWA 的角度来看,它也可以由操作系统启动。对于某些系统,如 Chromebook,\”浏览器\”和\”操作系统\”之间可能根本没有区别。
这段话有两个实践含义:
微软的表述与此呼应:
PWA 是使用托管在 Web 服务器上并在 Web 浏览器引擎中运行的 HTML、CSS 和 JavaScript 代码生成的。它们可以直接在 Web 浏览器(如网站)中使用,也可以从应用商店安装到设备上,也可以使用支持浏览器的应用安装功能。
PWA 的用户体验随设备功能纵向扩展或缩减。
1.4 PWA 的三大技术支柱
MDN 明确给出了 PWA 的最小技术要求。因为 PWA 是网站,所以它们具有与任何其他网站相同的基本特性:至少有一个 HTML 页面,其可能会加载一些 CSS 和 JavaScript;页面加载的 JavaScript 具有一个全局的 Window 对象,并且可以通过该对象访问所有可用的 Web API。
除此之外,PWA 还必须额外具备两个东西:
支柱一:Web 应用程序清单(Web App Manifest)
PWA 必须有一个 web 应用程序清单,并且清单必须包含足够的信息以便浏览器安装 PWA。
清单可以定义 PWA 外观的许多其他方面,比如主题颜色和背景颜色,以及其行为,包括其充当其他应用程序数据的共享目标的能力或处理特定文件类型的能力。
MDN 对清单的正式描述是:
Web 应用清单规范中定义的 web 应用清单是一个提供 web 应用信息的 JSON 文本文件。Web 应用清单最常见的用途是提供浏览器在设备上安装渐进式 web 应用(PWA)所需的信息,如应用程序的名称和图标。
web 应用清单包含一个 JSON 对象,其中的顶级键称为成员。
支柱二:Service Worker
PWA 必须有一个 service worker,并且 service worker 必须实现至少最小程度的脱机体验。
service worker 鼓励一种架构,其中应用程序的页面(即网站的传统部分)实现用户界面,service worker 实现可以支持脱机和后台操作的后端,使 PWA 的行为更像应用程序而不是网站。这是因为 service worker 可以在需要时(例如,处理推送通知)由浏览器在后台启动。
这个架构划分非常重要,请务必建立这个心智模型:
┌─────────────────────────────────────────────┐
│ PWA 应用的整体架构 │
├──────────────────────┬──────────────────────┤
│ 主应用(前端) │ Service Worker(后端) │
│ HTML / CSS / JS │ 独立线程,无 DOM 访问权 │
│ 实现 UI 与交互 │ 离线缓存 / 后台同步 │
│ 可访问 DOM、Window │ 推送 / 后台获取 / 通知 │
│ window 作用域 │ self 全局作用域 │
└──────────────────────┴──────────────────────┘
↕ postMessage / Broadcast Channel 通信 ↕
支柱三:安全上下文(HTTPS)
这一条来自 MDN 的\”可安装性\”要求:
要使 Web 应用程序可安装,它必须在安全上下文中提供。通常意味着它必须通过 HTTPS 提供。本地资源,如 localhost、127.0.0.1 和 file:// 也被视为安全。
MDN 的 Service Worker 使用指南再次强调:
service worker 在现代浏览器中默认开启。要使用 service worker 运行代码,你需要通过 HTTPS 提供你的代码——出于安全原因,Service worker 仅限在 HTTPS 上运行。支持 HTTPS 的服务器是必要的。为了托管实验代码,你可以使用 Github、Netlify、Vercel 等服务。为了促进本地开发,浏览器也认为 localhost 是一个安全的来源。
所以本地开发时你不需要去申请证书,直接用 localhost 或 127.0.0.1 即可。
1.5 PWA 与单页应用(SPA)的关系
这也是一个常见误区。MDN 的说法是:
单页应用可以提供更接近平台特定应用程序的用户体验,所以 PWA 通常以单页应用实现。特别是,单页应用使实现无缝的用户界面变得更加容易,在该用户界面中,用户被呈现一个单一、一致的页面,只更新页面相关部分以响应用户与应用程序的交互。
然而,PWA 不必是单页应用,单页应用也不必是 PWA。
一句话总结:SPA 是一种组织前端代码的方式,PWA 是一组赋予 Web 应用原生能力的技术标准,二者正交。
1.6 \”渐进式\”三个字的真正含义:渐进增强
虽然渐进增强是大多数网站的一个理想的属性,但对于 PWA 来说尤其重要,因为它们期望在广泛的设备上运行,并且通常使用可能不被所有浏览器支持的高级 Web API。
渐进增强的一个基本组成部分是,如果用户通过在浏览器中输入其 URL 的方式在网络上访问你的 PWA,则用户可以像访问普通网站一样与应用程序交互。但是如果浏览器可以安装它,则会提示用户安装它,并且该应用程序将作为设备上的新功能出现。
PWA 应该对高级 API 执行特性检测并提供可接受的回退体验。
MDN 给出的经典例子是后台同步:
例如,后台同步 API 使 PWA 可以要求服务工作线程在设备连接时尽快发出网络请求。这个经典的用例是消息传递。假设用户编写了一条消息,但当用户尝试发送消息时,设备处于离线状态。后台同步 API 使设备能够在连上网后在后台发送消息。在不支持后台同步的设备上,该应用程序应该让用户知道消息无法发送,并给他们再次重试的机会。
这句话要刻进 DNA:任何高级 API,都先做特性检测,再提供回退。本文后面所有代码都会遵守这个原则。
第二部分 价值篇:为什么要用 PWA
2.1 微软官方归纳的 PWA 四大权益
Microsoft Learn 把 PWA 的价值拆成了四组,非常成体系,这里完整呈现。
权益一:类似本机的体验
在设备上安装 PWA 时,其功能与其他应用一样。例如:
- PWA 有自己的应用程序图标,可以添加到设备的主屏幕或任务栏;
- 打开关联的文件类型时,可以自动启动 PWA;
- PWA 可以在用户登录时运行;
- 可以将 PWA 提交到应用商店,例如 Microsoft 应用商店。
权益二:高级功能
PWA 还有权访问高级功能。例如:
- 当设备脱机时,PWA 可以继续工作;
- PWA 支持推送通知;
- 即使应用程序未运行,PWA 也可以执行定期更新;
- PWA 可以访问硬件功能。
权益三:与 Web 相关的优势
最后,PWA 可以在 Web 浏览器中运行,就像在网站中一样。像网站一样运行,PWA 具有优势,例如:
- 可以通过搜索引擎为 PWA 编制索引;
- 可以从标准 Web 链接共享和启动 PWA;
- PWA 对用户来说是安全的,因为它们使用安全的 HTTPS 终结点和其他用户安全措施;
- PWA 适应用户的屏幕大小或方向以及输入法;
- PWA 可以使用 WebBluetooth、WebUSB、WebPayment、WebAuthn 或 WebAssembly 等高级 Web API。
权益四:降低开发成本
与需要每个平台(例如 Android、iOS 和每个桌面作系统)的特定独立代码库的已编译应用相比,PWA 的跨平台开发成本要低得多。
借助 PWA,可以使用网站、移动应用和桌面应用之间共享的单个代码库(跨作系统)。
微软还特别强调桌面场景的价值:
桌面计算仍然是许多用户的主要生产力环境。PWA 可以在继承该环境优势的桌面作系统上提供完全定制的可安装体验。但是,PWA 也可以安装在移动设备上,或直接在 Web 浏览器中使用。
2.2 缩小 Web 与原生之间的差距
微软给出了一个非常有力的观察——“目前,使用 Web 技术无法执行太多作”,许多曾经只能通过使用特定于设备的语言实现的功能,现在都可以通过使用标准 Web 技术来实现:
| 处理文件 | 读写本地文件系统 |
| 与其他应用共享内容 | 通过操作系统分享机制 |
| 访问剪贴板 | 读写系统剪贴板 |
| 在后台同步数据和提取资源 | Background Sync / Background Fetch |
| 访问设备硬件 | 例如蓝牙(WebBluetooth)和 USB(WebUSB) |
| 将内容存储在数据库中 | IndexedDB |
| 利用硬件加速图形 | Canvas / WebGL |
| 使用 CSS 布局、动画和筛选器创建高级设计 | CSS Layout / Animation / Filter |
| 使用 WebAssembly 运行近乎编译的性能代码 | WebAssembly |
借助 Microsoft Edge,桌面上的 PWA 可以充分利用这些功能,提供用户期望桌面应用能够执行的作。
2.3 真实商业案例:数据不说谎
这是最具有说服力的一部分。
微软引用的三个案例
| 星巴克 | PWA 每天增加了两次活跃用户;桌面版订单与移动的费率几乎相同 | Twitter 原始推文 |
| Trivago | 将 PWA 添加到主屏幕的用户增加了 150%;参与度增加导致酒店优惠的点击增加了 97% | Think with Google |
| Tinder | 使用 PWA 将加载时间从 11.91 秒缩短到 4.68 秒;该应用比编译的 Android 应用小 90% | Addy Osmani 的性能案例研究 |
微软建议:在 PWA 统计信息 网站上阅读更多成功案例。
web.dev 引用的四个案例
Hulu(美国视频在线播放服务公司)
Hulu 打造了渐进式 Web 应用版体验,以取代用户评价不佳和使用率不佳的桌面应用。正如 2019 年 Google I/O 大会上所分享的那样,一位开发者只需两周时间,就可以在其现有 Web 应用中研究和实现此体验。
**五个月内,96% 的旧版应用用户采用了 PWA,回访次数增加了 27%,互动度提高了 5.5%。**与仅位于标签页中的 PWA 相比,由于 PWA 位于启动器和任务栏中,因此更容易返回。
“一位开发者 + 两周”,这个投入产出比是 PWA 最打动决策者的地方。
JD.ID(印度尼西亚电子商务平台)
该平台希望通过专注于提升其 PWA 的性能和提供不受网络影响的稳定体验,扩大其在线影响力。通过这种增强型体验,该公司的整体移动转化率提高了 53%,安装应用的用户的转化率提高了 200%,日活跃用户数提高了 26%。
注意\”安装应用的用户的转化率提高了 200%\”——安装行为本身就是用户意图的强信号。
Clipchamp(浏览器内置的桌面级在线视频编辑器)
与标准桌面应用用户相比,PWA 用户的留存率提高了 9%。在 PWA 发布后的前 5 个月内,PWA 安装量每个月以 97% 的速度增长。
Gravit Designer(Corel Corporation 的矢量设计工具)
自向用户添加 PWA 作为安装选项以来,与其他平台和安装选项相比,PWA 用户的活跃度提高了 24%,重复用户增加了 31%,PWA 用户购买 Gravit Designer PRO 的可能性提高了 2.5 倍。
大厂的采用情况
web.dev 明确列举:许多大公司已在各种产品中发布了 PWA,包括
- Apple:AppStore Connect、Feedback Assistant
- Microsoft:Office 365、Windows 365
- Google:Duo、YouTube Music、云端硬盘
- Amazon:Luna
- Facebook:Instagram Lite、Gaming
流媒体与云游戏:PWA 能力的极限展示
自 2021 年起,大多数云游戏服务提供商都推出了渐进式 Web 应用,让您只需通过浏览器或安装 PWA,即可在任何设备(iPhone、Android、iPad、笔记本电脑、Mac 或 PC)上畅玩游戏机游戏。Amazon Luna、Microsoft Xbox Cloud Gaming、Facebook Gaming、Google Stadia、Nvidia GeForce Now 和 BlueStacks X 都通过浏览器以 PWA 的形式提供云游戏解决方案。
得益于 WebRTC、WebAssembly 和 GamePad API 等 Web 技术,它们都能在所有平台上提供出色的体验,性能接近原生应用。
这条信息有力地反驳了\”Web 做不了高性能应用\”的偏见。
2.4 兼容性全景:这不是\”未来技术\”,而是\”现在就能用\”
web.dev 给出了一组关键数据(数据源自 StatCounter 和 Can I Use):
| 支持离线操作的浏览器 | 97% |
| 网络用户可以安装 PWA | 88% |
桌面平台兼容性明细
| Windows 10 和 11 | Google Chrome、Microsoft Edge、Microsoft 商店 | Chrome 从 73 起;Edge 从 79 起 |
| ChromeOS | 内置 Chrome 浏览器、Play 商店 | Chrome 从 72 起;Play 商店从 85 起 |
| macOS、Linux 以及 Windows 7 和 8.x | Google Chrome、Microsoft Edge | Chrome 73 以上 |
注意(web.dev 原文):在桌面设备上,Safari 和 Firefox 不支持 PWA 安装。它们支持离线功能,但体验始终会在浏览器界面中启动。它可能会全屏显示,但绝不会在桌面设备上作为独立窗口显示。
MDN 的表述一致:
Firefox 和 Safari 不支持在任何桌面操作系统上安装 PWA。Chrome 和 Edge 支持在 Linux、Windows、macOS 和 Chromebook 上安装 PWA。
移动平台兼容性明细
| iOS 和 iPadOS | 第三方浏览器(iOS/iPadOS 16.4 起)、Safari(iOS 11.3 起)、AppStore(iOS/iPadOS 14 起,存在一些限制)、适用于企业分发的移动配置 |
| Android | Firefox、Google Chrome、Samsung Internet、Microsoft Edge、Opera、Brave、华为浏览器、百度、UCWeb、Play 商店(安装了 Google Chrome 的 72 版或与 TWA 兼容的浏览器)、Galaxy 商店、适用于企业分发的受管 Play iframe |
MDN 补充了 iOS 的一个关键分界点:
在 iOS 16.3 及更早版本上,PWA 只能通过 Safari 安装。 在 iOS 16.4 及更高版本上,PWA 可以通过 Safari、Chrome、Edge、Firefox 和 Orion 的分享菜单安装。
一个高频踩坑点:应用内浏览器
web.dev 给出了一条极其重要的提醒,很多运营同学都不知道:
注意:在 Android 和 iOS 设备上,用户无法通过许多应用内浏览器(例如 Facebook 移动浏览器、Instagram、Google 搜索应用或 Gmail)安装 PWA。
这意味着:如果你在微信、微博、Facebook App 里打开链接,用户是没法安装的。做推广落地页时必须考虑到这一点。
其他设备
web.dev 指出,一些其他小型设备也支持 PWA,例如游戏机(内置 Microsoft 商店的 Xbox)或 XR 设备(Microsoft Hololens、Facebook 的 Oculus 计划)。不过,其他内置浏览器的设备通常不接受 PWA,包括:
- 游戏机
- 智能电视
- 智能手表
- 汽车
您的 PWA 将始终在所有设备的浏览器中正常运行,但具有特定限制。借助这种在多部设备上运行的能力,您可以创建多设备历程,让用户可以在一台设备上启动任务,然后在另一台设备上完成该任务,并且数据会在两台设备之间同步,而所用的都是完全相同的已部署应用。
2.5 官方也坦诚的两大挑战
一份可信的技术资料不会只讲优点。web.dev 在\”挑战\”章节里非常坦诚地列出了问题。
挑战一:跨浏览器兼容性
Apple 是多设备世界中的重要公司,拥有 iOS、iPadOS、macOS 和 Safari。虽然 Apple 从未公开使用过 PWA 一词,但自 2018 年以来,他们一直在支持 iPhone 和 iPad 上 Safari 中可安装且支持离线的 PWA 技术。
不过,Apple 对 PWA 规范的实现缺少其他浏览器(尤其是由 Chromium 引擎提供支持的浏览器)所具备的许多功能。
在中间,我们还有 Firefox 及其 Gecko 引擎,其实现包括在 Android 上支持更多 PWA 规范,以及在桌面设备上支持较少的安装功能。
限制包括缺少推送通知、集成 API(例如 Web Bluetooth 或 WebNFC)以及安装促销技术,这些技术有助于用户了解他们可以安装当前网站以获得应用体验。此外,已实现的功能还存在一些 bug。
与所有 Web 开发一样,在发布 PWA 以及发布新的重大浏览器或操作系统版本时,您必须在每个平台上测试用户体验。您应始终在功能不可用时提供后备解决方案或替代体验。
挑战二:对 PWA 的认知度
作为 PWA 开发者,您可能会遇到企业和用户方面都缺乏认知度的问题。有些商家所有者可能不了解 PWA,或者对渐进式 Web 应用的强大功能和面临的挑战有误解。
发布 PWA 后,您面临的下一项挑战是确保用户了解该网站可供安装。
在某些平台(例如 iOS 和 iPadOS)上,安装难度更大,有时用户体验设计师会添加屏幕来向用户说明如何安装应用。
这就是为什么\”自定义安装提示\”(本文 5.x 节会讲到)几乎是所有生产级 PWA 的标配。
兼容性的正确心态
web.dev 给出了一段方法论,值得反复读:
您需要记住,渐进式 Web 应用只是一个 Web 应用,因此内容和服务在标准规范和协议的基础上运行。因此,从技术层面讲,PWA 可在 Web 运行的任何地方运行;您无需让平台与任何\”PWA 规范\”兼容。
不过,当我们谈论 PWA 和兼容性时,通常会考虑跨越浏览器和仅限在线情境边界的功能:图标安装和离线支持。
注意:PWA 应在任何地方运行,即使图标安装或离线支持功能不可用也是如此。请务必通过检查支持情况并提供后备解决方案,使您的 PWA 在没有这些功能的情况下也能正常运行。
第三部分 环境准备篇:把本地跑通链路打通
3.1 你需要准备什么
| 编辑器 | 任意(推荐 VS Code) | 无特殊要求 |
| 浏览器 | 推荐 Chrome 或 Edge(基于 Chromium) | MDN:Chrome 和 Edge 支持在 Linux、Windows、macOS 和 Chromebook 上安装 PWA |
| 本地服务器 | 任意静态服务器 | localhost / 127.0.0.1 被视为安全上下文 |
| 图标 | 至少 192×192 与 512×512 的 PNG | 可安装性的必需清单成员之一 |
关于 HTTPS,再次强调 MDN 的规定:
要使 Web 应用程序可安装,它必须在安全上下文中提供。通常意味着它必须通过 HTTPS 提供。本地资源,如 localhost、127.0.0.1 和 file:// 也被视为安全。
3.2 三种本地起服务的方式
方式一:Python(最省事)
# 进入项目目录后执行(Python 3)
python -m http.server 8080
方式二:Node.js
npx serve -l 8080
# 或者
npx http-server -p 8080
方式三:VS Code 插件 Live Server
安装 Live Server 插件后,右键 index.html → “Open with Live Server”,默认会打开 http://127.0.0.1:5500。
注意:不要直接双击打开 index.html(file:// 协议)。虽然 MDN 把 file:// 也列为安全上下文,但 Service Worker 的作用域(scope)机制在 file:// 下无法正常工作,会导致注册失败。请务必使用本地 HTTP 服务器。
3.3 DevTools 调试面板速查
MDN 列出了三大浏览器的 Service Worker 调试文档:
- Chrome:https://www.chromium.org/blink/serviceworker/service-worker-faq/
- Firefox:https://firefox-source-docs.mozilla.org/devtools-user/application/service_workers/index.html
- Edge:https://learn.microsoft.com/zh-CN/microsoft-edge/devtools-guide-chromium/service-workers/
在 Chrome / Edge 中,打开 F12 → Application(应用) 面板,你会用到这几个子面板:
| Manifest | 检查清单是否被正确解析;会显示\”Installability(可安装性)\”错误 |
| Service Workers | 查看注册状态、手动 Update / Unregister、勾选 Offline 模拟离线、Update on reload |
| Cache Storage | 查看 caches 里到底缓存了哪些资源,可手动删除 |
| Storage | 查看 / 清空 localStorage、IndexedDB |
| Lighthouse | 一键生成 PWA 审计报告 |
调试小贴士:Firefox 工具栏自定义选项中的\”Forget about this site\”按钮可用于清除 service worker 及其缓存(MDN 原文提示)。
3.4 快速自检清单(在写代码之前先记住)
来自 MDN 的\”可安装性\”三要素,做 PWA 之前请倒背如流:
第四部分 实战篇:从 0 到 1 手写一个 TodoPWA
终于到了动手环节。我们要做的项目叫 TodoPWA,一个待办清单应用。选它的理由是:它足够小(你能看懂每一行),又足够完整(能覆盖 PWA 的几乎所有关键能力)。
最终效果:
- 打开就是独立窗口,没有地址栏(display: standalone)
- 断网后照样能新增、勾选、删除待办(Service Worker + localStorage)
- 地址栏出现\”安装\”图标,也可以点页面内的按钮安装(beforeinstallprompt)
- 应用图标上显示未完成数量(Badging API)
- 右键 / 长按图标出现\”新建待办\”快捷方式(shortcuts)
- 可以把待办内容分享给其他 App(Web Share API)
- 断网时有专门的离线提示页面(自定义离线页面)
4.1 项目目录结构
todopwa/
├── index.html # 主页面(PWA 的唯一 HTML 入口)
├── offline.html # 离线回退页面
├── styles.css # 样式(含响应式 + 深色模式)
├── app.js # 主应用逻辑(UI 线程)
├── sw.js # Service Worker(离线/后台线程)
├── manifest.webmanifest # Web 应用清单
└── icons/
├── icon-192.png # 192×192 普通图标
├── icon-512.png # 512×512 普通图标
├── icon-maskable-512.png # 512×512 可掩码图标
└── shortcut-add.png # 快捷方式图标
说明:下文所有代码均假设应用部署在站点根目录(例如 https://example.com/ 或 http://127.0.0.1:8080/)。如果你要放在子目录(如 /demo/),请把 start_url、scope、sw.js 的路径、PRECACHE_URLS 中的路径一并改成对应的子目录前缀。
4.2 Step 1:HTML 骨架(index.html)
<!doctype html>
<html lang=\”zh-CN\”>
<head>
<meta charset=\”UTF-8\” />
<meta name=\”viewport\” content=\”width=device-width, initial-scale=1\” />
<title>TodoPWA · 离线待办清单</title>
<meta
name=\”description\”
content=\”一个可以安装到桌面与手机、断网也能使用的渐进式 Web 待办清单应用。\”
/>
<!– ① 页面级主题色:会覆盖 manifest 中的 theme_color(MDN 明确说明) –>
<meta name=\”theme-color\” content=\”#4f46e5\” media=\”(prefers-color-scheme: light)\” />
<meta name=\”theme-color\” content=\”#1e1b4b\” media=\”(prefers-color-scheme: dark)\” />
<!– ② 引入 Web 应用清单:PWA 可安装的必要条件之一 –>
<link rel=\”manifest\” href=\”manifest.webmanifest\” />
<!– ③ 普通图标与 iOS 图标 –>
<link rel=\”icon\” href=\”icons/icon-192.png\” sizes=\”192×192\” />
<link rel=\”apple-touch-icon\” href=\”icons/icon-192.png\” />
<link rel=\”stylesheet\” href=\”styles.css\” />
</head>
<body>
<header class=\”app-header\”>
<div class=\”header-main\”>
<h1 class=\”app-title\”>TodoPWA</h1>
<p class=\”app-subtitle\”>一个可以安装、断网也能用的待办清单</p>
</div>
<div class=\”header-actions\”>
<!– ④ 网络状态指示器 –>
<span id=\”status-dot\” class=\”status-dot\” aria-hidden=\”true\”></span>
<span id=\”status-text\” class=\”status-text\” role=\”status\”>在线</span>
<!– ⑤ 分享按钮:只有浏览器支持时才显示(特性检测 + 渐进增强) –>
<button id=\”share-button\” type=\”button\” class=\”ghost-button\” hidden>分享</button>
<!– ⑥ 自定义安装按钮:默认隐藏,等 beforeinstallprompt 事件触发后再显示 –>
<button id=\”install-button\” type=\”button\” class=\”primary-button\” hidden>
安装到桌面
</button>
</div>
</header>
<main class=\”app-main\”>
<!– ⑦ 新建待办表单:用真实语义化 form 元素,保证无 JS 场景下也能降级 –>
<form id=\”todo-form\” class=\”todo-form\” autocomplete=\”off\”>
<label class=\”sr-only\” for=\”todo-input\”>新建待办</label>
<input
id=\”todo-input\”
name=\”text\”
class=\”todo-input\”
type=\”text\”
maxlength=\”120\”
placeholder=\”今天要做什么?回车即可添加\”
required
/>
<button type=\”submit\” class=\”primary-button\”>添加</button>
</form>
<!– ⑧ 过滤切换 –>
<div class=\”filter-bar\” role=\”group\” aria-label=\”待办过滤\”>
<button type=\”button\” class=\”filter-button is-active\” data-filter=\”all\”>全部</button>
<button type=\”button\” class=\”filter-button\” data-filter=\”active\”>未完成</button>
<button type=\”button\” class=\”filter-button\” data-filter=\”done\”>已完成</button>
</div>
<!– ⑨ 列表容器 –>
<ul id=\”todo-list\” class=\”todo-list\”></ul>
<p id=\”empty-tip\” class=\”empty-tip\” hidden>还没有待办,先加一条试试。</p>
<footer class=\”app-footer\”>
<span id=\”count-label\” class=\”count-label\”>共 0 条,未完成 0 条</span>
</footer>
</main>
<script src=\”app.js\” defer></script>
</body>
</html>
代码要点解析:
| ② | <link rel=\”manifest\” href=\”manifest.webmanifest\” /> 是 MDN 给出的标准引入方式 | MDN:清单通过 <link> 元素引入;如果 PWA 有多个页面,每个页面都必须以这种方式引用清单 |
| ① | <meta name=\”theme-color\”> 会覆盖 manifest 的 theme_color | MDN:如果两者都设置了,theme-color meta 元素值会覆盖 theme_color 清单成员 |
| ⑥ | 按钮默认带 hidden 属性 | MDN:如果用户使用无法安装的浏览器访问,我们不希望安装 UI 可见 |
| ⑦ | 使用语义化 <form> | MDN 最佳实践:用 HTML <form> 处理提交意味着该表单将在所有浏览器上工作,包括不支持 JavaScript 的浏览器 |
4.3 Step 2:样式(styles.css)
/* ============================================================
* styles.css —— TodoPWA 样式
* 设计要点(均来自 MDN 最佳实践):
* 1. 响应式设计:不同视口下重排内容
* 2. 使用 system-ui 字体,让内容更像平台原生,且无需下载字体、加载更快
* 3. 使用 prefers-color-scheme 检测用户偏好的主题
* 4. 使用语义化元素 + :focus-visible 保证键盘可达性
* ============================================================ */
:root {
–bg: #f8fafc;
–surface: #ffffff;
–text: #0f172a;
–text-muted: #64748b;
–border: #e2e8f0;
–brand: #4f46e5;
–brand-weak: #eef2ff;
–danger: #dc2626;
–radius: 12px;
}
@media (prefers-color-scheme: dark) {
:root {
–bg: #0f172a;
–surface: #1e293b;
–text: #e2e8f0;
–text-muted: #94a3b8;
–border: #334155;
–brand: #818cf8;
–brand-weak: #312e81;
}
}
* {
box-sizing: border-box;
}
/* 关键点:使用 system-ui,使内容感觉更像原生于平台(MDN 最佳实践明确推荐) */
body {
margin: 0;
min-height: 100vh;
background: var(–bg);
color: var(–text);
font-family: system-ui, -apple-system, \”Segoe UI\”, \”Microsoft YaHei\”, sans-serif;
line-height: 1.6;
}
/* 屏幕阅读器专用:视觉上隐藏但可被辅助技术读取 */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* ———- 头部 ———- */
.app-header {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
background: var(–surface);
border-bottom: 1px solid var(–border);
/* 为独立的 PWA 窗口留出顶部安全区 */
padding-top: max(16px, env(safe-area-inset-top));
}
.app-title {
margin: 0;
font-size: 20px;
letter-spacing: 0.5px;
}
.app-subtitle {
margin: 2px 0 0;
font-size: 13px;
color: var(–text-muted);
}
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}
/* ———- 网络状态指示器 ———- */
.status-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #22c55e;
flex: none;
}
.status-dot.is-offline {
background: #f59e



