electron-updater更新electron应用程序

一、npm安装

具体参考https://www.cnblogs.com/lgx5/p/10732016.html

二、使用vue-cli构建electron项目

vue init simulatedgreg/electron-vue my-project
electron-updater更新electron应用程序_第1张图片
2019-08-29_140927.png

2.1 electron官网地址

 https://electronjs.org/   

2.2 下载package.json中的依赖

npm install

2.3 运行

npm run dev
electron-updater更新electron应用程序_第2张图片
2019-08-29_150322.png

2.4 打包程序electron-builder

npm run build

2.5 win32打包成exe文件

 "win": {
  "icon": "build/icons/icon.ico",
  "target": "nsis"
},
"nsis": {
  "oneClick": false,
  "allowToChangeInstallationDirectory": true,//自定义安装目录
  "allowElevation": true,
  "installerIcon": "build/icons/icon.ico",
  "createDesktopShortcut": true //生成桌面图标
},
"extraResources": {
  "from": "build/icons",
  "to": "./"
},

说明:extraResources是把图标资源复制到打包后的根目录,以后托盘时会用到,如图,

electron-updater更新electron应用程序_第3张图片
2019-08-29_143025.png

2.6 使用electron-updater更新升级程序

2.6.1 配置更新程序的地址

在package.json中添加如下配置:

 "publish": [
  {
    "provider": "generic",
    "url": "http://127.0.0.1:8090/demo/" 
  }
]

说明:url是自己放置更新程序包的访问地址,这里的地址是使用nginx构建的文件服务器地址,上面的这个地址一定要配置,否则在打包时无法生成app-update.yml文件而会导致无法升级

2.6.2 添加依赖

"electron-updater": "^4.0.0"

升级的时候往往就是因为electron-updater版本不搭配,导致一些乱七八糟的问题出现,此时electron的版本是2.0.4,打包的时候如果electron-updater的版本小于4.0.0,会出现无法打包,所以修改electron-updater的版本为^4.0.0

2.6.3 主进程中配置升级

  // =================================================================================================================
// 更新升级,注意这个autoUpdater不是electron中的autoUpdater
// 更新地址
const fs = require('fs-extra')
const updateURL = 'http://127.0.0.1:8090/demo/update/'
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
export function handleUpdate () {
 //= ==============================================================================================================
//                            清除每次更新下载的文件,否则无法进行更新
//= ==============================================================================================================
// updaterCacheDirName的值与src/main/app-update.yml中的updaterCacheDirName值一致,在windows中会创建一个类似
// C:\Users\Administrator\AppData\Local\electron-updater1\pending文件存储更新下载后的文件"*.exe"和"update-info.json"
let updaterCacheDirName = 'electron-updater1'
const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
log.warn(updatePendingPath)
fs.emptyDir(updatePendingPath)
log.warn(autoUpdater.app.baseCachePath)
//= =================================================================================================================
const message = {
    error: '检查更新出错',
    checking: '正在检查更新……',
    updateAva: '检测到新版本,正在下载……',
    updateNotAva: '现在使用的就是最新版本,不用更新'
  }
  // 设置是否自动下载,默认是true,当点击检测到新版本时,会自动下载安装包,所以设置为false
  autoUpdater.autoDownload = false
  autoUpdater.logger = log
  // https://github.com/electron-userland/electron-builder/issues/1254
  if (process.env.NODE_ENV === 'development') {
    autoUpdater.updateConfigPath = path.join(__dirname, 'default-app-update.yml')
  } else {
    autoUpdater.updateConfigPath = path.join(__dirname, '../../../app-update.yml')
  }
  autoUpdater.setFeedURL(updateURL)
  autoUpdater.on('error', function () {
    mainWindow.webContents.send(message.error)
  })
  autoUpdater.on('checking-for-update', function () {
    mainWindow.webContents.send(message.checking)
  })
  autoUpdater.on('update-available', function (info) {
    mainWindow.webContents.send(message.updateAva)
  })
  autoUpdater.on('update-not-available', function (info) {
    mainWindow.webContents.send(message.updateNotAva)
  })

  // 更新下载进度事件
  autoUpdater.on('download-progress', function (progressObj) {
    log.warn('触发下载。。。')
    console.log(progressObj)
    log.warn(progressObj)
    mainWindow.webContents.send('downloadProgress', progressObj)
  })
  autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
    ipcMain.on('isUpdateNow', (e, arg) => {
      log.warn('开始更新')
      autoUpdater.quitAndInstall()
      mainWindow.destroy()
      // callback()
    })
    mainWindow.webContents.send('isUpdateNow')
  })

  ipcMain.on('checkForUpdate', () => {
    // 执行自动更新检查
    log.warn('执行自动更新检查')
    log.warn(__dirname)
    autoUpdater.checkForUpdates()
  })

  ipcMain.on('downloadUpdate', () => {
    // 下载
    log.warn('执行下载')
    autoUpdater.downloadUpdate()
  })
}

