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. 结果

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

相关推荐
摇滚侠1 小时前
Spring Boot3零基础教程,KafkaTemplate 发送消息,笔记77
java·spring boot·笔记·后端·kafka
计算机学长felix4 小时前
基于SpringBoot的“面向校园的助力跑腿系统”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·后端
java水泥工6 小时前
课程答疑系统|基于SpringBoot和Vue的课程答疑系统(源码+数据库+文档)
spring boot·vue·计算机毕业设计·java毕业设计·大学生毕业设计·课程答疑系统
Rocket MAN8 小时前
Spring Boot 缓存:工具选型、两级缓存策略、注解实现与进阶优化
spring boot·后端·缓存
程序定小飞10 小时前
基于springboot的民宿在线预定平台开发与设计
java·开发语言·spring boot·后端·spring
FREE技术10 小时前
山区农产品售卖系统
java·spring boot
摇滚侠12 小时前
Spring Boot3零基础教程,云服务停机不收费,笔记71
java·spring boot·笔记
摇滚侠13 小时前
Spring Boot3零基础教程,监听 Kafka 消息,笔记78
spring boot·笔记·kafka
摇滚侠14 小时前
Spring Boot3零基础教程,RedisTemplate 定制化,笔记70
spring boot·笔记·后端
刘一说14 小时前
深入浅出 Spring Boot 自动配置(Auto-Configuration):原理、机制与最佳实践
java·spring boot·后端