electron+vue3+electron-updater 实现程序更新


electron+vue3+electron-updater 实现程序更新

本文主要介绍electron+vue3+electron-updater实现程序更新的具体步骤


一、首先,你需要一个干净的基础的可运行的 electron+vue3 项目

  • 若是不会创建项目,可以参考我的另一篇文章
  • electron+vue3+edge 调用C#.dll文件
  • 那篇文章不要添加 electron-edge-js 模块就是一个干净的基础的可运行的项目

二、引入electron-updater

1.引入 electron-updater 和 electron-log 库

npm install electron-updater
  • electron-log 打印日志方便调试
npm install electron-log

2.在 background.js 中使用

"use strict";

import { app, protocol, BrowserWindow, ipcMain } from "electron";

import { createProtocol } from "vue-cli-plugin-electron-builder/lib";

const { autoUpdater } = require('electron-updater');

const log = require('electron-log');

// const fs = require('fs');

// const fs_extra = require('fs-extra');

// const path = require('path');

const isDevelopment = process.env.NODE_ENV === "development";

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
    { scheme: "app", privileges: { secure: true, standard: true } },
]);

// 存在新版本时,默认自动下载更新
autoUpdater.autoDownload = false // 若想通过渲染进程手动触发,需要设置autoDownload为false


autoUpdater.setFeedURL({
    provider: 'generic',
    url: 'http://106.130.55.44:8082', // 打包文件存放地址
})


async function createWindow() {
    // Create the browser window.
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            // Use pluginOptions.nodeIntegration, leave this alone
            // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
            nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
            contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
        },
    });

    if (process.env.WEBPACK_DEV_SERVER_URL) {
        // Load the url of the dev server if in development mode
        await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
        if (!process.env.IS_TEST) win.webContents.openDevTools();
    } else {
        createProtocol("app");
        // Load the index.html when not in development
        win.loadURL("app://./index.html");
    }

    // if (!isDevelopment) {

    // 

    ipcMain.on('thisCheckForUpdates', () => {

        autoUpdater.checkForUpdates();

        //检查更新
        autoUpdater.on('checking-for-update', () => {
            log.info("正在检查更新...");
        })

        //没有可用更新
        autoUpdater.on('update-not-available', () => {
            log.info('没有可用更新.');
            win.webContents.send('thisUpdatenotavailable', { code: 102, msg: '没有可用更新', data: {} });
        })

        //有可用更新
        autoUpdater.on('update-available', (info) => {

            log.info('有可用更新.' + info);
            log.info(info);

            // autoUpdater.downloadUpdate()
            win.webContents.send('thisUpdateavailable', { code: 200, msg: '有可用更新', data: info });
        })

        // 更新出错
        autoUpdater.on('error', (err) => {
            log.info('更新出错. ' + err);
            win.webContents.send('thisUpdateerror', { code: 200, msg: '更新出错', data: err });
        })

        // 下载进度
        autoUpdater.on('download-progress', (progressObj) => {

            let log_message = progressObj.percent + '% (' + progressObj.transferred + "/" + progressObj.total + ')'

            log.info('下载进度:' + log_message);

            win.webContents.send('thisDownloadprogress', progressObj.percent);
        })

        //更新下载完成
        autoUpdater.on('update-downloaded', (info) => {

            log.info('更新下载完成', info);

            log.info('开始安装...');

            autoUpdater.quitAndInstall();
        })
        // }

    })

    // 接收更新命令
    ipcMain.on('thisDownloadnow', () => {

        // 更新前,删除本地安装包 ↓
        // let updaterCacheDirName = app.getName() + '-updater';
        // const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')

        // fs_extra.emptyDir(updatePendingPath)
        // 更新前,删除本地安装包 ↑

        //开始下载
        autoUpdater.downloadUpdate();

    })
}

// Quit when all windows are closed.
app.on("window-all-closed", () => {
    // On macOS it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== "darwin") {
        app.quit();
    }
});

