electron + vue3 项目实战 自动更新

1. 下载更新插件

js 复制代码
 npm install electron-log --save
 npm install electron-updater --save

2.electron主进程添加更新

2.1 更新封装

js 复制代码
// electron/ipc/api/updater.js
const { autoUpdater } = require('electron-updater')
const { dialog, BrowserWindow } = require('electron')
const log = require('electron-log')

// 配置日志
autoUpdater.logger = log
autoUpdater.logger.transports.file.level = 'info'

// 自动更新状态
let updateState = {
  isChecking: false,      // 标记是否正在检查更新
  isDownloading: false,   //  标记是否正在下载更新包
  downloadProgress: 0,    // 记录下载进度百分比 (0-100)
  lastError: null,          // 记录最后一次错误
  updateAvailable: false,   // 标记是否有可用更新
  updateDownloaded: false   // 标记更新是否已下载完成
}

// 主窗口引用
let mainWindow = null

/**
 * 设置主窗口引用
 */
function setMainWindow(window) {
  mainWindow = window
}

/**
 * 检查更新
 */
async function checkForUpdates(event, options = {}) {
  if (updateState.isChecking) {
    return { success: false, message: '正在检查更新中...' }
  }

  try {
    updateState.isChecking = true
    updateState.lastError = null

    console.log('开始检查更新...')

    // 发送检查开始消息
    if (mainWindow) {
      mainWindow.webContents.send('updater:updateMessage', '正在检查更新...')
    }

    const result = await autoUpdater.checkForUpdates()

    // 如果没有找到更新,autoUpdater 会触发 'update-not-available' 事件
    if (result) {
      console.log('发现更新:', result.updateInfo.version)
      return {
        success: true,
        message: `发现新版本 v${result.updateInfo.version}`,
        version: result.updateInfo.version
      }
    }

    return { success: true, message: '正在检查更新...' }
  } catch (error) {
    console.error('检查更新失败:', error)
    updateState.lastError = error.message

    // 发送错误消息
    if (mainWindow) {
      mainWindow.webContents.send('updater:updateError', error.message)
    }

    return {
      success: false,
      message: `检查更新失败: ${error.message}`
    }
  } finally {
    updateState.isChecking = false
  }
}

/**
 * 退出并安装更新
 */
async function quitAndInstall(event) {
  try {
    console.log('准备退出并安装更新...')
    autoUpdater.quitAndInstall()
    return { success: true }
  } catch (error) {
    console.error('安装更新失败:', error)
    return {
      success: false,
      message: `安装更新失败: ${error.message}`
    }
  }
}

/**
 * 获取更新状态
 */
async function getUpdateStatus(event) {
  return {
    ...updateState,
    currentVersion: require('../../package.json').version
  }
}

/**
 * 初始化自动更新监听器
 */
function initializeAutoUpdater() {
  // 检查更新中
  autoUpdater.on('checking-for-update', () => {
    console.log('正在检查更新...')
    updateState.isChecking = true

    if (mainWindow) {
      mainWindow.webContents.send('updater:updateMessage', '正在检查更新...')
    }
  })

  // 发现新版本
  autoUpdater.on('update-available', (info) => {
    console.log('发现新版本:', info.version)
    updateState.updateAvailable = true
    updateState.isChecking = false

    if (mainWindow) {
      mainWindow.webContents.send('updater:updateAvailable', info)
      mainWindow.webContents.send('updater:updateMessage', `发现新版本 v${info.version},正在下载...`)
    }

    // 可选:显示更新提示对话框
    if (mainWindow && process.env.NODE_ENV !== 'development') {
      dialog.showMessageBox(mainWindow, {
        type: 'info',
        title: '发现新版本',
        message: `发现新版本 v${info.version}`,
        detail: '新版本正在后台下载,下载完成后将提示您安装。',
        buttons: ['确定']
      })
    }
  })

  // 没有新版本
  autoUpdater.on('update-not-available', (info) => {
    console.log('当前已是最新版本')
    updateState.isChecking = false
    updateState.updateAvailable = false

    if (mainWindow) {
      mainWindow.webContents.send('updater:updateNotAvailable', info)
      mainWindow.webContents.send('updater:updateMessage', '当前已是最新版本')
    }
  })

  // 下载进度
  autoUpdater.on('download-progress', (progressObj) => {
    updateState.isDownloading = true
    updateState.downloadProgress = Math.floor(progressObj.percent)

    const progressMessage = `下载进度: ${progressObj.percent}% (${progressObj.transferred}/${progressObj.total})`
    console.log(progressMessage)

    if (mainWindow) {
      mainWindow.webContents.send('updater:downloadProgress', progressObj)
      mainWindow.webContents.send('updater:updateMessage', progressMessage)
    }
  })

  // 下载完成
  autoUpdater.on('update-downloaded', (info) => {
    console.log('更新下载完成,准备安装')
    updateState.isDownloading = false
    updateState.updateDownloaded = true
    updateState.downloadProgress = 100

    if (mainWindow) {
      mainWindow.webContents.send('updater:updateDownloaded', info)
      mainWindow.webContents.send('updater:updateMessage', '更新下载完成,准备安装')
    }

    // 提示用户安装更新
    if (mainWindow && process.env.NODE_ENV !== 'development') {
      dialog.showMessageBox(mainWindow, {
        type: 'info',
        title: '更新就绪',
        message: `新版本 v${info.version} 已下载完成`,
        detail: '应用将在关闭后自动安装更新。',
        buttons: ['立即重启', '稍后重启']
      }).then((result) => {
        if (result.response === 0) {
          autoUpdater.quitAndInstall()
        }
      })
    }
  })

  // 更新错误
  autoUpdater.on('error', (err) => {
    console.error('更新错误:', err)
    updateState.isChecking = false
    updateState.isDownloading = false
    updateState.lastError = err.message

    if (mainWindow) {
      mainWindow.webContents.send('updater:updateError', err.message)
      mainWindow.webContents.send('updater:updateMessage', `更新错误: ${err.message}`)
    }
  })

  console.log('自动更新监听器初始化完成')
}

