在移动互联网时代,用户对应用的体验要求越来越高。Uniapp 作为跨平台开发的利器,能让我们一套代码运行多端,但 Web 端体验往往不如原生 App——比如无法离线访问、不能添加到桌面、启动时白屏等。而 PWA(Progressive Web App,渐进式 Web 应用)的核心能力恰好能解决这些痛点。本文将带你从 0 到 1 实现 Uniapp 集成 PWA 核心能力,包括离线缓存、添加到桌面、启动页定制,让你的 Web 端应用更接近原生体验。

一、前置知识:什么是 PWA 及核心能力

PWA 不是单一技术,而是一系列 Web 技术的集合,核心目标是让 Web 应用拥有原生 App 的体验。其关键能力包括:

  • 离线缓存:通过 Service Worker 拦截网络请求,缓存核心资源,实现离线访问或弱网下快速加载;

  • 添加到桌面:支持用户将应用添加到手机/电脑桌面,像原生 App 一样启动,无需通过浏览器访问;

  • 启动页定制:通过 Web App Manifest 配置启动页(闪屏),解决启动白屏问题,提升品牌辨识度;

  • 其他能力:推送通知、后台同步等(本文重点聚焦前三项核心能力)。

Uniapp 本身对 PWA 有一定的支持,但需要手动配置和扩展,下面我们逐步实现。

二、环境准备

在开始集成前,确保你已具备以下环境:

  1. Uniapp 项目:已创建并能正常运行(本文基于 Vue 3 + Vite 版本,Vue 2 版本配置类似,略有差异);

  2. 开发工具:HBuilderX 或 VS Code + Uniapp 插件;

  3. 测试环境:支持 HTTPS 的服务器(PWA 核心能力依赖 HTTPS,本地测试可使用localhost 或开启 SSL 的本地服务);

  4. 依赖包:workbox-cli(用于生成 Service Worker,简化离线缓存配置)。

首先,安装 workbox-cli(全局安装或项目本地安装均可):


npm install workbox-cli -g
# 或本地安装
npm install workbox-cli --save-dev

三、核心步骤 1:配置 Web App Manifest(实现添加到桌面 + 启动页定制)

Web App Manifest 是一个 JSON 文件,用于定义应用的名称、图标、启动页、显示模式等信息,是实现“添加到桌面”和“启动页定制”的基础。

3.1 创建 Manifest 文件

在 Uniapp 项目的 public 目录下(Vue 3 + Vite 项目,Vue 2 项目为 static 目录),创建 manifest.json 文件,内容如下:


{
  "name": "我的 Uniapp PWA 应用", // 应用全称(添加到桌面时显示)
  "short_name": "Uniapp PWA", // 应用简称(桌面图标下方显示)
  "start_url": "/", // 启动页 URL(默认根路径)
  "display": "standalone", // 显示模式:standalone(类似原生 App,无浏览器导航栏)
  "background_color": "#ffffff", // 启动页背景色(与启动页图片背景色一致,避免闪屏)
  "theme_color": "#42b983", // 主题色(浏览器地址栏/状态栏颜色)
  "icons": [ // 应用图标(不同尺寸,适配不同设备)
    {
      "src": "icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png",
      "purpose": "maskable" // 适配圆形/异形图标(部分安卓设备)
    }
  ],
  "splash_pages": null // 禁用默认闪屏,使用自定义启动页
}

3.2 放置图标资源

public 目录下创建 icons 文件夹,放入上述配置中对应的图标(建议使用工具生成不同尺寸的图标,比如 favicon-generator)。

3.3 在 index.html 中引入 Manifest

修改 public/index.html,在 <head> 标签中添加以下代码,引入 Manifest 文件并配置相关元标签:


<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    <!-- 引入 Manifest -->
    <link rel="manifest" href="/manifest.json"&gt;
    <!-- 适配 iOS 设备(iOS 不完全支持 manifest,需额外配置) -->
    <link rel="apple-touch-icon" href="/icons/icon-192x192.png"&gt; <!-- iOS 桌面图标 -->
    <meta name="apple-mobile-web-app-capable" content="yes"&gt; <!-- 启用全屏模式 -->
    <meta name="apple-mobile-web-app-status-bar-style" content="#42b983"&gt; <!-- iOS 状态栏颜色 -->
    <meta name="apple-mobile-web-app-title" content="Uniapp PWA"&gt; <!-- iOS 应用名称 -->
    <!-- 启动页适配 iOS -->
    <link rel="apple-touch-startup-image" href="/icons/splash-640x1136.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)">
    <link rel="apple-touch-startup-image" href="/icons/splash-750x1334.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)">
    <link rel="apple-touch-startup-image" href="/icons/splash-1242x2208.png" media="(device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3)"&gt;
    <!-- 标题 -->
    <title>我的 Uniapp PWA 应用</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

