优化android 热更新
This commit is contained in:
1 parent
75d8f87f49
commit
999723508a
4 files changed
+74
-18
No files matched your search
@@ -13,6 +13,13 @@ const config: CapacitorConfig = {
|
||||
autoUpdate: 'off',
|
||||
version: '1.0.0',
|
||||
appReadyTimeout: 10000,
|
||||
// A 30 MB OTA package can take longer than the plugin default on a
|
||||
// mobile network. Manual checking keeps the UI responsive while this
|
||||
// timeout only governs the native request/download pipeline.
|
||||
responseTimeout: 60,
|
||||
autoDeleteFailed: true,
|
||||
autoDeletePrevious: true,
|
||||
keepUrlPathAfterReload: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -8,15 +8,30 @@ import { ZipArchive } from 'archiver'
|
||||
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url))
|
||||
const webDirectory = path.resolve(scriptDirectory, '..')
|
||||
const distDirectory = path.join(webDirectory, 'dist')
|
||||
const packageJson = JSON.parse(
|
||||
await readFile(path.join(webDirectory, 'package.json'), 'utf8'),
|
||||
)
|
||||
const versionIndex = process.argv.indexOf('--version')
|
||||
const version =
|
||||
versionIndex >= 0 ? process.argv[versionIndex + 1] : packageJson.version
|
||||
const requestedVersion =
|
||||
versionIndex >= 0 ? process.argv[versionIndex + 1] : undefined
|
||||
const versionProps = await readFile(path.join(webDirectory, '..', 'versions.props'), 'utf8')
|
||||
const version = /<JiaowuFrontendVersion>([^<]+)<\/JiaowuFrontendVersion>/.exec(
|
||||
versionProps,
|
||||
)?.[1]?.trim()
|
||||
|
||||
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?$/.test(version ?? '')) {
|
||||
throw new Error('请使用 --version 1.0.1 指定语义版本。')
|
||||
if (!version) {
|
||||
throw new Error('versions.props 中缺少 JiaowuFrontendVersion。')
|
||||
}
|
||||
|
||||
if (versionIndex >= 0 && !requestedVersion) {
|
||||
throw new Error('请在 --version 后提供版本号。')
|
||||
}
|
||||
|
||||
if (requestedVersion && requestedVersion !== version) {
|
||||
throw new Error(
|
||||
`更新包版本必须与 JiaowuFrontendVersion 一致(当前为 ${version})。`,
|
||||
)
|
||||
}
|
||||
|
||||
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?$/.test(version)) {
|
||||
throw new Error('JiaowuFrontendVersion 必须使用语义版本,例如 1.0.1。')
|
||||
}
|
||||
|
||||
await stat(path.join(distDirectory, 'index.html')).catch(() => {
|
||||
|
||||
@@ -18,6 +18,10 @@ interface AppUpdateCheckResponse {
|
||||
|
||||
const updateChannel =
|
||||
import.meta.env.VITE_APP_UPDATE_CHANNEL?.trim() || 'production'
|
||||
const foregroundCheckInterval = 5 * 60 * 1000
|
||||
|
||||
let checkInProgress: Promise<void> | undefined
|
||||
let lastCheckedAt = 0
|
||||
|
||||
function absoluteApiUrl(relativePath: string) {
|
||||
const configuredBase = String(http.defaults.baseURL ?? '/api')
|
||||
@@ -30,14 +34,14 @@ function absoluteApiUrl(relativePath: string) {
|
||||
return new URL(relativePath, apiBase).toString()
|
||||
}
|
||||
|
||||
export async function initializeAppUpdates() {
|
||||
if (!Capacitor.isNativePlatform()) return
|
||||
async function checkForAppUpdate() {
|
||||
if (checkInProgress) return checkInProgress
|
||||
if (!navigator.onLine || Date.now() - lastCheckedAt < foregroundCheckInterval) {
|
||||
return
|
||||
}
|
||||
|
||||
checkInProgress = (async () => {
|
||||
try {
|
||||
// Only confirm the bundle after Vue has mounted successfully. If a newly
|
||||
// installed bundle cannot reach this point, the native plugin rolls back.
|
||||
await CapacitorUpdater.notifyAppReady()
|
||||
|
||||
const platform = Capacitor.getPlatform()
|
||||
if (platform !== 'android' && platform !== 'ios') return
|
||||
|
||||
@@ -68,6 +72,7 @@ export async function initializeAppUpdates() {
|
||||
!data.version ||
|
||||
!data.downloadUrl ||
|
||||
!data.sha256 ||
|
||||
data.version === currentVersion ||
|
||||
next?.version === data.version
|
||||
) {
|
||||
return
|
||||
@@ -82,12 +87,39 @@ export async function initializeAppUpdates() {
|
||||
|
||||
ElNotification({
|
||||
title: `新版本 ${data.version} 已就绪`,
|
||||
message: data.releaseNotes || '更新将在下次启动应用时自动生效。',
|
||||
message:
|
||||
data.releaseNotes || '切换到后台或下次启动应用时将自动启用更新。',
|
||||
type: 'success',
|
||||
duration: 6000,
|
||||
})
|
||||
} catch (error) {
|
||||
// OTA failure must never stop users from entering the bundled application.
|
||||
console.warn('[app-update] update check failed', error)
|
||||
} finally {
|
||||
lastCheckedAt = Date.now()
|
||||
checkInProgress = undefined
|
||||
}
|
||||
})()
|
||||
|
||||
return checkInProgress
|
||||
}
|
||||
|
||||
export async function initializeAppUpdates() {
|
||||
if (!Capacitor.isNativePlatform()) return
|
||||
|
||||
try {
|
||||
// Confirm the bundle before any network request. If a newly installed
|
||||
// bundle cannot reach this point, the native plugin rolls it back.
|
||||
await CapacitorUpdater.notifyAppReady()
|
||||
} catch (error) {
|
||||
// Do not let a native-plugin error prevent the bundled app from starting.
|
||||
console.warn('[app-update] bundle readiness confirmation failed', error)
|
||||
}
|
||||
|
||||
void checkForAppUpdate()
|
||||
window.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
void checkForAppUpdate()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user