Vue electron自动更新/ electron手动更新

Vue electron自动更新 /electron手动更新

Uncaught TypeError: fs.existsSync is not a function

所有的帖子都是一样的,都不去试一下 ,这偏文章我把坑都走了一遍。
直接上代码

最主要的就是这个问题 const electron = require(‘electron’).ipcRenderer 能不用引用
这个问题解决了 后面的就简单了
这么多帖子 居然没有一个说这个问题
代码在gitee上 地址在最下面
在这里插入图片描述

直接引用就会报错
#Uncaught TypeError: fs.existsSync is not a function
在这里插入图片描述

产生问题的原因:

首先在渲染进程属于浏览器端,没有集成Node的环境,所以类似 fs 这样的Node的基础包是不可以使用。

因为没有Node环境,所以require关键词是不可以使用的。

这个 stackoverflow 上找的方法
新建一个 preload.js

const electron = require('electron');
window.ipcRenderer = require('electron').ipcRenderer;   //  直接吧 electron.ipcRenderer 方法挂载在windows上面
window.remote = require('electron').remote;

在main.js文件中的 webPreferen中设置预加载preload:

  const win = new BrowserWindow({
    width: 1920,
    height: 1040,
    frame:true,
    webPreferences: {
      nodeIntegration:true,
      contextIsolation:false,
      webSecurity: false,
      preload:__dirname+'\\preload.js' ,
    }
  })

在这里插入图片描述

这个重点提一下preload.js 存放位置 位置真的很重要 不然就 undefined

本地的 preload.js 放在 打包之后的位置

在这里插入图片描述

打包之后的 preload.js 放在 public 下 和index.html 同目录

在这里插入图片描述

放了两个 我之前就是 只放了一个 所有 本地运行没问题 打包之后就报错了
真特么坑 居然没有一个帖子说这个问题 也有可能只有我遇见了这个问题
不然就是这样 找不到
在这里插入图片描述

下面开始 安装 electron-updater
// 推荐yarn
yarn add electron-updater --save-dev  

// *不推荐 npm  反正我是一次都没装成功过  
**npm i electron-updater --save-dev

这个必须有 不然打包不会生成 latest.yml 文件

每次更新把 yml 和 exe 丢给后端就行了

//这个必须有  不然打包不会生成 latest.yml 文件
 publish:[
      {
     "provider":"generic", 
       url: "http://192.168.0.191/electron/" // 更新文件服务器地址
      }
    ],

新建updata.js

import {
    autoUpdater
} from 'electron-updater'
 
import {
    ipcMain
} from 'electron'
let mainWindow = null;
autoUpdater.autoDownload = false;
let canQuit = false;
export function updateHandle(window, feedUrl) {
    mainWindow = window;
    let message = {
        error: '检查更新出错',
        checking: '正在检查更新……',
        updateAva: '检测到新版本,正在下载……',
        updateNotAva: '现在使用的就是最新版本,不用更新',
    };
    //设置更新包的地址
    autoUpdater.setFeedURL(feedUrl);
    //监听升级失败事件
    autoUpdater.on('error', function (error) {
        sendUpdateMessage({
            cmd: 'error',
            message: error
        })
    });

    //监听开始检测更新事件
    autoUpdater.on('checking-for-update', function (message) {
        sendUpdateMessage({
            cmd: 'checking-for-update',
            message: message
        })
    });
    //监听发现可用更新事件
    autoUpdater.on('update-available', function (message) {
        sendUpdateMessage({
            cmd: 'update-available',
            message: message
        })
    });
    //监听没有可用更新事件
    autoUpdater.on('update-not-available', function (message) {
        sendUpdateMessage({
            cmd: 'update-not-available',
            message: message
        })
    });
 
    // 更新下载进度事件
    autoUpdater.on('download-progress', function (progressObj) {
        sendUpdateMessage({
            cmd: 'download-progress',
            message: progressObj
        })
    });

    autoUpdater.on('close', (event) => {
        if (!canQuit) {
            mainWindow.hide();
            mainWindow.setSkipTaskbar(true);
            event.preventDefault();
        }
    });

    //监听下载完成事件
    autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl) {
        sendUpdateMessage({
            cmd: 'update-downloaded',
            message: {
                releaseNotes,
                releaseName,
                releaseDate,
                updateUrl
            }
        })
        //退出并安装更新包
        if (process.platform !== 'darwin') {
            canQuit = true;
            autoUpdater.quitAndInstall();
        }
        // autoUpdater.quitAndInstall();
    });
 
    //接收渲染进程消息,开始检查更新
    ipcMain.on("checkForUpdate", (e, arg) => {

        //执行自动更新检查

        // sendUpdateMessage({cmd:'checkForUpdate',message:arg})
        if(arg){
            autoUpdater.autoDownload = true;
        }
        autoUpdater.checkForUpdates();
    })
}
//给渲染进程发送消息
function sendUpdateMessage(text) {
    mainWindow.webContents.send('message', text)
}