说明:iOS 对 PWA 的支持不如安卓完善,需要通过 apple-touch-* 系列元标签额外配置图标和启动页。

3.4 测试“添加到桌面”功能

  1. 运行 Uniapp 项目,构建 Web 端产物(npm run build:h5);

  2. 将构建后的 dist/build/h5 目录部署到支持 HTTPS 的服务器(或本地使用 serve -s dist/build/h5 --ssl-cert cert.pem --ssl-key key.pem 启动 HTTPS 服务);

  3. 用手机浏览器(推荐 Chrome、Edge 或 Safari)访问部署后的地址:

  • 安卓:点击浏览器菜单,选择“添加到桌面”;

  • iOS:点击 Safari 分享按钮,选择“添加到主屏幕”。

添加成功后,桌面会出现配置的应用图标,点击即可像原生 App 一样启动应用。

四、核心步骤 2:集成 Service Worker(实现离线缓存)

Service Worker 是一个运行在浏览器后台的脚本,独立于网页线程,能够拦截和处理网络请求,从而实现离线缓存。Uniapp 本身不自带 Service Worker 配置,我们使用 Workbox 工具来简化配置。

4.1 创建 Workbox 配置文件

在 Uniapp 项目根目录下,创建 workbox-config.js 文件,配置缓存规则:


module.exports = {
  globDirectory: 'dist/build/h5', // 待缓存的文件目录(Web 端构建产物目录)
  globPatterns: [ // 缓存文件匹配规则
    '**/*.{html,css,js,json,png,jpg,jpeg,gif,svg,woff,woff2,eot,ttf}'
  ],
  swDest: 'dist/build/h5/sw.js', // 生成的 Service Worker 文件路径
  runtimeCaching: [ // 运行时缓存规则(动态资源,如接口请求)
    {
      urlPattern: /^https:\/\/api\.example\.com/, // 匹配需要缓存的接口域名
      handler: 'NetworkFirst', // 策略:优先网络,网络失败时使用缓存
      options: {
        cacheName: 'api-cache', // 缓存名称
        cacheableResponse: {
          statuses: [200] // 只缓存 200 状态码的响应
        },
        expiration: {
          maxEntries: 50, // 最大缓存条目数
          maxAgeSeconds: 60 * 60 * 24 // 缓存有效期:24 小时
        }
      }
    }
  ],
  skipWaiting: true, // 新的 Service Worker 安装完成后立即激活,无需等待旧的 Service Worker 退出
  clientsClaim: true // 激活后立即控制所有打开的客户端(网页)
};

缓存策略说明:

  • CacheFirst:优先使用缓存,适用于静态资源(如图片、CSS、JS);

  • NetworkFirst:优先使用网络,适用于动态接口(确保数据最新,网络失败时用缓存兜底);

  • StaleWhileRevalidate:先使用缓存,同时后台请求更新缓存,适用于非核心动态资源。

4.2 生成 Service Worker 文件

package.json 中添加脚本,用于生成 Service Worker:


{
  "scripts": {
    "build:h5": "uni build --platform h5",
    "build:h5:pwa": "npm run build:h5 && workbox generateSW workbox-config.js"
  }
}

执行以下命令,构建 Web 端并生成 Service Worker:


npm run build:h5:pwa

执行完成后,会在 dist/build/h5 目录下生成 sw.js(Service Worker 脚本)和 workbox-*.js(Workbox 核心库)。

4.3 注册 Service Worker

在 Uniapp 项目的入口文件(如 src/main.js)中,添加 Service Worker 注册代码:


import { createApp } from 'vue'
import App from './App.vue'
import uView from 'uview-plus'
import 'uview-plus/dist/uview-plus.css'

const app = createApp(App)
app.use(uView)
app.mount('#app')

