多多读书
1149 字
6 分钟
APP开发的终点PWA

大家都知道,如今开发和推出一个 APP 变得越来越困难。因此,选择开发具有 APP 体验的 Web 应用是一个不错的选择。渐进式网络应用(Progressive Web App,简称 PWA)是一种结合了网页和传统移动应用的开发技术。它利用了现代的 Web 技术,如 Service Workers 和 Web App Manifest 等,使得网页应用能够拥有类似原生应用的功能和用户体验。具体来说,PWA 可以创建快捷方式到用户的主屏幕上,并且支持离线访问数据和接收推送通知等功能,为用户提供了更加流畅、可靠的应用体验。

PWA 的优点:#

  • 跨平台兼容性:PWA 可以在各种设备和操作系统上运行,无需为不同平台开发单独的应用,大大减少了开发和维护成本。
  • 可发现性:PWA 可以通过 Web 搜索引擎被搜索到,使得应用更容易被用户发现和访问。
  • 离线访问:通过使用 Service Workers,PWA 可以缓存应用的核心文件和数据,使得用户在离线状态下也能够访问应用内容。
  • 快速加载:PWA 利用缓存机制和增量更新,使得应用可以快速加载和响应用户操作,提供更好的性能体验。
  • 推送通知:PWA 可以向用户发送推送通知,增强用户参与度和留存率。

PWA 的缺点:#

  • 功能受限:由于依赖于 Web 技术,PWA 在某些功能上可能无法与原生应用相媲美,如访问设备硬件等。
  • 兼容性问题:虽然 PWA 在现代浏览器上有较好的支持,但在一些旧版本浏览器上可能存在兼容性问题。
  • 学习成本:相对于传统的 Web 开发,PWA 需要开发人员熟悉新的技术和开发模式,可能存在一定的学习曲线。

三个要素#

要使你的网站转换成 PWA,需要以下三个关键要素:

  1. Web App Manifest:实现将 PWA 网页应用添加到桌面的功能。
  2. Service Worker:用于缓存应用的核心文件和数据,实现离线访问和快速加载等功能。
  3. HTTPS:HTTP 是 PWA 强制要求的,用来保证程序的安全性,本地调试可以使用 http://localhost。

Web App Manifest#

接下来我将使用 vite 构建 react 应用模板并转换成 PWA,先创建项目。

然后在 public 目录下创建 manifest.json 文件和 icons 目录放置 icon 图片。为什么要在 public 目录下?因为 public 目录下的文件打包时会直接复制到 dist 目录下。

manifest.json#

{
  "name": "Dodo Reader",
  "short_name": "Dodo Reader",
  "description": "Dodo Reader是一个支持阅读PDF、EPUB和TXT文件格式的Web应用程序",
  "icons": [
    {
      "src": "icons/icon-32.png",
      "sizes": "32x32",
      "type": "image/png"
    },
    // ...
    {
      "src": "icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "/index.html",
  "display": "fullscreen",
  "theme_color": "#FFFFFF",
  "background_color": "#FFFFFF"
}

这些字段看名称几乎都能知道它的作用,其中display包含fullscreenstandaloneminimal-uibrowser。然后在根目录下的 index.html 中 head 内添加如下代码:

<link rel="manifest" href="manifest.json" />

完成之后启动服务,如果在浏览器上能看到添加应用图标,表示配置成功。

Service Worker#

Service Worker 可以缓存资源,实现离线时的资源访问,并在离线状态下提供更好的用户体验。首先在 public 目录下添加文件 service-worker.js,并添加如下代码:

const deleteCache = async (key) => {
  await caches.delete(key)
}

const deleteOldCaches = async () => {
  const cacheKeepList = ['v1']
  const keyList = await caches.keys()
  const cachesToDelete = keyList.filter((key) => !cacheKeepList.includes(key))
  await Promise.all(cachesToDelete.map(deleteCache))
}

self.addEventListener('activate', (event) => {
  // 删除旧版本资源缓存
  event.waitUntil(deleteOldCaches())
})

const putInCache = async (request, response) => {
  const cache = await caches.open('v1')
  await cache.put(request, response)
}

const cacheFirst = async (request) => {
  // 判断是否有缓存
  const responseFromCache = await caches.match(request)
  if (responseFromCache) {
    return responseFromCache
  }
  // 如没有缓存,请求并缓存
  const responseFromNetwork = await fetch(request)
  putInCache(request, responseFromNetwork.clone())
  return responseFromNetwork
}

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url)
  // 判断是否当前站点资源请求
  if (url.origin === location.origin) {
    event.respondWith(cacheFirst(event.request))
  }
})

然后在 src/main.tsx 文件添加注册代码:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/service-worker.js')
    .then(function () {
      console.log('Service worker installed')
    })
    .catch(function (error) {
      console.log('Service Worker registration failed:', error)
    })
}

添加完成可以验证一下是否挂载成功,到开发者工具中应用程序面板查看缓存存储,如果有内容表示成功缓存。

这个时候即使断开网络也是可以访问的。

HTTPS#

HTTP 不用多说,上线之后一定要配置,不然无法生效。

下面是我在 PC 桌面端添加的样例。

APP开发的终点PWA
https://fuwari.vercel.app/posts/20230919/
作者
我也困了
发布于
2023-09-19
许可协议
CC BY-NC-SA 4.0