app.on("activate", () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", async () => {
    // if (isDevelopment && !process.env.IS_TEST) {
    //     // Install Vue Devtools
    //     try {
    //         await installExtension(VUEJS3_DEVTOOLS);
    //     } catch (e) {
    //         console.error("Vue Devtools failed to install:", e.toString());
    //     }
    // }
    createWindow();
});

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
    if (process.platform === "win32") {
        process.on("message", (data) => {
            if (data === "graceful-exit") {
                app.quit();
            }
        });
    } else {
        process.on("SIGTERM", () => {
            app.quit();
        });
    }
}


2.在 vue.config.js 中设置打包配置

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
    transpileDependencies: true,
    pluginOptions: {
        electronBuilder: {
            nodeIntegration: true,
            builderOptions: {
                "appId": "app.electron.wx001",
                "productName": "app",  //项目名,也是生成的安装文件名,即productName.exe
                "copyright": "Copyright © 2023-02-28",
                "directories": {
                    "output": "./dist"
                },
                "publish": {
                    "provider": 'generic',
                    "url": 'http://106.130.55.44:8082' // 服务器的下载链接。下面必须要 latest.yml文件和需要更新的exe文件
                },
                "extraFiles": ["./resources",],  // 把指定的资源复制到程序根目录,即把resources文件夹的内容复制到程序根目录,
                "win": {
                    "icon": "./build/icons/icon.ico", //这里注意配好图标路径,注意需要256x256的 不然会报错
                    "target": [{
                        "target": "nsis",
                        "arch": ["x64",]
                    }]
                },
                nsis: {
                    oneClick: false, // 一键安装
                    allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
                    allowToChangeInstallationDirectory: true, // 允许修改安装目录
                    installerIcon: "./build/icons/icon.ico", // 安装图标
                    uninstallerIcon: "./build/icons/uninsert.ico", //卸载图标
                    installerHeaderIcon: "./build/icons/icon.ico", // 安装时头部图标
                    createDesktopShortcut: true, // 创建桌面图标
                    createStartMenuShortcut: true, // 创建开始菜单图标
                    //  include: "./resources/installer.nsh", //默认安装目录配置文件
                },
            }
        },
    },
})

更新文件挂在IIS的情况下需要注意的地方

  • 需要在IIS上添加MIME类型才能访问。MIME类型为:application/octet-stream
  • 添加MIME
  • 如果不添加MIME就会找不到latest.yml文件,结果就是无法实现更新 报错信息如下
[2023-05-11 16:50:55.409] [info]  开始检测更新...
[2023-05-11 16:50:55.414] [info]  Checking for update...
[2023-05-11 16:50:55.500] [info]  Error in auto-updater. Error: Cannot find channel "latest.yml" update info: HttpError: 404 Not Found
"method: GET url: http://106.130.55.44:8082/latest.yml?noCache=1h05034pq\n\nPlease double check that your authentication token is correct. Due to security reasons, actual status maybe not reported, but 404.\n"
Headers: {
  "content-type": "text/html",
  "server": "Microsoft-IIS/10.0",
  "x-powered-by": "ASP.NET",
  "date": "Thu, 11 May 2023 08:50:53 GMT",
  "content-length": "1163"
}
    at f (E:\Program Files (x86)\QRCloud\app\resources\app.asar\background.js:2:287305)
    at o.handleResponse (E:\Program Files (x86)\QRCloud\app\resources\app.asar\background.js:2:289160)
    at ClientRequest.<anonymous> (E:\Program Files (x86)\QRCloud\app\resources\app.asar\background.js:2:288605)
    at ClientRequest.emit (events.js:315:20)
    at SimpleURLLoaderWrapper.<anonymous> (electron/js2c/browser_init.js:105:6816)
    at SimpleURLLoaderWrapper.emit (events.js:315:20)

  • 文件拓展名:.yml
  • MIME类型:application/octet-stream
  • 在这里插入图片描述

三、打包两个版本的安装包 0.1.0 和 0.2.0

在这里插入图片描述

四、安装0.1.0的版本,把0.2.0版本放到服务器,可以去网页中访问一下latest.yml文件,确保可以访问到而不是404

  • 在这里插入图片描述

  • Tomcat下部署如下图

  • 在这里插入图片描述

  • IIS部署如下(多一个web.config文件,是因为配置MIME)

  • 在这里插入图片描述

