热更新

This commit is contained in:
biss committed 2026-08-23 16:59:17 +08:00
1 parent 9e77c8470e
commit 0aa9c21531
2 files changed
+45 -6

No files matched your search

+41 -3
View File
@@ -1,5 +1,6 @@
import { App } from '@capacitor/app'
import { Capacitor } from '@capacitor/core'
import { CapacitorUpdater } from '@capgo/capacitor-updater'
import { CapacitorUpdater, type BundleInfo } from '@capgo/capacitor-updater'
import { ElNotification } from 'element-plus'
import http from '../api/http'
@@ -20,6 +21,7 @@ const updateChannel =
import.meta.env.VITE_APP_UPDATE_CHANNEL?.trim() || 'production'
let checkInProgress: Promise<void> | undefined
let updatePromptVisible = false
function absoluteApiUrl(relativePath: string) {
const configuredBase = String(http.defaults.baseURL ?? '/api')
@@ -87,9 +89,12 @@ async function checkForAppUpdate() {
ElNotification({
title: `新版本 ${data.version} 已就绪`,
message:
data.releaseNotes || '切换到后台或下次启动应用时将自动启用更新。',
(data.releaseNotes
? `${data.releaseNotes} 点击此提示可立即启用。`
: '切换到后台或下次启动应用时将自动启用更新;点击此提示可立即启用。'),
type: 'success',
duration: 6000,
duration: 0,
onClick: () => void applyDownloadedUpdate(downloaded),
})
} catch (error) {
// OTA failure must never stop users from entering the bundled application.
@@ -102,6 +107,33 @@ async function checkForAppUpdate() {
return checkInProgress
}
async function applyDownloadedUpdate(bundle: BundleInfo) {
if (updatePromptVisible) return
updatePromptVisible = true
try {
await ElNotification.closeAll()
// `set` replaces the WebView bundle and immediately reloads, so ask for a
// deliberate confirmation instead of interrupting unsaved form input.
await import('element-plus').then(({ ElMessageBox }) =>
ElMessageBox.confirm(
'将重新加载应用以启用已下载的新版本。未保存的内容请先提交。',
'启用更新',
{
confirmButtonText: '立即启用',
cancelButtonText: '稍后',
type: 'info',
},
),
)
await CapacitorUpdater.set({ id: bundle.id })
} catch {
// Choosing "later" is safe: next() has already queued this bundle for
// activation when the app backgrounds or is launched again.
} finally {
updatePromptVisible = false
}
}
export async function initializeAppUpdates() {
if (!Capacitor.isNativePlatform()) return
@@ -117,5 +149,11 @@ export async function initializeAppUpdates() {
// Every cold start checks the latest public release immediately. A bundle
// downloaded here is activated when the app is next launched.
void checkForAppUpdate()
// Keep the native app aligned with the PWA behavior: returning to the app
// is another opportunity to discover a newly deployed web bundle. The
// single-flight guard prevents duplicate cold-start/foreground requests.
void App.addListener('appStateChange', ({ isActive }) => {
if (isActive) void checkForAppUpdate()
})
window.addEventListener('online', () => void checkForAppUpdate())
}