// 注册 Service Worker(仅在 Web 端且支持 Service Worker 的浏览器中执行)
if (process.env.VUE_APP_PLATFORM === 'h5' && 'serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(registration => {
        console.log('Service Worker 注册成功:', registration.scope)
      })
      .catch(error => {
        console.error('Service Worker 注册失败:', error)
      })
  })
}

说明:process.env.VUE_APP_PLATFORM === 'h5' 用于判断当前环境为 Web 端,避免在其他端(如 App、小程序)执行该代码。

4.4 测试离线缓存功能

  1. 将重新构建后的 dist/build/h5 目录部署到服务器;

  2. 用浏览器访问应用,先正常浏览页面(让 Service Worker 缓存资源);

  3. 打开浏览器开发者工具(F12),切换到 Application 面板:

  • 查看 Service Workers 选项,确认 sw.js 已激活;

  • 查看 Cache Storage 选项,可看到缓存的静态资源和接口数据。

  1. 断开网络(关闭 WiFi 和数据流量),刷新页面:

如果页面能正常显示(静态资源加载成功),且之前缓存的接口数据能正常展示,说明离线缓存功能实现成功。

五、核心步骤 3:定制启动页(优化启动体验)

虽然通过 Manifest 配置了启动页,但 Uniapp Web 端启动时可能仍会出现短暂白屏(因 Vue 初始化需要时间)。我们可以通过以下方式优化:

5.1 静态启动页占位

public/index.html#app 容器中添加静态启动页内容,与 Manifest 配置的启动页风格一致:


&lt;div id="app"&gt;
  <!-- 静态启动页 -->
  <div class="splash-screen">
    <img src="/icons/icon-512x512.png" alt="应用图标" class="splash-icon">
    <p class="splash-text">我的 Uniapp PWA 应用</p>
  </div>
</div>
<style>
  /* 启动页样式 */
  .splash-screen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #ffffff;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 9999;
  }
  .splash-icon {
    width: 80px;
    height: 80px;
    border-radius: 16px;
    margin-bottom: 20px;
  }
  .splash-text {
    font-size: 18px;
    color: #42b983;
    font-weight: bold;
  }
</style>

5.2 Vue 初始化完成后隐藏启动页

src/App.vue 中,添加 onMounted 钩子,在 Vue 初始化完成后隐藏静态启动页:


<script setup>
import { onMounted } from 'vue'

onMounted(() => {
  // 隐藏静态启动页
  const splashScreen = document.querySelector('.splash-screen')
  if (splashScreen) {
    // 添加过渡动画,提升体验
    splashScreen.style.opacity = '0'
    splashScreen.style.transition = 'opacity 0.5s ease-out'
    setTimeout(() => {
      splashScreen.style.display = 'none'
    }, 500)
  }
})
</script>

<template>
  <view class="app">
    <!-- 应用内容 -->
    <router-view></router-view>
  </view>
</template>

这样,启动时会先显示静态启动页,待 Vue 初始化完成后平滑隐藏,彻底解决启动白屏问题。

六、常见问题排查

6.1 无法添加到桌面

  • 检查是否部署在 HTTPS 环境(localhost 除外);

  • 检查 manifest.json 配置是否完整(必填项:nameshort_namestart_urldisplayicons);

  • iOS 设备需确保 apple-touch-icon 配置正确,且图片尺寸符合要求。

6.2 离线缓存不生效

  • 检查 sw.js 是否成功生成并部署;

  • 查看浏览器开发者工具 Application > Service Workers,确认 Service Worker 已激活;

  • 检查缓存规则是否正确(globPatterns 是否匹配需要缓存的文件);

  • 确保接口请求符合 runtimeCaching 配置的 urlPattern

6.3 启动页仍有白屏

  • 检查静态启动页是否添加到 #app 容器中;

  • 确保 onMounted 钩子中正确隐藏了启动页;

  • 优化 Vue 初始化逻辑,减少启动时的同步操作。

七、总结

本文通过三个核心步骤,实现了 Uniapp 集成 PWA 的核心能力:通过 Web App Manifest 配置实现“添加到桌面”和启动页基础配置,通过 Service Worker + Workbox 实现离线缓存,通过静态启动页 + 过渡动画优化启动体验。集成 PWA 后,你的 Uniapp Web 端应用将拥有更接近原生 App 的体验,提升用户留存率和使用体验。

后续还可以探索 PWA 的其他高级能力,比如推送通知、后台同步等,进一步增强应用的功能。如果在集成过程中有任何问题,欢迎在评论区交流!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