说明:更新过程中出现以下问题:
问题1:Error: TypeError: this.app.whenReady is not a function
问题分析:electron 2.0.4不支持此方法,electron 3+后才支持此方法,所以升级electron为^3.0.0

问题2:无法触发更新,控制台提示Update for version 3.1.13 is not available (latest version: 0.0.2, downgrade is disallowed)

问题分析:查看electron-updater模块下out/appUpdater.js中找到次错误处507行,发现isUpdateAvailable函数返回为false,isUpdateAvailable函数代码:

  async isUpdateAvailable(updateInfo) {
  const latestVersion = (0, _semver().parse)(updateInfo.version);

  if (latestVersion == null) {
    throw (0, _builderUtilRuntime().newError)(`This file could not be downloaded, or the latest version (from update server) does not have a valid semver version: "${latestVersion}"`, "ERR_UPDATER_INVALID_VERSION");
  }

  const currentVersion = this.currentVersion;

  if ((0, _semver().eq)(latestVersion, currentVersion)) {
    return false;
  }

  const isStagingMatch = await this.isStagingMatch(updateInfo);

  if (!isStagingMatch) {
    return false;
  } // https://github.com/electron-userland/electron-builder/pull/3111#issuecomment-405033227
  // https://github.com/electron-userland/electron-builder/pull/3111#issuecomment-405030797


  const isLatestVersionNewer = (0, _semver().gt)(latestVersion, currentVersion);

  if (!this.allowDowngrade) {
    return isLatestVersionNewer;
  }

  const currentVersionPrereleaseComponent = (0, _semver().prerelease)(currentVersion);
  const latestVersionPrereleaseComponent = (0, _semver().prerelease)(latestVersion);

  if (currentVersionPrereleaseComponent === latestVersionPrereleaseComponent) {
    // allowDowngrade taken in account only if channel differs
    return isLatestVersionNewer;
  }

  return true;
}

关键在于 const isStagingMatch = await this.isStagingMatch(updateInfo);这里返回的是false,导致无法更新,分别打印latestVersion和currentVersion发现latestVersion的值是最新安装包程序所对应的版本,而currentVersion却是electron的版本3.1.13,搜索全文发现在package-lock.json中发现electron的版本是3.1.13,所以在这里可以看出有两种解决方式,一种就是直接在package.json中修改程序的新版本大于3.1.13,另一种则是修改electron-updater中appUpdater.js中isUpdateAvailable函数代码

const pkg=require('../../../package.json')
const isLatestVersionNewer = (0, _semver().gt)(latestVersion, pkg.version);

分析代码

//这段代码获取当前版本
if (app == null) {
    this.app = new (_ElectronAppAdapter().ElectronAppAdapter)();
    this.httpExecutor = new (_electronHttpExecutor().ElectronHttpExecutor)((authInfo, callback) => this.emit("login", authInfo, callback));
  } else {
    this.app = app;
    this.httpExecutor = null;
  }

