Electron-builder打包和自动更新

2023-11-05

前言

文本主要讲述如何为 electron 打包出来软件配置安装引导和结合 github 的 release 配置自动更新。

electron-builder 是将 Electron 工程打包成相应平台的软件的工具,我的工程是使用 electron-vite 构建的,其默认集成了 electron-builder ,下文也是基于 electron-vite 生成的工程进行讲解。

下文是基于 Window 平台讲解,所以安装包我也会说成 exe 文件

配置

electron-builder 有两种配置方式

  • 在 package.json 配置
  • 使用 electron-builder.yml 配置

如果打包命令带上 —config,就是使用 electron-builder.yml 的方式,例如

electron-builder --win --config

以下介绍都基于 electron-builder.yml 的方式,如需使用 package.json,请自行翻阅文档转换

详见:CLI

NSIS安装引导

electron-builder 生成的安装包默认是一键安装,也就是无法选择安装路径等。这时候就需要用到 NSIS 了(注意:NSIS 只适用于 Window 平台)

只需要修改 electron-builder.yml 即可,我常用的配置如下:

nsis:
  oneClick: false # 创建一键安装程序还是辅助安装程序(默认是一键安装)
  allowElevation: true # 是否允许请求提升,如果为false,则用户必须使用提升的权限重新启动安装程序 (仅作用于辅助安装程序)
  allowToChangeInstallationDirectory: true # 是否允许修改安装目录 (仅作用于辅助安装程序)
  createStartMenuShortcut: true # 是否创建开始菜单快捷方式
  artifactName: ${productName}-${version}-${platform}-${arch}.${ext}
  shortcutName: ${productName}
  uninstallDisplayName: ${productName}
  createDesktopShortcut: always

详见:NsisOptions

自动更新

结合 github 的 release 配置自动更新

代码修改

  1. 修改 electron-builder.yml

    以 dubbo 仓库举例子:https://github.com/apache/dubbo

    # 仓库配置
    publish:
      provider: github # 选择github平台
      owner: apache # github用户名
      repo: dubbo # github仓库名
    # 更新日志
    releaseInfo:
      releaseNotes: |
       这是更新日志
       测试测试
    
  2. 工程代码修改

    我是基于 TypeScript 的写法,如果需要 JavaScript 的写法,请参考文档:Auto-Update官方案例

    • 安装 electron-updater

      npm install electron-updater
      
    • 主线程添加自动更新代码

      import { autoUpdater, UpdateInfo } from 'electron-updater';
      
      // dev-start, 这里是为了在本地做应用升级测试使用,正式环境请务必删除
      if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
        autoUpdater.updateConfigPath = path.join(__dirname, '../../dev-app-update.yml');
      }
      Object.defineProperty(app, 'isPackaged', {
        get() {
          return true;
        }
      });
      // dev-end
      
      // 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
      ipcMain.on('check-for-update', () => {
        logger.info('触发检查更新');
        autoUpdater.checkForUpdates();
      });
      
      // 设置自动下载为false(默认为true,检测到有更新就自动下载)
      autoUpdater.autoDownload = false;
      // 检测下载错误
      autoUpdater.on('error', (error) => {
        logger.error('更新异常', error);
      });
      
      // 检测是否需要更新
      autoUpdater.on('checking-for-update', () => {
        logger.info('正在检查更新……');
      });
      // 检测到可以更新时
      autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
        logger.info('检测到新版本,确认是否下载');
        const releaseNotes = releaseInfo.releaseNotes;
        let releaseContent = '';
        if (releaseNotes) {
          if (typeof releaseNotes === 'string') {
            releaseContent = <string>releaseNotes;
          } else if (releaseNotes instanceof Array) {
            releaseNotes.forEach((releaseNote) => {
              releaseContent += `${releaseNote}\n`;
            });
          }
        } else {
          releaseContent = '暂无更新说明';
        }
        // 弹框确认是否下载更新(releaseContent是更新日志)
        dialog
          .showMessageBox({
            type: 'info',
            title: '应用有新的更新',
            detail: releaseContent,
            message: '发现新版本,是否现在更新?',
            buttons: ['否', '是']
          })
          .then(({ response }) => {
            if (response === 1) {
              // 下载更新
              autoUpdater.downloadUpdate();
            }
          });
      });
      // 检测到不需要更新时
      autoUpdater.on('update-not-available', () => {
        logger.info('现在使用的就是最新版本,不用更新');
      });
      // 更新下载进度
      autoUpdater.on('download-progress', (progress) => {
        logger.info('下载进度', progress);
      });
      // 当需要更新的内容下载完成后
      autoUpdater.on('update-downloaded', () => {
        logger.info('下载完成,准备更新');
        dialog
          .showMessageBox({
            title: '安装更新',
            message: '更新下载完毕,应用将重启并进行安装'
          })
          .then(() => {
            // 退出并安装应用
            setImmediate(() => autoUpdater.quitAndInstall());
          });
      });
      

      上面的代码只是主线程的,还需要渲染线程和页面配置

