美文网首页前端
Electron - 自动升级总结

Electron - 自动升级总结

作者: 红薯爱帅 | 来源:发表于2021-06-30 21:48 被阅读0次

    1. 概述

    本文介绍electron应用的在线升级方案调研和开发。

    2. 客户端升级方案探讨

    客户端升级方案

    如上图,通过三个方面讨论一下在线升级的几个概念

    2.1. 带宽因素

    带宽的大小,直接关系到安装包的下载时长。
    带宽因素,其实也就是安装包的体积因素,所以,尽量生成高压缩比的安装包。
    Electron应用的package.jsonbuild字段,可配置安装包的高压缩比:

    {
      "build": {
        "asar": true,
        "compression": "maximum",
        ... 
      }
    }
    

    在安装包大小一定的情况下,在线升级分为全量更新增量更新

    全量更新

    下载NewVersion的Installer,并覆盖安装

    增量更新

    • 方法1,每次Release需要生成与历史所有版本的diff文件,当Client发起Update请求时,对比OldVersion和NewVersion的差别文件,并打包Response给Client
    • 方法2,基于Release包打包经常变动的文件作为增量升级包,例如app.asar。于是,如果更新了其他文件的话,只能强制全量更新
    • 方法3,对比installer单文件差异,然后只下载差异block即可
    • 结论:开发麻烦,增加了在线升级的复杂度,性价比低,项目前期不建议

    Electron应用如何支持增量更新

    Electron-updater采用上述方法3,更新机制和详细日志可以参考附1的日志

    2.2. 用户量

    对于活跃用户量很大的应用,灰度发布很有必要,不论客户端还是服务端
    如果是项目初期,用户量并不多,功能并不复杂,变动大,而且经常迭代更新,全量发布会减少项目的迭代负担,更早发现问题、解决问题
    当然,前提是测试要充分,让用户发现问题是下下策

    全量发布

    针对所有用户发布

    灰度发布

    只针对部分用户发布,可以随机20%发布,也可以基于用户Tag发布(前提是有可用的用户Tag)

    Electron应用如何支持灰度发布

    Electron应用在electron-updater的基础上,也可以支持灰度发布,三个点:

    • latest.yml增加自定义字段,比如grayReleased: 80
    • 客户端每次启动,自动获取是否有可用的update,以及其详细信息,即latest.yml
    • 客户端本地随机生成100以内的自然数,如果小于80,则提示升级或自动升级,否则不升级

    2.3. 兼容性

    强制更新

    启动时,自动无感更新

    这种情况,一般是服务端的升级已不再支持旧版本,Electron应用的实现机制

    • latest.yml记录服务端支持的最低版本,例如minVersionSupported: 0.1.0
    • 客户端每次启动,自动获取是否有可用的update,以及其详细信息,即latest.yml
    • 客户端比较Current VersionminVersionSupported,决定是否强制更新

    可选更新

    启动时,自动可选更新

    强制更新的最后一步,如果CurrentVersion >= minVersionSupported,用户可选择是否立即更新

    启动后,手动检测更新

    一般情况下,在客户端会提供一个Page,供用户手动查看当前版本、检测是否有新版本,以及执行立即更新

    2.4. 其他问题

    2.4.1. 新版本的变更内容

    仿照灰度发布强制更新的做法,可以修改latest.yml来实现

    Electron支持Github Release的Release-Notes,对其他server不支持,所以只能用上面workaround

    2.4.2. 客户端安装失败后怎么办

    这个问题很严重,主要是对终端的适配问题,于是,测试工作就显得尤为重要

    如果真在用户端发生了,需要具体问题具体分析了

    • 如何及时捕获到异常,并告知到服务端
    • 如何回滚到旧版本,让用户先用着

    3. 构建与发布

    3.1. 打包工具

    Electron应用的打包和发布,主流工具有3个,可以参考官网介绍

    经过各种对比,主要是易用性和生态完整性,决定采用electron-builder,官网:https://www.electron.build

    3.2. 自动更新工具

    Differences between electron-updater and built-in autoUpdater

    • Dedicated release server is not required.
    • Code signature validation not only on macOS, but also on Windows.
    • All required metadata files and artifacts are produced and published automatically.
    • Download progress and staged rollouts supported on all platforms.
    • Different providers supported out of the box (GitHub Releases, Amazon S3, DigitalOcean Spaces, Bintray and generic HTTP(s) server).
    • You need only 2 lines of code to make it work.
    import { autoUpdater } from "electron-updater"
    autoUpdater.checkForUpdatesAndNotify()
    

    Electron-updater的优缺点:

    优点

    • 版本更新检查基于package.json中的version字段值,支持三段式的版本号,无法定制
    • 包含在线升级功能,实现了版本检查逻辑及回调、下载安装升级逻辑
    • 支持多种版本服务器,包括自搭建的通用服务器
    • 支持alpha/beta/latest版本更新策略
    • 支持增量更新,实现了增量更新失败时转全量更新的策略(目前只有windows版的,项目组据说计划增加mac版本的增量更新)
    • 支持构建时自动发布版本到服务器
    • *支持降级更新

    缺点

    3.3. Release Server

    Electron的打包最终是为了发布,因此支持不同方式的Publish,Release Server有以下类型:

    • Bintray
    • Generic Server, any HTTP(S) server, such as electron-release-server
    • GitHub
    • S3, AWS Object Storage Server
    • Spaces or Snap Store, the app store for Linux

    electron-release-server是一个完善的Generic Server,支持安装包的上传和下载,以及分类管理,自带Web。缺点是,还需要自己手动upload,不能自动publish。

    本文采用MinIO(类S3的分布式对象存储服务)为例。

    4. 打包开发与测试

    4.1. 启动minio server

    docker run -p 9999:9000 \
      --name minio --rm -d \
      -e "MINIO_ROOT_USER=xxx" \
      -e "MINIO_ROOT_PASSWORD=wJalrXUtnFENG/bxxR12CYxxxwwEXAMPLEKEY" \
      -v /home/xxx/soft/minio/data:/data \
      minio/minio server /data
    

    通过浏览器打开MinIO Dashboard:http://10.211.28.93:9999
    并创建一个prefix是*的readonly的bucket,名字是public,下面会用到

    4.2. 自动打包发布

    修改package.json,增加build字段如下,electron-builder会读这个字段

    增加electron-builder.env文件,内容如下,存储MinIO的秘钥

    # publish to minio witch is s3-likely storage server
    AWS_ACCESS_KEY_ID=xxx
    AWS_SECRET_ACCESS_KEY=wJalrXUtnFENG/bxxR12CYxxxwwEXAMPLEKEY
    

    执行yarn electron-builder --publish always即可打包和发布

    • publish[0].path是auto-updater默认的feedurl,不能包含${version},必须指向最新版本的latest.yml和安装包

    • publish[1]会自动上传安装包到MinIO,主要用于备份

    • publish[2]只是生成了latest.yml,并不会自动上传,需要自动上传功能,需要通过js调用electron-builder实现。可手动move到http-server的目录下即可,也可以采用electron-release-server

    推荐采用MinIO作为release-server,可以自动publish,提高效率

    {
      "build": {
        "appId": "com.foxchat.www",
        "asar": true,
        "compression": "maximum",
        "directories": {
          "output": "release/${version}"
        },
        "electronDownload": {
          "mirror": "https://npm.taobao.org/mirrors/electron/"
        },
        "files": [
          "!node_modules",
          "node_modules/@sentry/**/*",
          "dist/**"
        ],
        "mac": {
          "icon": "build/icons/icon.icns",
          "artifactName": "${productName}-${os}-${arch}-${version}-setup.${ext}",
          "target": [
            "dmg"
          ]
        },
        "win": {
          "icon": "build/icons/logo256.ico",
          "artifactName": "${productName}-${os}-${arch}-${version}-setup.${ext}",
          "target": [
            {
              "target": "nsis",
              "arch": [
                "x64"
              ]
            }
          ]
        },
        "linux": {
          "icon": "build/icons",
          "target": "deb"
        },
        "nsis": {
          "oneClick": false,
          "allowElevation": true,
          "perMachine": false,
          "allowToChangeInstallationDirectory": true,
          "installerIcon": "./build/icons/logo256.ico",
          "uninstallerIcon": "./build/icons/logo256.ico",
          "installerHeaderIcon": "./build/icons/logo256.ico",
          "createDesktopShortcut": true,
          "createStartMenuShortcut": true,
          "shortcutName": "FoxChat",
          "deleteAppDataOnUninstall": false
        },
        "publish": [
          {
            "provider": "s3",
            "bucket": "public",
            "endpoint": "http://10.211.28.93:9999",
            "channel": "latest",
            "path": "/im/artifact/latest/${os}"
          },
          {
            "provider": "s3",
            "bucket": "public",
            "endpoint": "http://10.211.28.93:9999",
            "channel": "latest",
            "path": "/im/artifact/${version}/${os}"
          },
          {
            "provider": "generic",
            "url": "http://10.211.28.93:9797/artifact"
          }
        ]
      },
    }
    

    4.3. Tips

    修改nsis脚本,可以自定义安装界面

    参考:https://github.com/eyasliu/blog/issues/22

    image image

    5. 客户端自动更新开发

    基于electron-updater完成开发,直接上代码

    这里补充几点:

    • app.getVersion()不work的话,可以这样子
    import { version } from '../../../package.json'
    import { app } from 'electron'
    app.getVersion = () => version
    
    • 代码里面的info,就是latest.yml的数据,样例如下
    {
      version: '0.0.7',
      files: [
        {
          url: 'FoxChat-win-0.0.7-setup.exe',
          sha512: '795pdq9/Lt9MuANpM3tChxpCtzsqNe4v2wWyK41kUJ3PABHJns2xo5Jw46CWFOOCEVes57L5lmXV9v4NWNBeXg==',
          size: 62858586
        }
      ],
      path: 'FoxChat-win-0.0.7-setup.exe',
      sha512: '795pdq9/Lt9MuANpM3tChxpCtzsqNe4v2wWyK41kUJ3PABHJns2xo5Jw46CWFOOCEVes57L5lmXV9v4NWNBeXg==',
      releaseDate: '2021-06-29T10:09:27.716Z',
      releaseNotes: [ '增加在线升级功能', '登录功能优化' ],
      minVersionSupported: '0.1.0',
      grayReleased: 100,
      downloadedFile: 'C:\\Users\\Administrator\\AppData\\Local\\foxchat-updater\\pending\\FoxChat-win-0.0.7-setup.exe'
    }
    
    自动升级的安装包下载路径:
    C:\Users\Administrator\AppData\Local\foxchat-updater
    
    Electron-log的默认路径
    C:\Users\Administrator\AppData\Roaming\FoxChat\logs
    
    • TODO,开发一个UI,提高自动升级功能的用户体验
    import { app, dialog } from 'electron'
    import { autoUpdater } from "electron-updater"
    import log from 'electron-log'
    
    log.transports.file.level = "debug"
    autoUpdater.logger = log
    
    function updateHandle() {
        log.info('client version', app.getVersion())
    
        autoUpdater.autoDownload = false
    
        autoUpdater.on('error', (error) => {
            dialog.showErrorBox('Error: ', error == null ? "unknown" : (error.stack || error).toString())
        })
        
        autoUpdater.on('checking-for-update', () => {
            log.info('Checking for update')
        });
    
        autoUpdater.on('update-available', (info) => {
            log.info('Got a new client version, will auto download it', info)
            autoUpdater.downloadUpdate()  
        })
    
        autoUpdater.on('update-not-available', (info) => {
            log.info('Current version is up-to-date', info)
        })
    
        autoUpdater.on('update-downloaded', (info) => {
            log.info(info)
            dialog.showMessageBox({
                type: 'info',
                title: '软件升级',
                message: '发现新版本,是否立即升级?',
                buttons: ['是的', '稍后']
            }).then((resp) => {
                if (resp.response === 0) {
                    log.info('begin to install new version ...')
                    autoUpdater.quitAndInstall(true, true)
                }
            })
        })
    
        autoUpdater.on('download-progress', function (progressObj) {
            log.debug('download progress', progressObj)
        })
    
        autoUpdater.checkForUpdates()
    }
    
    updateHandle()
    
    export {updateHandle}
    

    附1,electron-updater的增量更新日志

    增量更新的机制

    • 对比old-version.exe.blockmap文件和new-version.exe.blockmap文件,计算得到changed blocks
    • 基于changed blocks,计算得到download blockskind=1是需要下载的(change-blocks肯定要大于download-blocks)
    • 下载所有kind=1download blocks,并与本地文件merge,形成available installer

    效果

    从下面的log可以,可以看到只下载了7%大小的文件内容,体积不到4MB:Full: 61,385.34 KB, To download: 4,103.49 KB (7%)

    一次客户端升级的完整日志

    [2021-06-30 15:27:03.799] [info]  client version 0.0.6
    [2021-06-30 15:27:03.807] [info]  Checking for update
    [2021-06-30 15:27:13.150] [info]  Found version 0.0.7 (url: FoxChat-win-0.0.7-setup.exe)
    [2021-06-30 15:27:13.151] [info]  Got a new client version, will auto download it {
      version: '0.0.7',
      files: [
        {
          url: 'FoxChat-win-0.0.7-setup.exe',
          sha512: '795pdq9/Lt9MuANpM3tChxpCtzsqNe4v2wWyK41kUJ3PABHJns2xo5Jw46CWFOOCEVes57L5lmXV9v4NWNBeXg==',
          size: 62858586
        }
      ],
      path: 'FoxChat-win-0.0.7-setup.exe',
      sha512: '795pdq9/Lt9MuANpM3tChxpCtzsqNe4v2wWyK41kUJ3PABHJns2xo5Jw46CWFOOCEVes57L5lmXV9v4NWNBeXg==',
      releaseDate: '2021-06-29T10:09:27.716Z'
    }
    [2021-06-30 15:27:13.155] [info]  Downloading update from FoxChat-win-0.0.7-setup.exe
    [2021-06-30 15:27:13.157] [debug] updater cache dir: C:\Users\Administrator\AppData\Local\foxchat-updater
    [2021-06-30 15:27:13.164] [info]  Download block maps (old: "http://10.211.28.93:9999/public/im/artifact/latest/win/FoxChat-win-0.0.6-setup.exe.blockmap", new: http://10.211.28.93:9999/public/im/artifact/latest/win/FoxChat-win-0.0.7-setup.exe.blockmap)
    [2021-06-30 15:27:13.202] [info]  File has 195 changed blocks
    [2021-06-30 15:27:13.203] [debug] [
      {
        "kind": 0,
        "start": 0,
        "end": 350804
      },
      {
        "kind": 1,
        "start": 350804,
        "end": 430577
      },
      {
        "kind": 0,
        "start": 430577,
        "end": 463345
      },
      {
        "kind": 1,
        "start": 463345,
        "end": 490212
      },
      {
        "kind": 0,
        "start": 490212,
        "end": 10750880
      },
      {
        "kind": 1,
        "start": 10750880,
        "end": 14595768
      },
      {
        "kind": 0,
        "start": 14595640,
        "end": 54052515
      },
      {
        "kind": 1,
        "start": 54052643,
        "end": 54172009
      },
      {
        "kind": 0,
        "start": 54171859,
        "end": 62463158
      },
      {
        "kind": 1,
        "start": 62463308,
        "end": 62479157
      },
      {
        "kind": 0,
        "start": 62479006,
        "end": 62743206
      },
      {
        "kind": 1,
        "start": 62743357,
        "end": 62858586
      }
    ]
    [2021-06-30 15:27:13.220] [info]  Full: 61,385.34 KB, To download: 4,103.49 KB (7%)
    [2021-06-30 15:27:13.224] [info]  Differential download: http://10.211.28.93:9999/public/im/artifact/latest/win/FoxChat-win-0.0.7-setup.exe
    [2021-06-30 15:27:13.249] [debug] download range: bytes=350804-430576
    [2021-06-30 15:27:13.266] [debug] download progress {
      total: 4201972,
      delta: 79773,
      transferred: 79773,
      percent: 1.8984657679775117,
      bytesPerSecond: 1899357
    }
    [2021-06-30 15:27:13.268] [debug] download range: bytes=463345-490211
    [2021-06-30 15:27:13.278] [debug] download progress {
      total: 4201972,
      delta: 106640,
      transferred: 106640,
      percent: 2.5378560352139425,
      bytesPerSecond: 1974815
    }
    [2021-06-30 15:27:13.388] [debug] download range: bytes=10750880-14595767
    [2021-06-30 15:27:13.900] [debug] download progress {
      total: 4201972,
      delta: 3951528,
      transferred: 3951528,
      percent: 94.03984605323406,
      bytesPerSecond: 5845456
    }
    [2021-06-30 15:27:16.128] [debug] download range: bytes=54052643-54172008
    [2021-06-30 15:27:16.138] [debug] download progress {
      total: 4201972,
      delta: 3964841,
      transferred: 3964841,
      percent: 94.3566734856872,
      bytesPerSecond: 1361085
    }
    [2021-06-30 15:27:16.156] [debug] download progress {
      total: 4201972,
      delta: 106053,
      transferred: 4070894,
      percent: 96.88055988949951,
      bytesPerSecond: 1388436
    }
    [2021-06-30 15:27:16.218] [debug] download range: bytes=62463308-62479156
    [2021-06-30 15:27:16.236] [debug] download progress {
      total: 4201972,
      delta: 121902,
      transferred: 4086743,
      percent: 97.2577399373437,
      bytesPerSecond: 1356820
    }
    [2021-06-30 15:27:16.240] [debug] download range: bytes=62743357-62858585
    [2021-06-30 15:27:16.263] [debug] download progress {
      total: 4201972,
      delta: 237131,
      transferred: 4201972,
      percent: 100,
      bytesPerSecond: 1382682
    }
    [2021-06-30 15:27:16.634] [info]  New version 0.0.7 has been downloaded to C:\Users\Administrator\AppData\Local\foxchat-updater\pending\FoxChat-win-0.0.7-setup.exe
    [2021-06-30 15:27:32.884] [info]  begin to install new version ...
    [2021-06-30 15:27:32.885] [info]  Install on explicit quitAndInstall
    [2021-06-30 15:27:32.886] [info]  Install: isSilent: true, isForceRunAfter: true
    [2021-06-30 15:27:33.149] [info]  Update installer has already been triggered. Quitting application.
    [2021-06-30 15:27:43.027] [info]  client version 0.0.7
    [2021-06-30 15:27:43.210] [info]  App starting... 0.0.7
    

    相关文章

      网友评论

        本文标题:Electron - 自动升级总结

        本文链接:https://www.haomeiwen.com/subject/rtcdultx.html