最后,打开安装的0.1.0版本的软件,就可以实现更新了,

因为只是实现了功能,但是没有写页面更新的动画效果,

但是可以去日志文件里看更新进度

  • 打开目录C:\Users\OAO\AppData\Roaming\vele\logs 此路是电脑中路径
    在这里插入图片描述
  • 找到 main.log 并打开
[2023-05-11 16:55:35.049] [info]  开始检测更新...
[2023-05-11 16:55:35.054] [info]  Checking for update...
[2023-05-11 16:55:35.153] [info]  {
  version: '0.2.0',
  files: [
    {
      url: 'app Setup 0.2.0.exe',
      sha512: 'XL65AupO/8wLQBHDFqM7JBkq5tKDSXmgbhqC00Ekl+bGSyjhvVWu+K2QBLhS7BrxKhY9SY/cukFn+VWViaRfPw==',
      size: 59516421
    }
  ],
  path: 'app Setup 0.2.0.exe',
  sha512: 'XL65AupO/8wLQBHDFqM7JBkq5tKDSXmgbhqC00Ekl+bGSyjhvVWu+K2QBLhS7BrxKhY9SY/cukFn+VWViaRfPw==',
  releaseDate: '2023-05-11T08:45:28.653Z'
}
[2023-05-11 16:55:36.376] [info]  下载进度:Download speed: 284467 - Downloaded 0.536275526379518% (319172/59516421)
[2023-05-11 16:55:37.673] [info]  下载进度:Download speed: 205174 - Downloaded 0.8339143914584515% (496316/59516421)
[2023-05-11 16:55:38.674] [info]  下载进度:Download speed: 187153 - Downloaded 1.0754410114815203% (640064/59516421)
...中间省略若干行
[2023-05-11 17:02:30.631] [info]  下载进度:Download speed: 142595 - Downloaded 99.52017612080539% (59230847/59516421)
[2023-05-11 17:02:31.670] [info]  下载进度:Download speed: 142557 - Downloaded 99.74218543820032% (59362979/59516421)
[2023-05-11 17:02:32.591] [info]  下载进度:Download speed: 142610 - Downloaded 100% (59516421/59516421)
[2023-05-11 17:02:33.435] [info]  Update downloaded {
  version: '0.2.0',
  files: [
    {
      url: 'app Setup 0.2.0.exe',
      sha512: 'XL65AupO/8wLQBHDFqM7JBkq5tKDSXmgbhqC00Ekl+bGSyjhvVWu+K2QBLhS7BrxKhY9SY/cukFn+VWViaRfPw==',
      size: 59516421
    }
  ],
  path: 'app Setup 0.2.0.exe',
  sha512: 'XL65AupO/8wLQBHDFqM7JBkq5tKDSXmgbhqC00Ekl+bGSyjhvVWu+K2QBLhS7BrxKhY9SY/cukFn+VWViaRfPw==',
  releaseDate: '2023-05-11T08:45:28.653Z',
  downloadedFile: 'C:\\Users\\OAO\\AppData\\Local\\vele-updater\\pending\\app Setup 0.2.0.exe'
}
[2023-05-11 17:02:39.869] [info]  开始安装...

页面展示更新进度动画UI

HomeView.vue

<template>
    <div class="home">
        <img alt="Vue logo" src="../assets/logo.png">

        <h1>Welcome to Your Vue.js App 0.1.0</h1>

        <div v-if="aProgress > 0" style="width:100%;margin: 0 auto;text-align: center;">
            <a-progress type="circle" :percent="aProgress" />
        </div>

        <!-- <HelloWorld msg="Welcome to Your Vue.js App 0.1.0" /> -->

    </div>
</template>

<script>

import { notification, Modal, Progress } from 'ant-design-vue';

import { ipcRenderer } from 'electron';

// import { autoUpdater } from 'electron-updater';

// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'