backgrounnd.ts 我用的ts 这个和你们main.js 是一样


import { app, protocol, BrowserWindow,Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'

// 自动更新    引入上面创建的 updater.js 
import {updateHandle} from './updater.js' ;  

const isDevelopment = process.env.NODE_ENV !== 'production'

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

async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 1920,
    height: 1040,
    frame:true,
    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 as unknown) as boolean,
      // contextIsolation: !(process.env
      //     .ELECTRON_NODE_INTEGRATION as unknown) as boolean,
      nodeIntegration:true,
      contextIsolation:false,
      webSecurity: false,
      // preload:'./src/preload.js' ,
      preload:__dirname+'\\preload.js' ,   这里是重点  //  这里引入 preload.js
    }
  })
  Menu.setApplicationMenu(null)

  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 as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
   
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
    win.webContents.openDevTools()
    // win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
  }
  updateHandle(win, 'http://192.168.0.191/electron/');
}

// 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(VUEJS_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()
    })
  }
}

如果 updater.js 引用错误

在这里插入图片描述

在同目录 把updater.js copy 一份 吧名字改成 updater.ts 就好了

在这里插入图片描述

app.vue 设置更新页面

这个页面包含手动更新 和自动更新

<template>
    <div id="app">
        <a-config-provider :locale="zh_CN">
            <router-view />
        </a-config-provider>

        <a-modal v-model="modalVisible" width="300PX" :footer="null" :closable="false" :keyboard="false"
            :maskClosable="false" wrapClassName="supplement-detail-modal" :title="isUpdatte?'检查到新版本...':'系统正在更新...'">
            <div style="width:120px;margin:30px auto;" v-if="isUpdatte">
                <a-progress type="circle" :percent="percent" :format="percent => `${percent} %`" />
            </div>
            <div style="display:flex;justify-content: space-between;" v-if="!isUpdatte">
                <a-button type="primary" @click="isUpdatte=true" style="margin:30px auto;">
                    更新新版本
                </a-button>
            </div>
        </a-modal>
    </div>

