Vue 项目做好了,老板说:能不能出个 App?
这时候你有两条路:
PWA(渐进式 Web 应用):让你的网页具备 App 的体验——可以安装到桌面、离线使用、推送通知。本质上还是网页,不需要上架应用商店。
Capacitor:把你的 Vue 项目打包成真正的原生 App,可以上架 App Store 和 Google Play,能调用摄像头、GPS、蓝牙等原生 API。
两条路都有适用场景,选错了会很痛苦。
选什么
选 PWA,如果:
• 不需要上架应用商店 • 主要场景是移动端浏览器访问 • 需要离线功能和桌面快捷方式 • 不需要调用复杂的原生设备 API • 想快速上线,不想处理 App 审核
选 Capacitor,如果:
• 需要上架 App Store / Google Play • 需要调用摄像头、蓝牙、NFC 等原生 API • 需要推送通知(iOS 的推送必须走原生) • 用户群体习惯从应用商店下载 App
PWA 实现
安装 vite-plugin-pwa
pnpm add -D vite-plugin-pwa配置
// vite.config.tsimport { defineConfig } from "vite";import vue from "@vitejs/plugin-vue";import { VitePWA } from "vite-plugin-pwa";export default defineConfig({ plugins: [ vue(), VitePWA({ registerType: "autoUpdate", // 有新版本自动更新 manifest: { name: "我的 Vue App", short_name: "VueApp", description: "一个 Vue PWA 应用", theme_color: "#42b883", background_color: "#ffffff", display: "standalone", // 全屏显示,像原生 App icons: [ { src: "/icons/icon-192.png", sizes: "192x192", type: "image/png", }, { src: "/icons/icon-512.png", sizes: "512x512", type: "image/png", }, ], }, workbox: { // 缓存策略 runtimeCaching: [ { urlPattern: /^https:\/\/api\.example\.com\/.*/, handler: "NetworkFirst", // 优先网络,失败用缓存 options: { cacheName: "api-cache", expiration: { maxEntries: 100, maxAgeSeconds: 60 * 60 * 24, // 缓存 1 天 }, }, }, { urlPattern: /\.(png|jpg|jpeg|svg|gif)$/, handler: "CacheFirst", // 优先缓存,减少网络请求 options: { cacheName: "image-cache", }, }, ], }, }), ],});离线提示
当用户离线时,给出友好提示:
<!-- src/components/OfflineNotice.vue --><script setup> import { useOnline } from "@vueuse/core"; const isOnline = useOnline();</script><template> <div v-if="!isOnline" class="offline-banner"> 📡 当前处于离线状态,部分功能可能不可用 </div></template>更新提示
有新版本时提示用户刷新:
<!-- src/App.vue --><script setup> import { useRegisterSW } from "virtual:pwa-register/vue"; const { needRefresh, updateServiceWorker } = useRegisterSW();</script><template> <div v-if="needRefresh" class="update-banner"> 发现新版本! <button @click="updateServiceWorker()">立即更新</button> </div> <RouterView /></template>Capacitor 实现
安装
pnpm add @capacitor/core @capacitor/clipnpm add @capacitor/android @capacitor/ios初始化
npx cap init "我的 App" "com.example.myapp"这会在项目根目录生成 capacitor.config.ts:
// capacitor.config.tsimport { CapacitorConfig } from "@capacitor/cli";const config: CapacitorConfig = { appId: "com.example.myapp", appName: "我的 App", webDir: "dist", // Vite 构建输出目录 server: { androidScheme: "https", },};export default config;添加平台
npx cap add androidnpx cap add ios构建和同步
# 构建 Vue 项目pnpm build# 同步到原生项目npx cap sync# 打开 Android Studionpx cap open android# 打开 Xcodenpx cap open ios调用原生 API
Capacitor 提供了丰富的原生插件:
pnpm add @capacitor/camera @capacitor/geolocation @capacitor/push-notificationsimport { Camera, CameraResultType } from "@capacitor/camera";import { Geolocation } from "@capacitor/geolocation";// 拍照async function takePhoto() { const photo = await Camera.getPhoto({ quality: 90, allowEditing: false, resultType: CameraResultType.Uri, }); return photo.webPath;}// 获取位置async function getLocation() { const position = await Geolocation.getCurrentPosition(); return { lat: position.coords.latitude, lng: position.coords.longitude, };}在 Vue 组件里使用:
<script setup> import { Camera, CameraResultType } from "@capacitor/camera"; import { ref } from "vue"; const photoUrl = ref(""); async function handleTakePhoto() { const photo = await Camera.getPhoto({ quality: 90, resultType: CameraResultType.Uri, }); photoUrl.value = photo.webPath; }</script><template> <div> <button @click="handleTakePhoto">拍照</button> <img v-if="photoUrl" :src="photoUrl" /> </div></template>热更新(开发调试)
开发时不需要每次都重新构建,可以用 Capacitor 的实时重载:
// capacitor.config.ts(开发环境)const config: CapacitorConfig = { appId: "com.example.myapp", appName: "我的 App", webDir: "dist", server: { url: "http://192.168.1.100:5173", // 你的开发机 IP cleartext: true, },};这样手机上的 App 会直接加载开发服务器的内容,修改代码立即生效。
PWA vs Capacitor 对比
写在最后
PWA 和 Capacitor 不是竞争关系,而是两个不同场景的解决方案。
如果你的用户主要通过浏览器访问,PWA 能用最低的成本提升移动端体验。
如果你需要上架应用商店或者调用复杂的原生 API,Capacitor 是最顺手的选择,因为你的 Vue 代码几乎不需要改动。
文档:
• vite-plugin-pwa: https://vite-pwa-org.netlify.app • Capacitor 官网: https://capacitorjs.com
#VuePWA #Capacitor #移动端 #离线应用 #跨平台 #ServiceWorker #原生App #VitePluginPwa
夜雨聆风