export default {
    name: 'HomeView',
    components: {
        // 引入进度条组件
        'a-progress': Progress
    },
    data() {
        return {
            aProgress: 0
        }
    },
    mounted() {
        var that = this;

        if (process.env.NODE_ENV === 'production') {
            // 生产环境下的逻辑
            console.log("生产环境");

            that.thisCheckForUpdates();
        } else {
            // 开发环境下的逻辑
            console.log("开发环境")

            var num = 3.2780868997482226.toFixed(2);

            that.aProgress = num;
        }
    },
    methods: {
        /**
         * 
         * @param {string} type 消息类型(success,info,warning,error)
         * @param {string} msg 消息标题
         * @param {string} descr 消息描述
         * @param {number} timer 显示时长,默认1.5秒
         */
        thisSysNoti(type, msg, descr, timer = 1.5) {
            notification[type]({
                message: msg,
                duration: timer,
                description: descr,
            });
        },
        thisCheckForUpdates() {

            var that = this;

            //发送检测更新命令
            ipcRenderer.send('thisCheckForUpdates');

            //接收可以更新的命令
            ipcRenderer.on('thisUpdateavailable', (ev, res) => {

                console.log('有新的版本可用');
                console.log(res);

                var updaterMsg = '有新的版本可用(' + res.data.version + ')';

                // 询问是否更新
                Modal.confirm({
                    title: '温馨提示',
                    content: updaterMsg,
                    onOk() {
                        console.log('开始下载...');
                        ipcRenderer.send('thisDownloadnow');
                        Modal.destroyAll();
                    },
                    onCancel() { },
                });
            })

            ipcRenderer.on('thisUpdatenotavailable', (ev, res) => {
                console.log(res);
                that.thisSysNoti('info', '温馨提示', res.msg, 2.5);
            })

            ipcRenderer.on('thisUpdateerror', (ev, res) => {
                console.log(res);
                that.thisSysNoti('error', '温馨提示', res.msg, 2.5);
            })

            // 监听下载进度
            ipcRenderer.on('thisDownloadprogress', (ev, res) => {
                console.log(res);
                // 下载进度保留2位小数,比如: 3.2780868997482226 => 3.27
                that.aProgress = res.toFixed(2)
            })
        }
    }
}
</script>

效果图

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

下载完成后自动进行安装引导

  • 17
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Electron是一个开源框架,用于构建跨平台的桌面应用程序,结合Vue.js和Vite(一个快速的前端构建工具)可以让您创建现代、高性能的Web视图层,嵌入到 Electron 应用中。RTSP(Real-Time Streaming Protocol)是一种网络协议,用于实时视频流传输。 要在 Electron + Vue3 + Vite 中实现 RTSP 播放,您可以按照以下步骤操作: 1. **安装依赖**: - 安装 `vue-video-player` 或类似的库,它提供了处理媒体流的功能,如 `vue-streaming-api`。 - 如果需要,安装支持 RTSP 解码的库,比如 `fluent-ffmpeg` 或 `mediasoup-client`。 ```bash npm install vue-video-player fluent-ffmpeg --save ``` 2. **设置配置**: 在项目中创建一个配置文件(例如 `config.js`),用于管理 RTSP 地址等信息。 ```javascript export default { rtspsource: 'rtsp://your_rtspserver_url/stream' } ``` 3. **在 Vue 组件中使用**: 使用 Vue 插件或组件内的方法加载并播放 RTSP 流。例如,使用 `vue-video-player`: ```html <template> <div id="player"> <VideoPlayer v-bind:src="config.rtspsource"></VideoPlayer> </div> </template> <script> import VideoPlayer from 'vue-video-player'; import { defineComponent, ref } from 'vue'; import config from '@/config'; export default defineComponent({ components: { VideoPlayer, }, setup() { const player = ref(null); // 当组件挂载后尝试播放 mounted() { player.value.play(); } return { player, }; }, }); </script> ``` 4. **错误处理**: 添加错误处理代码来捕获并处理播放过程中可能出现的问题,如连接失败、编码不兼容等。 5. **优化和调整**: 根据应用需求可能还需要对视频质量、缓冲策略等进行优化,并确保在不同平台上运行稳定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬季色调

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值