一、PWA是什么
1、直观感受
可以直接访问 PWA 直接的感受下PWA长什么样。访问了上述网站之后,可以在浏览器的地址栏中看到一个下载的图标,点击下载之后就会下载一个本地应用,这个就是PWA了, 这个PWA的功能就是可以双击全屏的一个黑色图片。这个 PWA 在断网的情况下也可以正常访问。
2、传统WEB和原生应用
在深入探讨PWA(Progressive Web App)之前,我们有必要回顾Web与原生应用的技术博弈史。现代浏览器已从简单的文档解析器演进为功能完备的运行时环境——Chrome浏览器整合了超过50个核心子系统,支持WebAssembly、WebGL、WebRTC等尖端技术规范,其复杂度堪比轻量级操作系统。据统计,全球Top 1000应用中有72%已提供对应的Web版本(数据来源:HTTP Archive 2023),印证了"浏览器即平台"的技术趋势。
然而,传统Web应用在用户体验层面仍面临双重挑战:
- 网络依赖性:全球仍有17%的移动用户处于2G/3G网络环境(GSMA 2023数据),传统网页在离线场景下的不可用性导致关键业务中断
- 性能瓶颈:移动端网页平均加载时间超过3秒时,53%的用户会选择离开(Google Core Web Vitals报告)
相比之下,原生应用凭借以下优势占据移动生态:
✅ 本地资源预加载带来的60fps流畅交互
✅ 后台同步、推送通知等系统级功能集成
✅ 基于Metal/Vulkan的图形渲染性能
但原生开发的高昂成本不容忽视:
⛔ 多平台(iOS/Android/Windows)需维护独立代码库
⛔ 平均安装包体积达82MB(Android Studio 2023统计)
⛔ 应用商店审核导致更新延迟(平均72小时)
3、PWA
好了,在了解了app应用和网页应用的优缺点之后,我们再来看看PWA。
首先什么是PWA?PWA的全称是progressive web app,直译就是渐进式web应用。这里web应用应该很好理解,说明PWA是一个基于网页的应用程序。
那什么是渐进式呢?我们都知道渐进的意思是从一个东西慢慢变成另一个东西,中间是有过度过程的,那这里说的渐进式是指的从什么过度到什么呢?实际上这里指的是从网页应用逐步的变成原生应用。也就是说PWA是一个集合了网页应用和原生应用特性的集合体。
二、PWA的特点
在简单了解什么是PWA之后,我们来看看PWA有什么特点。
2.1、PWA 具有网站的优势
- PWA 是使用标准的 web 平台技术开发的,也就是我们所熟悉的html、css、js,所以它们可以从单一代码库在多个操作系统和设备类上运行。
- PWA 可以直接通过 web 访问。
2.2、PWA 可以安装在设备上
- PWA 可以从平台的应用商店安装,也可以直接从 web 安装。
- PWA 可以像平台特定的应用程序一样安装,并可以自定义安装过程。
- 一旦安装,PWA 会在设备上得到一个应用图标,与平台特定应用程序一样。
- 一旦安装,PWA 可以作为独立的应用程序启动,而不是作为浏览器中的网站。
- PWA 可以在后台与离线操作:一个典型的网站只在被浏览器加载后才处于活动状态。PWA 可以:
- 在设备没有网络连接时工作。
- 在后台更新内容。
- 对来自服务器的推送消息做出响应。
- 使用操作系统的通知系统显示通知。
- PWA 可以使用整个屏幕,而不是在浏览器 UI 中运行。
- PWA 可以与设备集成,注册为共享目标和来源,并访问设备特性。
- PWA 可以在应用商店以及通过 web 公开发布。
简而言之,PWA就是一个集成了传统网站和应用app优点的集合。
好了,上面介绍了传统web、原生app、PWA,我们用一个表格来总结下3者的特点:
维度 | 原生应用 | 传统Web | PWA |
---|---|---|---|
安装体积 | 50-200MB | 0 | 50-500KB (预缓存资源) |
网络依赖 | 可选功能离线 | 完全依赖网络 | 核心功能离线 |
系统集成 | 完整API访问 | 受限访问 | 渐进式API访问 |
更新机制 | 应用商店审核 | 即时更新 | 静默更新+版本控制 |
跨平台成本 | 多代码库 | 单一代码库 | 单一代码库+平台适配层 |
三、实现一个PWA
上面解释了这么多什么是PWA,以及PWA的特点,对于程序员来说都太虚了,让我们进入到程序员最关心的步骤,实现一个PWA。
talk is cheap,show me the code
3.1、PWA的组成
一个最简单的PWA由3个文件组成,一个是html文件,用于展示内容,一个manifest.json文件用于描述PWA,一个service work也就是js文件。
├── src/
│ ├── index.html # 应用入口
│ ├── manifest.webmanifest # 安装描述文件
│ └── sw.js # Service Worker核心
├── public/ # 静态资源
│ ├── icons/
│ │ ├── icon-512.webp
│ │ └── maskable-icon.webp
│ └── splash/
│ └── splash-1080p.jpg
└── server.js # 本地开发服务器
3.2、PWA版本的hello world
3.2.1、helloworld.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello PWA</title>
<!-- 引入Web App Manifest -->
<link rel="manifest" href="/manifest.json">
</head>
<body>
<h1>Hello World</h1>
<!-- 注册Service Worker -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(reg => console.log('ServiceWorker已注册'))
.catch(err => console.log('注册失败:', err));
}
</script>
</body>
</html>
- 这个html文件的功能就是在网页上显示一句hello world
- 要实现PWA,和普通的html文件相比,多了2个东西,
- 在head中要引入manifest文件
- 在script代码块中加载sw.js,也就是service work
3.2.2、manifest文件
{
"name": "Hello PWA",
"short_name": "PWA Demo",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3498db",
"icons": [
{
"src": "/images/icon-512x512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "/images/icon-512x512.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
]
}
这个就是PWA应用需要的manifest文件,下面我详细解释下每个参数的作用
3.2.2.1、基础标识字段
字段 | 值 | 作用 |
---|---|---|
name | "Hello PWA" | 应用全名,显示在浏览器安装提示、启动画面、应用商店 |
short_name | "PWA Demo" | 短名称,用于主屏幕图标下方、任务切换器 |
3.2.2.2、 视觉呈现控制
字段 | 值 | 作用 |
---|---|---|
display | "standalone" | 显示模式控制: standalone:隐藏地址栏和浏览器控件,fullscreen:全屏(适合游戏),minimal-ui:保留基础导航控件 |
background_color | "#ffffff" | 启动画面背景色(必须与CSS背景一致) |
theme_color | "#3498db" | 控制浏览器地址栏/状态栏颜色 |
3.2.2.3、导航与启动
字段 | 值 | 作用 |
---|---|---|
start_url | "/" | 用户点击图标后加载的初始页面; 支持带参数路径(如/?from=pwa) |
3.2.2.4、 图标配置(核心重点)
"icons": [
{
"src": "/images/icon-512x512.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "/images/icon-512x512.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
]
关键配置说明:
src
图标文件路径(需确保服务器可访问该路径)
问题提醒:当前两个图标使用相同文件,建议提供不同尺寸(至少包含 192x192 和 512x512)sizes
声明图标尺寸,浏览器自动选择最合适的
必须与文件实际尺寸一致(否则会拉伸失真)-
purpose
- maskable:允许操作系统对图标进行遮罩处理(适配圆角/特殊形状的图标显示)
- any:默认值,图标完整显示不裁剪
- 推荐至少提供一个 maskable 图标(提升安卓设备显示效果)
3.3.3、 sw.js文件
const CACHE_NAME = 'hello-pwa-v1';
const urlsToCache = ['/', '/helloworld.html'];
// 安装阶段:缓存核心资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
// 拦截请求:优先返回缓存内容
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
这个就是PWA应用需要的service worker,通过上面的注释就可以看到,这个service worker主要实现了2个功能,一个是安装PWA到本地,一个是拦截用户的http请求,优先返回缓存中的内容,urlsToCache变量中定义了要缓存的内容。这里缓存的是helloworld.html文件内容。这样在断网的情况下也可以继续访问helloworld.html的内容。
有了以上3个文件, 一个PWA就完成了,可以在本地起一个服务运行上面的网页,就可以看到浏览器上出现了按照PWA的按钮,点击之后就会下载PWA到本地。后面断网之后仍然可以访问hellworld.html的内容。
上面就是PWA应用的hello world版本,大家可以自己尝试下。
4、启程时刻
PWA不是昙花一现的技术热潮,而是重塑Web生态的里程碑。从本文的Hello World出发,您已掌握打开新世界的钥匙。当您下次在地铁无网络环境下流畅打开自己的PWA应用时,或许会真切感受到——Web的未来,此刻正在您手中构建。