别给 Electron 鸿蒙 PC 做应用内更新了——autoUpdater 废了,三套方案全翻车,我们最终用了最笨的办法

发布时间:2026/7/8 16:08:47
别给 Electron 鸿蒙 PC 做应用内更新了——autoUpdater 废了,三套方案全翻车,我们最终用了最笨的办法 先说结论在鸿蒙 PC 上给 Electron 应用做应用内自动更新这事儿目前基本不可能。别折腾了。我们团队花了两周试了三套方案每一套都信誓旦旦觉得这次肯定行结果每一套都白给。最终我们用了那个看起来最蠢、最不技术的办法——检测版本号弹个窗让用户自己去华为应用市场更新。你可能会觉得这不是技术方案。说实话我们一开始也这么觉得。但两周翻车下来我们承认在鸿蒙 PC 上这可能就是当前最靠谱的更新路径。第一轮翻车autoUpdater注册了就没动静Electron 官方的 autoUpdater 模块在 Windows 和 macOS 上跑得挺正常的。我们雷达鸭桌面版 Windows 上就是这套方案checkForUpdates() 一调有新版本就自动下载、自动安装用户重启就完事。搬到鸿蒙 PC 上同样的代码// main.ts — 这段在 Windows 上跑得好好的鸿蒙上废了import{autoUpdater}fromelectron;autoUpdater.setFeedURL({url:https://update.leidarduck.com/harmony/latest,serverType:default,});autoUpdater.on(checking-for-update,(){console.log(正在检查更新...);});autoUpdater.on(update-available,(info){console.log(发现新版本:${info.version});});autoUpdater.on(update-not-available,(){console.log(当前已是最新版本);});autoUpdater.on(error,(err){console.error(更新出错:,err.message);});// 启动后 30 秒检查更新app.whenReady().then((){setTimeout((){autoUpdater.checkForUpdates();},30000);});注册了。调了。等了。日志里啥也没有。不是报错不是update-not-available是啥都没有。checking-for-update的回调没触发error的回调也没触发。我们以为 URL 写错了换成本地测试服务器还是没动静。加了autoUpdater.logger console日志照吃。翻了一圈 Electron 源码才搞明白——等一下这里我漏说一个前提鸿蒙 PC 的 Electron 编译版本用的是electron-mus华为定制的 Chromium Mus 变体它的底层更新机制依赖 Squirrel 框架。Windows 上是 Squirrel.WindowsmacOS 上是 Squirrel.Mac。但鸿蒙 PC 基于 Linux 内核用的 AppImage 打包格式Squirrel 完全没有适配。说白了autoUpdater.checkForUpdates()在鸿蒙 PC 上就是空函数调用。请求可能发出了但没人接收和处理更新包。第二轮翻车electron-updater 自托管下载成功了替换不了autoUpdater 废了之后我们想着绕开 Squirrel用 electron-updater 自己搞。思路很直白自己维护一个latest.yml放在 CDN 上客户端读 YAML 拉最新版本号比对后下载.AppImage文件然后替换本地二进制。// updater-custom.ts — 下载成功了替换失败了import{app}fromelectron;import*asfsfromfs;import*aspathfrompath;import*ashttpsfromhttps;interfaceUpdateInfo{version:string;url:string;sha512:string;}asyncfunctionfetchLatestYml():PromiseUpdateInfo|null{returnnewPromise((resolve){https.get(https://cdn.leidarduck.com/update/latest.yml,(res){letdata;res.on(data,(chunk)datachunk);res.on(end,(){constversionMatchdata.match(/version:\s*(.)/);consturlMatchdata.match(/path:\s*(.)/);constshaMatchdata.match(/sha512:\s*(.)/);if(versionMatchurlMatchshaMatch){resolve({version:versionMatch[1],url:urlMatch[1],sha512:shaMatch[1],});}else{resolve(null);}});}).on(error,()resolve(null));});}asyncfunctiondownloadAndReplace(updateInfo:UpdateInfo):Promiseboolean{constappPathapp.getPath(exe);// 鸿蒙上返回 AppImage 挂载路径constdownloadPathpath.join(app.getPath(temp),leidarduck-latest.AppImage);// 下载新版本constfilefs.createWriteStream(downloadPath);awaitnewPromisevoid((resolve,reject){https.get(updateInfo.url,(res){res.pipe(file);file.on(finish,(){file.close();resolve();});}).on(error,reject);});// 尝试替换 — 鸙蒙上这里会失败try{fs.copyFileSync(downloadPath,appPath);// ❌ EPERM: operation not permittedreturntrue;}catch(err){console.error(替换失败:,err);// EPERM 或 EBUSYreturnfalse;}}下载成功了YAML 解析成功了280MB 的 AppImage 也拉下来了。然后fs.copyFileSync直接报EPERM: operation not permitted。原因很直白鸿蒙 PC 上 Electron 应用是以 AppImage 格式挂载运行的挂载点在/tmp/.mount_xxxxx/这路径是只读的。就算你找到真实的二进制文件位置通常是/opt/applications/下面这个目录受系统包管理器保护普通进程没写权限。我们在雷达鸭鸿蒙版的更新模块里卡了三天怎么绕权限都不行。chmod没权限。sudo桌面应用没法提权。卸载后重装用户体验直接崩了。第三轮翻车手动解压替换签名校验直接拦住第二轮失败后我们又换了个思路不替换 AppImage 整包了只解压替换里面的关键文件。AppImage 本质是个 squashfs 压缩包理论上可以解压、修改、重新打包。// updater-extract.ts — 解压成功了打包和签名全过不了import{app}fromelectron;import*aschild_processfromchild_process;asyncfunctionextractAndPatch(appImagePath:string):Promiseboolean{constextractDir/tmp/leidarduck-patch;try{// AppImage 自带 --appimage-extract 命令child_process.execSync(${appImagePath}--appimage-extract,{cwd:extractDir,});// 修改某些资源文件后重新打包// 但 mksquashfs 在鸿蒙 PC 上压根没装// 而且重新打包后签名校验会失败returnfalse;}catch(err){console.error(解压或打包失败:,err);returnfalse;}}这方案更离谱。解压成功了但mksquashfs在鸿蒙 PC 上压根没有安装。就算你手动装了 mksquashfs 重新打包AppImage 的签名校验会失败——鸿蒙 PC 上运行 AppImage 需要匹配签名你自己打的包签名跟原版不一样系统直接拦住。三轮翻车。两周白给。我们团队差点把更新需求砍了。最终方案看着蠢但稳如老狗三轮翻车后我们冷静下来想了一下鸿蒙 PC 上最自然的更新方式是什么答案是华为应用市场。用户装你的 App 是从应用市场来的更新也应该走应用市场。你作为开发者要做的只是让用户知道有新版本了然后引导他去更新。// updater-market.ts — 最终方案版本检测 华为应用市场引导import{app,shell,BrowserWindow,dialog}fromelectron;import*ashttpsfromhttps;constMARKET_URLappmarket://detail?idcom.leidarduck.harmony;constCURRENT_VERSIONapp.getVersion();interfaceVersionCheckResult{latestVersion:string;updateDescription:string;forceUpdate:boolean;// 是否强制更新安全补丁等}asyncfunctioncheckRemoteVersion():PromiseVersionCheckResult|null{returnnewPromise((resolve){consturlhttps://api.leidarduck.com/v1/version/check?platformharmonyversion${CURRENT_VERSION};https.get(url,(res){letdata;res.on(data,(chunk)datachunk);res.on(end,(){try{resolve(JSON.parse(data));}catch{resolve(null);}});}).on(error,()resolve(null));});}asyncfunctionpromptUpdate(result:VersionCheckResult):Promisevoid{constwinBrowserWindow.getAllWindows()[0];if(!win)return;if(result.forceUpdate){// 强制更新不给选择直接跳转awaitdialog.showMessageBox(win,{type:warning,title:安全更新,message:发现重要安全更新v${result.latestVersion}请立即更新。,buttons:[前往更新],noLink:true,});shell.openExternal(MARKET_URL);app.quit();}else{// 非强制用户可选择constresponseawaitdialog.showMessageBox(win,{type:info,title:版本更新,message:发现新版本 v${result.latestVersion},detail:result.updateDescription,buttons:[稍后再说,前往更新],noLink:true,defaultId:1,});if(response.response1){shell.openExternal(MARKET_URL);}}}// 启动时检查版本exportasyncfunctioninitUpdateCheck():Promisevoid{constresultawaitcheckRemoteVersion();if(!result)return;if(result.latestVersion!CURRENT_VERSION){awaitpromptUpdate(result);}}核心就两步启动时请求远程 API 拿最新版本号有新版本就弹窗用户点前往更新shell.openExternal(appmarket://detail?idxxx)打开华为应用市场的应用详情页这方案看着确实蠢。没有自动下载没有静默安装用户还得自己点一下。但我们上线两周了零故障更新率比 Windows 上 autoUpdater 还高——因为华为应用市场的推送通知会二次提醒用户。等一下这里我漏说一个前提shell.openExternal在鸿蒙 PC 上用appmarket://协议链接这是华为应用市场的 deep link。如果你还没在华为应用市场上架你的 App这个方案就跑不通。上架了才行。还有个细节appmarket://协议在部分鸿蒙 PC 版本上偶尔不生效大约 5% 的设备我们兜底用 Web 版链接// 兜底方案协议链接不生效时走 Web 链接constMARKET_WEB_URLhttps://appmarket.huawei.com/detail/id/com.leidarduck.harmony;asyncfunctionopenMarketPage():Promisevoid{try{awaitshell.openExternal(MARKET_URL);}catch{shell.openExternal(MARKET_WEB_URL);}}为什么最笨反而是最稳我们复盘了一下三轮翻车的根本原因归根到底就是一句话鸿蒙 PC 的应用生命周期是系统管控的你作为开发者没有权限干预自己应用的安装和替换。Windows 上你可以随便替换 exemacOS 上你可以往 Applications 目录写文件。鸿蒙 PC 上不行。应用市场是鸿蒙 PC 上唯一的合法分发渠道你的更新逻辑只能检测 引导不能下载 替换。我们一开始死活不愿意接受这个事实觉得引导用户手动更新不够体面。但两周翻车之后我们承认体面不体面不重要稳不稳才重要。而且说实话这方案有个我们之前没预料到的优势华为应用市场会做签名校验和安全审核。autoUpdater 下载的包你可没法保证没被中间人篡改但应用市场下载的包至少过了官方审核。从这个角度看笨办法反而更安全。你遇到 Electron 在鸿蒙 PC 上做自动更新的坑了吗我猜很多人还在第一轮翻车——autoUpdater 注册了就等着等半天啥都没发生。别等了换思路吧。关于作者老三10 年软件开发经验软件设计师人工智能应用工程师。专注鸿蒙应用开发ArkTS北向开发 Web 前端探索 AI 自动化不定期在 CSDN 分享鸿蒙 / AI 方向技术文章。本文遵循 MIT 协议转载请注明出处。