Electron实现自定义全量更新

1. 前言

本文主要介绍如何手动实现客户端应用的自动全量更新,通过改造electron-updater实现版本,系统等字段的动态判断更新。

实现后台配置不同设备,版本,系统的版本更新,可自行在后台配置定向更新,批量更新等。

2. 框架

采用electron-egg框架来进行的自动更新,一部分工作框架自带,只需要进行相应的自动更新修改即可。

3. 后台

3.1. 接口

匹配latest.yml的get请求,这个目前是必须的,具体的实现由后端代码自行处理。

kotlin 复制代码
/**
     * 适配Electron的更新,使用Get方式请求
     */
    @GetMapping("ee/latest.yml", produces = ["application/json"])
    open fun eeLatest(appLatestRequest: AppLatestRequest): Any? {

        val appUpdate = appUpdateService.eeLatest(appLatestRequest)

        if(appUpdate == null) {
            return AppUpdateResponse(false)
        } else {
            return AppUpdateResponse(true, appUpdate.version, appUpdate.downloadUrl, appUpdate.sha512)
        }

    }
kotlin 复制代码
/**
     * APP更新接口
     * 优先匹配单设备,在匹配全量的更新记录
     */
    fun check(appUpdateRequest: AppUpdateRequest): AppUpdate? {
        // 查找有没有直接设备匹配的更新记录,如果没有就查找所有
        var appUpdates = appUpdateMapper.selectListByQuery(
            QueryWrapper.create()
                .ge(AppUpdate::version, appUpdateRequest.version)
                .eq(AppUpdate::deviceId, appUpdateRequest.deviceId)
        )

        if(appUpdates.isEmpty()) {
            appUpdates = appUpdateMapper.selectListByQuery(
                QueryWrapper.create()
                    .ge(AppUpdate::version, appUpdateRequest.version)
                    .eq(AppUpdate::deviceId, "all")
            )

            return appUpdates.filter {
                if(!it.checkRule.isNullOrEmpty()) {
                    // 模板表达式匹配
                    return@filter AviatorEvaluator.compile(it.checkRule, true).execute(
                        BeanUtil.beanToMap(appUpdateRequest)
                    ) as Boolean
                }

                return@filter true
            }.firstOrNull()

        } else {

            return appUpdates.filter {
                if(!it.checkRule.isNullOrEmpty()) {
                    // 模板表达式匹配
                    return@filter AviatorEvaluator.compile(it.checkRule, true).execute(
                        BeanUtil.beanToMap(appUpdateRequest)
                    ) as Boolean
                }

                return@filter true
            }.firstOrNull()

        }
    }

3.2. 规则

下发的规则字段匹配可能会非常多,经常变动。这个时候如果通过简单的字段来匹配的话,需要扩充很多字段,需要手动匹配逻辑(大于某个版本,小于某个版本)来进行处理。采用aviator表达式引擎来进行表达式计算,返回表达式是true或者false来决定是否适配这一条配置。

lua 复制代码
AviatorEvaluator.compile(it.checkRule, true).execute(
                        BeanUtil.beanToMap(appUpdateRequest)
                    )

通过配置的校验规则进行判断是否可以下发,参数来源于请求参数。

3.3. 返回JSON定义

kotlin 复制代码
class AppUpdateResponse(
                val canDownload: Boolean? = null,
                val version : String? = null,
                val path : String? = null,
                val sha512 : String? = null) {

}

必须有version,path,sha512字段匹配,canDownload是后台增加用户判断是否需要下载的判断。

3.4. 更新表定义

sql 复制代码
-- auto-generated definition
create table t_app_update
(
    id           int auto_increment
        primary key,
    version      varchar(16)       null comment '版本号',
    device_id    varchar(64)       null comment '设备id',
    download_url varchar(255)      null comment '下载地址',
    sha512       varchar(256)      null comment '加签值',
    check_rule   varchar(255)      null comment '校验规则',
    platform     varchar(20)       null comment '平台  windows mac  linux',
    open_flag    tinyint default 1 null comment '开启标记 1- 开启  0 -关闭',
    tentant_code varchar(16)       null comment '商户号',
    add_time     datetime          null,
    update_time  datetime          null
)
    engine = InnoDB
    charset = utf8mb4;

3.5. downloadUrl

download_url需要放置到外网一个可以访问的地址,用于后续进行下载。本项目采用minio对外提供文件下载地址。