</template>
<script>
    import zh_CN from 'ant-design-vue/lib/locale-provider/zh_CN';
    import moment from 'moment';
    import 'moment/locale/zh-cn';
    import {
        ConfigProvider,
        progress,
        button
    } from 'ant-design-vue'
    // const electron = require('electron').ipcRenderer;

    const ipcRenderer = window.ipcRenderer
    moment.locale('zh-cn');
    export default {
        components: {
            AConfigProvider: ConfigProvider,
            AProgress: progress,
            AButton: button,
        },
        data() {
            return {
                zh_CN,
                modalVisible: false,
                percent: 0,
                isUpdatte: false,
            };
        },
        mounted() {
            if (ipcRenderer) {
                const _this=this
                ipcRenderer.on("message", (event, arg) => {
                    // for (var i = 0; i < arg.length; i++) {
                    console.log(arg);
                    if ("update-available" == arg.cmd) {
                        //显示升级对话框
                        _this.modalVisible = true;
                        if(!_this.isUpdatte)return;
                    } else if ("download-progress" == arg.cmd) {
                        //更新升级进度
                        /**
                         * 
                         * message{bytesPerSecond: 47673
                          delta: 48960
                          percent: 0.11438799862426002
                          total: 42801693
                          transferred: 48960
                          }
                         */
                        console.log(arg.message.percent);
                        let percent = Math.round(parseFloat(arg.message.percent));
                        _this.percent = percent;
                    } else if ("error" == arg.cmd) {
                        _this.modalVisible = false;
                        _this.$message.error("更新失败");
                    }
                    // }
                });
            }
        },
        created() {
            //间隔1小时检测一次
            alert(ipcRenderer)
            let _this=this
            window.setInterval(() => {
            	// _this.isUpdatte == true 就是自动更新 获取到新版会自动更新 重新安装程序  推荐手动更新  
            	//  _this.isUpdatte == false 就是自动更新 
                ipcRenderer.send("checkForUpdate",_this.isUpdatte);
                
            }, 10000);
        }
    };
