diff --git a/Dockerfile b/Dockerfile index d9d71c5..db9d99a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,6 +55,9 @@ COPY --from=builder /app/public ./public # 本地构建时只有占位文件 (ota-package/README.md), server 找不到 latest.json 则 OTA 返回"无更新" COPY ota-package ./ota-package ENV OTA_PACKAGE_DIR=/app/ota-package +# OTA bundle 下载用的绝对 base (manifest.url 必须是绝对 URL, 插件不拼 base, 相对路径会导致下载 0% 失败) +# 生产为 http 明文 (无 https), 客户端 tauri.conf.json 的 hotswap.require_https 已设为 false 放行 http +ENV OTA_PUBLIC_BASE=http://bh.vps.honor3.com:3001 # 健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ diff --git a/src/api/ota.js b/src/api/ota.js index 634496b..f645a12 100644 --- a/src/api/ota.js +++ b/src/api/ota.js @@ -107,6 +107,7 @@ export async function applyOtaUpdate(onProgress) { // 注册一次性进度监听 (applyUpdate 期间触发) let unlisten = null + let unlistenLifecycle = null if (onProgress) { try { unlisten = await mod.onDownloadProgress((p) => onProgress(p.downloaded, p.total)) @@ -115,13 +116,39 @@ export async function applyOtaUpdate(onProgress) { } } + // 监听 lifecycle 事件, 捕获失败详情 (download-error / apply 失败时 error 字段带具体原因) + // applyUpdate() 抛出的错误往往只有泛化信息, 细节藏在 lifecycle 事件里 + let lifecycleError = '' + try { + unlistenLifecycle = await mod.onLifecycle((ev) => { + if (ev.event === 'download-error' || ev.event === 'apply' || ev.event === 'check-error') { + if (ev.error) { + lifecycleError = ev.error + console.error('[ota] lifecycle', ev.event, 'error:', ev.error) + } + } + }) + } catch (e) { + console.warn('[ota] onLifecycle 监听失败:', e) + } + try { const newVersion = await mod.applyUpdate() return newVersion + } catch (e) { + // 把 lifecycle 里的详细错误拼进抛出的异常, 方便前端展示真实原因 + const base = e?.message || '升级失败' + const detail = lifecycleError ? ` (${lifecycleError})` : '' + const err = new Error(base + detail) + err.cause = e + throw err } finally { if (unlisten) { try { unlisten() } catch { /* ignore */ } } + if (unlistenLifecycle) { + try { unlistenLifecycle() } catch { /* ignore */ } + } } }