4. 前台

4.1. 更新配置

核心是关闭自动更新,手动配置feedUrl,让请求到后台更新接口上,返回对应的json配置信息

4.1.1. 强制测试版本更新

ini 复制代码
// 强制测试版本更新
    autoUpdater.forceDevUpdateConfig = true;

4.1.2. 关闭自动更新

ini 复制代码
autoUpdater.autoDownload = false;

4.1.3. 设置FeedUrl

ini 复制代码
const version = electronApp.getVersion();
Log.info('[addon:autoUpdater] current version: ', version);

// 设置下载服务器地址
let server = cfg.options.url;
let lastChar = server.substring(server.length - 1);
server = lastChar === '/' ? server : server + "/" + "?version=" + version + "&platform=" + Os.platform();
Log.info('[addon:autoUpdater] server: ', server);
cfg.options.url = server;
try {
  autoUpdater.setFeedURL(cfg.options);
} catch (error) {
  Log.error('[addon:autoUpdater] setFeedURL error : ', error);
}

4.2. 更新监听

需要用到electron和web中的ipc通信,互相进行消息传递。

web node app.checkUpdate 自动或者手动触发更新
node checkUpdate 通过调用feedUrl,检查是否需要更新
node web update-available 有可用更新,通过web弹窗提示
node app.downloadUpdate 开始更新
node web download-progress 更新进度,同步提示给web进行进度条展示
node update-downloaded 下载完成,直接触发系统级别的安装

4.2.1. 更新状态值

yaml 复制代码
const status = {
      error: -1,
      available: 1,
      noAvailable: 2,
      downloading: 3,
      downloaded: 4,
    }

4.3. 弹窗提示

需要监听是否有更新和更新进度两块,这两个合二为一。

arduino 复制代码
ipc.on('app.updater', (event, info) => {
  const infoN = JSON.parse(info)
  console.log('app.updater', infoN)
  // 弹窗提示用户进行更新
  if (infoN.status == 1) {
    // 改为确认框
    ElMessageBox.confirm('发现新版本,是否立即更新?', '更新提示', {
      confirmButtonText: '更新',
      cancelButtonText: '稍后更新',
      type: 'warning'
    }).then((res) => {
      // 用户点击了更新按钮
      console.log('用户点击了更新按钮', res)
      if (res === 'confirm') {
        ipc.invoke('app.downloadUpdate')
        openProgressDialog()
      }
    }).catch(() => {
      // 用户点击了稍后更新按钮

    });
  } else if(infoN.status == 3) {
    updateProgress(infoN.percentNumber)
  }
})


<el-dialog
  v-model="showDialog"
  title="下载进度"
  :show-close="false"
  :close-on-click-modal="false"
  :close-on-press-escape="false"
  width="30%"
>
  <el-progress
    :percentage="percentNumber"
    :stroke-width="18"
    :text-inside="true"
  />
</el-dialog>  

5. 整体思路

5.1. 成果


更新为自动更新,通过ipc调用node,传递token过去

ipc.invoke('app.checkUpdate', userStore.getToken)

5.2. 结果

至此整个功能更新功能基本完成,后续需要开发一个更新页面,用来配置更新条目。适配不同版本,不同设备,不同平台的更新,相应的就可以做到定向更新,灰度更新等功能。

相关推荐
向上的车轮2 分钟前
Spring Boot生态中ORM对数据治理的支持有哪些?
spring boot·数据治理·orm
武昌库里写JAVA1 小时前
使用 Java 开发 Android 应用:Kotlin 与 Java 的混合编程
java·vue.js·spring boot·sql·学习
一只爱撸猫的程序猿2 小时前
创建一个关于智能博物馆导览案例
spring boot·aigc·ai编程
java水泥工3 小时前
Java项目:基于SpringBoot和VUE的在线拍卖系统(源码+数据库+文档)
java·vue.js·spring boot
neoooo3 小时前
JDK 新特性全景指南:从古早版本到 JDK 17 的华丽变身
java·spring boot·后端
我是场4 小时前
Android14内核调试 - boot & vendor_boot
java·开发语言·spring boot
StuVan5 小时前
springboot2整合nacos作为配置中心
spring boot
Q_Q5110082857 小时前
python的校园研招网系统
开发语言·spring boot·python·django·flask·node.js·php
爪洼守门员7 小时前
安装electron报错的解决方法
前端·javascript·electron