</script>
<style lang="less">
    .ant-popover-message {
        * {
            font-size: 22px !important;
        }

        .ant-popover-buttons {
            .ant-btn {
                font-size: 22px !important;
            }
        }
    }

    @font-face {
        font-family: AGENCYB;
        src: url('./assets/AGENCYB.TTF');
    }

    @font-face {
        font-family: AGENCYR;
        src: url('./assets/AGENCYR.TTF');
    }

    html,
    body,
    #app {
        height: 100%;
        width: 100%;
        padding: 0;
        margin: 0;
    }

    div {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    .box-title {
        position: relative;
        line-height: 32px;
        height: 32px;
        font-size: 18px;
        padding-left: 15px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        font-weight: bold;

        &.border {
            border-bottom: 1px solid #A7B0C1;
        }

        &:before {
            position: absolute;
            left: 0;
            top: calc(16px - 8px);
            content: '';
            display: inline-block;
            width: 4px;
            height: 18px;
            background: #2c3e50;
        }
    }

    .box-content {
        height: calc(100% - 32px);
    }

    .second-title {
        position: relative;
        line-height: 24px;
        height: 24px;
        font-size: 16px;
        padding-left: 15px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        color: #939393;

        &:before {
            position: absolute;
            left: 0;
            /*top: calc(12px - 3px);*/
            content: '';
            display: inline-block;
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: #5190eb;
        }
    }

    .ant-modal-body {
        padding-top: 0;
    }
</style>

现在获取新版本 直接报错 cmd: “update-not-available”

死活找不到这个问题 全带全部没有问题

原来是 版本号一样 程序判断不需要更新! 明明已经有了 latest.yml 还需要版本号 真的坑

打包的时候 就改一下 package.json 里面 version 就可以了
在这里插入图片描述

到这一本就可以实现 自动更新

你以为完了

他现在是会自动 更新了 TM的 自动更新 安装会失败
原因是因为 appid 是一样
所有修改版本号的同时也要修改 appid

在这里插入图片描述

每次打包都要修改appid 和版本号 无语了

下面放打包 自动修改 version 和appid代码 我的配置在vue.config.js 里面 你也可以把代码放在 build.js 里面

 const path = require('path')
var webpack = require('webpack');
const fs = require('fs');

const demoName="app"
function resolve(dir) {
    return path.join(__dirname, dir)
}

//------------------------ 自动修改 版本号   用版本号 做appid 
function AddZero(time){
    if(time<10){
      return "0"+time
    }else{
      return time
    }
  }
  let packageTxt=fs.readFileSync('./package.json','utf8');
  let versionData = packageTxt.split('\n');
  let packageJson = JSON.parse(packageTxt);
  let VersionArr = packageJson.version.split('.');
  let date = new Date();
  let today = date.getFullYear()+""+AddZero((date.getMonth()+1))+""+AddZero(date.getDate())
  if(today == VersionArr[1]){
    VersionArr[2] = parseInt(VersionArr[2])+1
  }else{
    VersionArr[1] = date.getFullYear()+""+AddZero((date.getMonth()+1))+""+AddZero(date.getDate())
    VersionArr[2] = 1;
  }
  let versionLine = VersionArr.join('.');
  for(let i= 0; i<versionData.length;i++){
    if(versionData[i].indexOf('"version":')!=-1){
      versionData.splice(i,1,'  "version": "'+versionLine+'",');
      break;
    }
  }
  fs.writeFileSync('./package.json',versionData.join('\n'),'utf8');
//------------------------


module.exports = {
    outputDir: 'dist',
    publicPath: './',
    productionSourceMap: false,

    // 简单配置webpack
    configureWebpack: {
        // provide the app's title in webpack's name field, so that
        // it can be accessed in index.html to inject the correct title.
        resolve: {
            alias: {
                '@': resolve('src')
            }
        },
    },
    //  更加细粒化的配置webpack
    //  取自vue-admin-template
   
    chainWebpack: config => {
        config.module
            .rule('svg')
            .exclude.add(resolve('src/svg-icon'))
            .end()
        config.module
            .rule('icons')
            .test(/\.svg$/)
            .include.add(resolve('src/svg-icon'))
            .end()
            .use('svg-sprite-loader')
            .loader('svg-sprite-loader')
            .options({
                symbolId: 'icon-[name]'
            })
            .end()

    },
    pluginOptions: {
        electronBuilder: {
            // List native deps here if they don't work
      // 原生包必须这里声明下
      externals: ["serialport"],
    //   If you are using Yarn Workspaces, you may have multiple node_modules folders
    //   List them all here so that VCP Electron Builder can find them
      nodeModulesPath: ["../../node_modules", "./node_modules"],
      nodeIntegration: true,
            // 打包配置
            builderOptions: {
                "appId": demoName+versionLine,
               
                // 发布者名称
                productName: demoName,

                // 安装包名称,可自行配置
                artifactName: demoName+'.exe',
                
                nsis: {
                    // 一键安装,如果设为true,nsis设置就无意义请直接删除 nsis 配置
                    oneClick: false,
                    // true全用户安装【目录为:C:\Program Files (x86)】,false安装到当前用户
                    perMachine: true,
                    // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
                    allowElevation: true,
                    // 允许修改安装目录
                    allowToChangeInstallationDirectory: true,
                    // 创建桌面图标
                    createDesktopShortcut: true,
                    // 创建开始菜单图标
                    createStartMenuShortcut: true,
                    // 快捷方式的名称,默认为应用程序名称
                    shortcutName: demoName,
                    // 安装图标
                    // installerIcon: "./logo.png",// 安装图标
                    // uninstallerIcon: "./logo.png",//卸载图标
                    // installerHeaderIcon: "./logo.png", // 安装时头部图标
                },
                // files: [
                //     {
                //       'filter': ['**/*']
                //     }
                //   ],
                //   extraFiles: ['./extensions/'],
                //   asar:  false,
                publish:[
                    {
                        "provider":"generic",
                        url: "http://192.168.0.191/electron/" // 更新文件服务器地址
                    }
                ],
            }
        }
    },
  
    
}

如果打包软件报错

在这里插入图片描述
这个因为electron 版本问题

yarn add   electron    //  直接yarn  在安装一遍  不要用npm  

最后放上代码

我知道你想说什么 依赖下载失败
我把 node_modules 都上传了
就问你细不细节

项目地址: vue-eletron 自动更新/手动更新 .

点个赞好吗 铁子!

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值