发布 release

  1. 创建 token

    登录 github → 点击个人头像 → Settings → 选择Developer Settings → 创建token

    Untitled

    配置选择

    Untitled

    复制创建好的 token

  2. 给仓库设置 token

    回到 electron 工程项目 → Settings → Secrets and variables → Actions

    secret 的名字使用 GH_TOKEN,值就是刚才复制的 token

    Untitled

  3. 添加 github action 需要的文件

    在 .github/workflows 文件夹下创建 build.yml 文件,内容如下(请自行把注释删掉)

    我们这里就用到了上一步配置的 GH_TOKEN

    name: build
    
    # 当提交tag时触发
    on:
      push:
        tags:
          - "*"
    
    jobs:
      build:
    
        runs-on: windows-latest
    
        steps:
        # 步骤1,检出仓库代码
        - name: Check out Git repository
          uses: actions/checkout@v3
        # 步骤2,使用node环境
        - name: Use Node.js
          uses: actions/setup-node@v3
          with:
            node-version: 18.x
            cache: 'npm'
        # 步骤3,执行npm install命令,安装依赖
        - name: Install dependencies
          run: npm install
        # 步骤4,执行打包命令(请自行修改成自己的打包命令)
        - name: build win
          run: npm run build:win
          env:
            GH_TOKEN: ${{ secrets.GH_TOKEN }}
        # 步骤5,发布release,需要注意包含的3个文件
        - name: release
          uses: softprops/action-gh-release@v1
          with:
            files: |
             dist/*.exe
             dist/*.exe.blockmap
             dist/latest.yml
            draft: false
          env:
            GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
    

    看清楚注释,作业别闭眼抄哈

  4. 发布

    提交代码,推送tag,等待几分钟,release 就构建好了

总结

没啥好总结的


参考资料

electron-builder

GitHub Actions

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Electron-builder打包和自动更新 的相关文章

  • 实现快速 Javascript 搜索?

    基本上 我有一个带有文本框的页面和 ul 列在其下面 这 ul 由用户的朋友列表填充 用户开始在文本框中输入朋友的名字 例如按 r 我想立即更新 ul 每次按键仅显示名字以 R 开头的朋友 例如 Richard Redmond Raheem
  • 计算字符串中的唯一单词

    下面我尝试将字符串数组提供给一个函数 该函数将唯一单词添加到单词数组中 并且如果该单词已经在数组中 则增加计数数组中相应元素的计数 var words var counts calculate a b calculate a c funct
  • 有没有办法根据渲染的字符串创建 DOM 对象?

    有没有办法从整个字符串而不只是innerHTML 创建DOM 对象 我有一个完整呈现的 DOM 形式的字符串
  • 如何将事件对象传递给 JavaScript 中的函数?

  • 使用 Jquery 附加链接

    我正在尝试根据您所在的页面添加指向我的页面的链接 我使用 Squarespace 来构建这个网站 因此对我来说最简单的方法是使用 Javascript 或 Jquery 我认为我缺少的这个语法有问题 我已经尝试用 来打破引号 但这不起作用
  • Excel 宏与 Javascript

    我希望使用 Javascript 中的宏而不是默认的 VBA 来操作 Excel 电子表格 我可以使用以下 VBA 代码执行 javascript 代码 javascript to execute Dim b As String b fun
  • Chrome 开发工具:无需切换到“源”选项卡即可进入调试器

    如果我把debugger https developer mozilla org en US docs JavaScript Reference Statements debugger当 Chrome 开发工具打开时 我的 JavaScri
  • 如何解构 React props 并仍然访问其他 props?

    我很好奇如果我想要所有的 props 但也想要解构单个属性 那么组件的参数 props 是否可以像导入一样解构 我想这更像是一个 JavaScript 问题 而不是一个 React 问题 但是举个例子 import React useEff
  • Browserify:如果需要,使用 module.exports,否则暴露全局

    我正在考虑采用浏览器化 http browserify org 对于我的一些项目 但想确保其他人如果想使用 捆绑的 代码就不必使用 browserify 执行此操作的明显方法是通过以下方式公开模块导出module exports以及通过一个
  • 在 Chrome 中加载analytics.js时出现307重定向

    我正在构建一个网络应用程序并使用 Google Analytics analytics js 进行分析 我最近注意到 Chrome 中的分析功能无法正常工作 我使用单独模块中的标准代码片段加载分析并通过 requirejs 包含 我已验证该
  • 可选回调的 JavaScript 样式

    我有一些函数偶尔 并非总是 会收到回调并运行它 检查回调是否已定义 函数是一种好的风格还是有更好的方法 Example function save callback do stuff if typeof callback undefined
  • 我们如何使用 thymeleaf 绑定对象列表的列表

    我有一个表单 用户可以在其中添加任意数量的内容表对象这也可以包含他想要的列对象 就像在 SQL 中构建表一样 我尝试了下面的代码 但没有任何效果 并且当我尝试绑定两个列表时 表单不再出现 控制器 ModelAttribute page pu
  • 如何使用 Jquery .animate() 函数创建连续滚动内容? [复制]

    这个问题在这里已经有答案了 可能的重复 在jquery中实现圆形滚动条 https stackoverflow com questions 812049 implementing circular scroller in jquery 我想
  • Socket.io 与服务器离线连接

    如何检测服务器是否离线或由于其他原因无法连接 我的代码看起来像这样 this socket io connect connectionInfo reconnect false 它不会抛出任何错误 因此 try catch 子句不起作用 Us
  • 在firefox上用js改变表单方法

    我需要使用 javascript jQuery 或纯 更改表单的方法属性 我的表单有 method post 我尝试用以下方法更改它 submit button click function var url input id url val
  • 使用 javascript/jquery 从数据库格式化日期的正确方法

    我正在调用包含日期时间数据类型的数据库 日期看起来像这样 2005 05 23 16 06 00 000 当用户从列表中选择某个项目时 我想在表格中显示它 我调用我的控制器操作并返回所有时间的 Json 并将它们放入表中 问题是日期完全错误
  • JsGrid 将嵌套对象加载到表中

    我正在 Django 中开发一个 Web 项目并使用 jsGrid 我遇到了问题并且找不到解决方案 我有一个嵌套的 JSON 数据 它是通过组合多个数据库表记录创建的 这是我的 JSON count 3 results personnel
  • Javascript/jQuery 外部高度()

    Does idOfLememt outerHeight 对所有浏览器产生相同的结果 IE7 有什么不同吗 只要去http api jquery com outerHeight http api jquery com outerHeight
  • 我如何用 javascript/jquery 进行两指拖动?

    我正在尝试创建当有两个手指放在 div 上时拖动 div 的功能 我已将 div 绑定到 touchstart 和 touchmove 事件 我只是不确定如何编写这些函数 就像是if event originalEvent targetTo
  • JavaScript 中“键”的类型是什么?

    当我失去焦点并开始思考一个愚蠢的问题时 我遇到了这样的时刻 var a b value b 的类型是什么 我的意思不是 值 的类型 而是标记为 b 的实际键 背景 当我必须创建一个字符串键时 我开始想知道这一点 var a b value

随机推荐

  • 哈希表(Hash Table)原理及其实现

    原理 介绍 哈希函数构造 冲突处理 举例 拉链法 hash索引跟B树索引的区别 实现 原理 介绍 哈希表 Hash table 也叫散列表 是根据关键码值 Key value 而直接进行访问的数据结构 也就是说 它通过把关键码值映射到表中一
  • 逻辑回归(梯度上升、交叉验证)Python实现

    目录 1 介绍 2 算法实现 3 代码 4 实验结果 1 介绍 logistic回归又称logistic回归分析 是一种广义的线性回归分析模型 常用于数据挖掘 疾病自动诊断 经济预测等领域 例如 探讨引发疾病的危险因素 并根据危险因素预测疾
  • [shell/脚本]检索某个文件夹下的所有文件夹并且复制文件夹下文件到指定目录

    写一个脚本实现不同分支下的代码sync 递归去检索某个文件下的所有文件 bin bash usage source sync code sh 源码路径 目标路径 SOURCEDIR 1 TARGETDIR 2 if d SOURCEDIR
  • node、npm、cnpm踩坑

    文章目录 前言 一 cnpm i 报错无法使用 二 解决步骤 1 查看cnpm 是否安装 2 查看 node 和 npm 版本 3 处理 总结 前言 提示 npm install g cnpm registry https registry
  • vue项目请求控制请求头必须为https

    前言 因为很多项目必须要求是严格模式 不能有http请求 需要限制我们的请求头必须为https 如果是http的话 手动转成https来实现请求效果 实现方法 在 public index html 的 head 标签里面加入以下代码 效果
  • Step4:Angular调试方法

    1 方法一 采用VSCode编译器 下载插件debugger for chrome 选择调试 然后再选择chrome浏览器 在运行中输入npm start执行 就可以在代码中打断点了 2 方法二 在浏览器中按F12打开开发者工具 Sourc
  • Python第二课

    枭 Python第二课 今天讲解了Python的 内置函数 模块导入 序列 列表 切片操作 内置函数 divmod x y 用法 x y divmod a b 其中x返回值a b y返回值a b map func iterablies 用法
  • 4g网络设置dns地址_4G网速越来越慢,通过这三个简单的操作,网速成倍提升

    随着互联网的进步 从零几年开始移动手机在全国开始普及起来 网速也像火箭一样快速飙升 从2G发展到了现在的5G 不过 有很多网友表示 刚从2G或者3G升级到4G时 网速体验非常好 但近两年来的4G网速越来越慢 还卡顿 甚至感觉还不如以前的3g
  • 忘记网站服务器密码怎么办,忘记远程服务器的密码怎么办

    忘记远程服务器的密码怎么办 内容精选 换一换 如果在创建弹性云服务器时未设置密码 或密码丢失 过期 可以参见本节操作重置密码 密码丢失或过期前 已安装密码重置插件 公共镜像创建的弹性云服务器默认已安装一键重置密码插件 私有镜像创建的云服务器
  • Matlab—M_Map的实战学习笔记(一)M_Map库的安装

    最近在做美赛集训 做到了2020年的美赛A题 有关苏格兰附近鲭鱼和鲱鱼分布预测问题 在写论文的过程中 为了画几张精美的地图 可谓是历经千难万险 花费了不少时间 走了不少弯路 现在对使用matlab的m map映射库进行地图绘制做一个总结 力
  • Python:UnicodedecodeError编码问题解决方法汇总-彻底解决

    今天真的被编码问题一直困扰着 午休都没进行 也真的见识到了各种编码 例如 gbk unicode utf 8 ansi gb2312等 如果脚本程序中编码与文件编码不一致 就会报出UnicodedecodeError的错误 1 情景一 读文
  • python语法-面向对象(构造方法、魔术方法)

    python语法 面向对象 构造方法 魔术方法 1 构造方法 构造方法 python类可以使用 init 方法 称之为构造方法 可以实现 在创建类对象时 会自动执行 在创建类对象时 将传入参数自动传递给 init 方法使用 演示使用构造方法
  • Android中的定时器Timer、AlarmManager、CountDownTimer的使用

    1 Timer和TimerTask的使用 java util Timer定时器 实际上是个线程 定时调度所拥有的TimerTasks 1 创建一个Timer code class hljs cs has numbering style di
  • 解析 Linux 内核可装载模块的版本检查机制

    解析 Linux 内核可装载模块的版本检查机制 王 华东 系统工程师 自由职业者 简介 为保持 Linux 内核的稳定与可持续发展 内核在发展过程中引进了可装载模块这一特性 内核可装载模块就是可在内核运行时加载到内核的一组代码 通常 我们会
  • js获取到的时间减1秒或加1秒

    如题 使用时间戳来计算 function setDate time isAdd var date getCurTime time 也可以直接透传如 2021 5 8 var d new Date date var t s d getTime
  • 闲鱼把各种玩法做成了一个平台:哆啦A梦

    玩法平台背景 在闲鱼内我们把供给用户的闲鱼红包 支付宝红包 包邮券 宝卡等统称为用户权益 是闲鱼用户运营的重要策略 在拉新 留存 促活 裂变等方面都展现了其重要价值 在阿里内部管理权益的平台是拉菲 拉菲对外提供概率抽奖和领奖两种能力 各个业
  • 为什么gbk编码常用抽取正则表达式无法抽取“嘚瑟“的“嘚”字

    根据 GBK汉字内码扩展规范编码表 http ff 163 com newflyff gbk list 可以查到 嘚 字的编码为874e 而我们常用的gbk汉字抽取正则表达式为 x80 xff x80 xff 以python正则为例 抽取汉
  • Python基础--入门基础和数据类型测试题(二)

    Made By Zly All Right Reversed 上一篇 篇四 Python 入门基础和数据类型测试题 二 1 以下不属于Python语言保留字的是 A do B pass C while D def 2 表达式3 4 2 8
  • 第一讲 检索系统与数据库编程

    第一讲 检索系统与数据库编程 准备工作 1 检索系统 1 1 检索系统初识 1 1 1 什么是检索系统 1 1 2 从认知心理学看待检索系统 1 2 检索系统的四大法宝 1 2 1 检索的工具 结构化查询语言 SQL 1 2 2 检索的环境
  • Electron-builder打包和自动更新

    前言 文本主要讲述如何为 electron 打包出来软件配置安装引导和结合 github 的 release 配置自动更新 electron builder 是将 Electron 工程打包成相应平台的软件的工具 我的工程是使用 elect