module.exports = {
  checkForUpdates,
  quitAndInstall,
  getUpdateStatus,
  initializeAutoUpdater,
  setMainWindow
}

2.2 主进程添加更新检查

js 复制代码
const { initializeAutoUpdater, setMainWindow } = require(path.resolve(__dirname, '../ipc/api/updater'))
function createWindow() {

   ......
   // 1 设置主窗口引用给更新模块
   setMainWindow(mainWindow)

  // 2 初始化自动更新(仅生产环境)
  if (!config.isDev) {
    initializeAutoUpdater()

     // 应用加载完成后自动检查更新
    mainWindow.webContents.once('did-finish-load', () => {
      setTimeout(() => {
        console.log('应用加载完成,开始自动检查更新...')
        // 通过 IPC 调用检查更新
        mainWindow.webContents.send('updater:autoCheck')
      }, 3000)
    })
  }
  
  // 监听窗口关闭后事件
  mainWindow.on('closed', () => {
    console.log('mainWindow closed', " 主进程关闭 窗口已关闭...")
    mainWindow = null
    // 3删除主窗口引用
    setMainWindow(null)
  })
    

}

2.3 维护preload.js

3 渲染进程封装组件

js 复制代码
// electron更新组件
import AppUpdater from '@/components/AppUpdater'

APP.VUE中引用组件
<template>
  <!-- element-plus 国际化组件处理 -->
  <el-config-provider :locale="elementLocales[effectiveLang]">
    <router-view />
    <AppUpdater />
  </el-config-provider>
</template>

4 配置 package.json

js 复制代码
"build": {
    ......
    "publish": [
      {
        "provider": "github",
        "owner": "github用户名",
        "repo": "github项目名"
      }
    ],
    ......

5 github上维护最新版本

5.1 创建仓库

5.2 创建release

js 复制代码
项目右侧-> 点击release -> New 或者 Draft a new release -> new Tag -> 写 release title -> 上传文件:
1 可执行的安装文件;
2 latest0tml 文件;
-> 最后 Publish release

6 测试更新

js 复制代码
打包一个低版本-> 安装使用 -> 开始就会检查版本,如果有新的版本提示是否安装 -> 是 退出安装,否 稍后安装!
注意:设置了环境只有生产环境才会检查!
相关推荐
opteOG4 小时前
Vue3设计与实现
vue.js
前端没钱4 小时前
Tauri2+vue3+NaiveUI仿写windows微信,安装包仅为2.5M,95%的API用JavaScript写,太香了
前端·vue.js·rust
参宿75 小时前
图解Vue3 响应式,手动实现核心原理
前端·javascript·vue.js
2301_801252225 小时前
前端框架Vue(Vue 的挂载点与 data 数据对象)
java·前端·javascript·vue.js·前端框架
前端白袍5 小时前
Vue:关于 Vue2 父子组件传值方法 以及 props 的定义方法和使用
前端·javascript·vue.js
慧一居士5 小时前
Vue项目页面间,页面中跳转及刷新规划,何时使用router-view,router-link,iframe,slots ,使用场景,及对应场景的完整使用示例
前端·vue.js
Data_Adventure5 小时前
Vue 3 组件重构实战:从重复代码到优雅抽象的三种方案
前端·vue.js
zhangyao9403306 小时前
详细-vue3项目初始化配置流程
vue.js
一枚前端小能手6 小时前
🔄 重学Vue之依赖注入(provide、inject)
前端·javascript·vue.js