....ElectronAppAdapter.d.ts
import { AppAdapter } from "./AppAdapter";
export declare class ElectronAppAdapter implements AppAdapter {
    private readonly app;
    constructor(app?: Electron.App);
    whenReady(): Promise;
    readonly version: string;
    readonly name: string;
    readonly isPackaged: boolean;
    readonly appUpdateConfigPath: string;
    readonly userDataPath: string;
    readonly baseCachePath: string;
    quit(): void;
    onQuit(handler: (exitCode: number) => void): void;
}

问题4:出现UnhandledPromiseRejectionWarning: Error: ENOENT, dev-app-update.yml not found in D:\hzhh123\workspace\vue-work\electron-demo1\node_modules\electron\dist\resources\default_app.asar
问题描述:dev-app-update.yml文件不存在
问题分析:dev-app-update.yml文件没有打包到default_app.asar中,dev-app-update.yml的格式是怎样的,查看打包后的文件win-unpacked\resources,发现其中一个app-update.yml文件,查阅资料后发现其实dev-app-update.yml的文件内容格式是一样的,那么直接设置成一样的内容

  provider: generic
  url: 'http://127.0.0.1:8090/demo/'
  updaterCacheDirName: electron-demo1-updater

可以发现里面的url就是安装包升级的url,updaterCacheDirName是更新时保存下载文件所用的缓存地址,组成格式是应用名称加-updater,这个目录结构在windows下一般如下:

C:\Users\Administrator\AppData\Local\-electron-demo1-updater\pending

所以调试的时候可以建一个default-app.yml文件放在D:\hzhh123\workspace\vue-work\electron-demo1\node_modules\electron\dist\resources\default_app.asar 下,这里就涉及到asar解压缩,但是这样会很麻烦,打包后也需要这样替换,麻烦,所幸electron-updater中提供了这个文件的属性配置updateConfigPath,可以通过设置这个属性来解决这个问题

if (process.env.NODE_ENV === 'development') {
  autoUpdater.updateConfigPath = path.join(__dirname, 'default-app-update.yml')
} else {
  autoUpdater.updateConfigPath = path.join(__dirname, '../../../app-update.yml')
}

参考https://github.com/electron-userland/electron-builder/issues/1254

2.6.5 渲染更新进程

2.6.5.1 新建一个组件模板components/update/index.vue




2.6.5.2 调用

一般在首页调用这个组件






最终截图:

electron-updater更新electron应用程序_第4张图片
2019-08-29_165425.png

问题:每次只要下载后但是我不更新,我下次更新时就不起作用了
问题分析:在updaterCacheDirName目录中如果存在上次下载的安装包,下次安装时会检测安装包已存在,但是无法进行调用更新,我的解决方法是检测到有新版本时直接将其删除,然后再下载就可以了

  //= ==============================================================================================================
  //                            清除每次更新下载的文件,否则无法进行更新
  //= ==============================================================================================================
  // updaterCacheDirName的值与src/main/app-update.yml中的updaterCacheDirName值一致,在windows中会创建一个类似
  // C:\Users\Administrator\AppData\Local\electron-updater1\pending文件存储更新下载后的文件"*.exe"和"update-info.json"
  let updaterCacheDirName = 'electron-updater1'
  const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
  log.warn(updatePendingPath)
  fs.emptyDir(updatePendingPath)
  log.warn(autoUpdater.app.baseCachePath)

2.7 asar解压缩

安装asar

npm install -g asar

解压

asar extract 压缩文件  解压文件夹

压缩:如果压缩文件存在,则会被替换

asar pack 文件夹  压缩文件名

2.8 完整的代码

https://gitee.com/hzhh123/electron-demo1.git

2.9 electron-log日志

一开始搞更新的时候主进程是如何执行的无法看到,后来看苏南大叔的https://newsn.net/say/electron-log.html后加入了日志调试才能看出问题

"electron-log": "^2.2.17"

主进程中配置electron-log

var log = require('electron-log')
log.transports.console.level = false
log.transports.console.level = 'silly'

你可能感兴趣的:(electron-updater更新electron应用程序)