# 🚀Electron程序的打包与在线升级

📅 2023/4/28

# electron-builder 配置及打包

采用electron-builder 进行打包,该方式可以方便进行在线升级。可以根据需求配置以下的相应字段。下方配置及方法以windows平台作为示例。

{
    "build": {
        "productName": "应用程序名称",
        "appId": "应用程序唯一标识",
        "asar": true, //是否采用asar打包
        "electronDownload": { //electron镜像地址,由于打包过程中需要下载相应版本及平台的electron包,如果下载失败可以通过此配置设置淘宝镜像下载
          "mirror": "https://npm.taobao.org/mirrors/electron/" //设置electron下载镜像
        },
        "publish": [ //发布信息
            {
                "provider": "发布平台例如 GitHub等", 
                "url": "在线更新的地址"
            }
        ],
        "files": [ //排除不需要进行打包的文件,通常是一些静态文件,如dll、exe、.node 文件等
            "!**/app.asar.unpacked/**"
        ],
        "extraResources": [ //在打包过程中需要移动的文件,上方files字段将静态文件排除后,需要将这些文件放在asar文件之外。
        {
            "from": "./app.asar.unpacked", //移出路径
            "to": "./app.asar.unpacked" //移入路径
        }
        ],
        "win": { //windows平台下的打包配置
            "target": "nsis", //nsis,支持 x64 和 ia32 架构,dmg,支持 arm64 架构。
            "icon": "./XXX.ico" //应用图标
        },
        "linux": {
            "target": [
                "AppImage" //Linux平台下构建选项,可以为AppImage、deb、snap等
            ]
        },
        "nsis": { //nsis 配置,用于指定在 Windows 平台上使用 NSIS 构建安装程序时的配置选项。
            "oneClick": false, //是否默认安装
            "allowToChangeInstallationDirectory": true, //是否可以选择安装目录
            "allowElevation": true, //是否需要管理员权限
            "installerIcon": "./XXX.ico", //安装程序图标
            "createDesktopShortcut": true //是否创建快捷方式
        }
    }
}

如果需要自定义安装程序或界面,可以在nsis字段下使用"include"或"script"字段指定NSIS脚本的路径,用于自定义安装程序。如果提示缺少nsis-resources-xxx等包,可以通过错误信息的下载地址下载,之后手动放到C:/User/用户名/AppData/Local/electron-builder/cache/nsis/目录下。electron-builder 的配置选项很多,上述文件只是配置了一些常用字段,具体可以去electron-builder官网 (opens new window)查看。

electron-builder install-app-deps && electron-builder --win --ia32

通过以上命令可以指定打包windows平台下的32位程序包,在一些老旧的系统上可能会出现打包出来的程序无法运行的情况,可以通过以兼容模式运行尝试解决:右键安装包 --> 属性 --> 兼容性 --> 勾选以兼容模式运行这个程序 --> 选择平台

更改兼容性

# Electron 在线升级

# 打包生成文件

通过electron-builder 打包后在 windows 平台下会生成如下文件,其中.exe文件则为windows平台下的安装包,latest.yml为版本信息,用于在线更新。

  • builder-debug.yml
  • builder-effective-config.yaml
  • latest.yml
  • .exe 文件
  • .exe.blockmap 文件
  • 未打包的文件夹,通常以unpacked结尾

# 准备更新服务器

打包完成后需要准备一台可以用于在线更新的服务器。如果没有服务器,暂时可用本地服务模拟,只要可以提供一个在线更新地址即可。

# 程序改造

安装 electron-updater 包进行更新,该包提供了开箱即用的更新功能(windows)

npm i electron-updater

主进程引入 electron-updater 中的 autoUpdater 方法用于自动更新,并监听一系列事件向渲染进程发送消息展示更新进度。

  • checking-for-update:当应用程序开始检查是否有可用更新时触发。可以使用此事件显示 "正在检查更新" 的消息或类似的内容。
  • update-available:当发现有可用更新时触发。可以使用此事件通知用户有新版本可供下载,并提示他们是否要下载更新。
  • update-not-available:当没有可用更新时触发。可以使用此事件通知用户当前已经是最新版本,并提示他们继续使用应用程序。
  • download-progress:当更新程序正在下载时触发。可以使用此事件显示下载进度条或百分比,并通知用户下载的速度。
  • update-downloaded:当更新程序已经下载完成并准备好安装时触发。可以使用此事件提示用户是否要立即安装更新。
  • error:当发生错误时触发。可以使用此事件接受错误信息。
    const {app, BrowserWindow} = require('electron')
    // 引入自动更新模块
    const { autoUpdater } = require('electron-updater')
    // 更新地址
    const autoUpdaterUrl = '准备好的更新服务器:例如http://localhost:3000/'
    //是否自动下载,如果需要强制更新可以设置为true
    autoUpdater.autoDownload=false
    //设置更新地址
    autoUpdater.setFeedURL(autoUpdaterUrl)
    
    const returnData = {
        error: { status: -1, msg: "检测更新异常" },
        checking: { status: 0, msg: "正在检查应用程序更新" },
        updateAva: { status: 1, msg: "检测到新版本,正在下载,请稍后" },
        updateNotAva: { status: 2, msg: "您现在使用的版本为最新版本,无需更新!" }
    }
    
    /* 检测更新 */
    function checkUpdate() {
        autoUpdater.checkForUpdates().then(r => console.log('开始更新检测'))
    }
    
    /* 开始下载 */
    function startDownLoad(){
        //当禁用自动下载时需要通过此方法开启下载
        autoUpdater.downloadUpdate()
    }
    
    /* 安装更新 */
    function installNewVersion(){
        //下载完成后需要重启APP开启更新,传递的参数分别为是否静默安装、是否立即退出安装
        autoUpdater.quitAndInstall(true, true)
    }
    
    //更新错误
    autoUpdater.on("error", function (error) {
        sendUpdateMessage(returnData.error)
    })

    //检查中
    autoUpdater.on("checking-for-update", function () {
        sendUpdateMessage(returnData.checking)
    })
    
    autoUpdater.on("update-available", function (info) {
        sendUpdateMessage(returnData.updateAva)
    })

    //当前版本为最新版本
    autoUpdater.on("update-not-available", function (info) {
        setTimeout(function () {
            sendUpdateMessage(returnData.updateNotAva)
        }, 1000)
    })

    // 更新下载进度事件
    autoUpdater.on("download-progress", function (progressObj) {
        sendUpdateProcess(progressObj)
    })

    autoUpdater.on("update-downloaded", function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
        sendUpdateMessage("更新完毕")
    })
    
    function sendUpdateMessage(text) {
        //如果需要,可以创建更新窗口加载更新页面并向渲染进程发送更新监测信息
    }
    function sendUpdateProcess(text) {
        //如果需要,可以创建更新窗口加载更新页面并向渲染进程发送更新进度信息
    }
    /*自动更新模块结束 */
    
    //此处暴露三个方法:检测更新、开始下载、安装新版本
    module.exports = {checkUpdate,startDownLoad,installNewVersion}

上述代码提供了一个自动更新模块,仅需要引入后调用封装好的方法即可实现更新,如果需要显示更新界面,可以创建更新窗口加载更新页面并向渲染进程发送消息实现交互。更新下载的新安装包会在C:/Users/用户名/AppData/Local/xxx-updater 目录下。将打包生成的文件(unpacked结尾文件夹不需要)放到更新目录下,程序则会自动检测到更新的版本。版本号可以在package.json中的version字段指定。