原生js结合electron。通过electron-builder和electron-updater打包并自动更新

一.package.json文件

先展示一个最终的package.json文件。后边再说都是怎么来的。(注释部分手动清理)

  还有些

{
  "name": "name",//项目名
  "main": "main.js",
  "version": "0.0.2",
  "scripts": {
    "start": "electron .",
    "pack": "electron-builder --dir",
    "dist": "electron-builder" //打包命令 npm run dist 就可以执行打包
  },
//默认安装完electron-builder会在dependencies里,一定要放在这。要不然会报模块找不到 "devDependencies": { "electron": "^10.1.1", "electron-builder": "^22.8.0", "menu": "^0.2.5", "path": "^0.12.7", "socket.io": "^2.3.0" },
//其他的electron就要放在这。要不然也会报模块找不到(最重要的就是electron-updater) "dependencies": { "is-electron": "^2.2.0", "electron-log": "^4.2.4", "electron-updater": "^4.3.4" }, "build": { "productName": "naem",//应用名称 "appId": "**",//应用程序id "directories": { "output": "build"//输出目录 },
  //electron-updater需要的 "publish": [ { "provider": "generic", "url": "http://localhost/",//放latest.yml和.exe文件的服务器路径。(这里我用的nginx) "updaterCacheDirName": "name-updater" } ],
   //安装包源文件目录 把一些公用的提出来,要不然有可能找不到。 "files": [ "./installer.nsh", "./icon.ico", "./index.html", "./main.js", "./package.json", "app/**/*" ],
  //是否用asar打包,默认是true。如果用asar打包的话,那么项目目录将会都打包到asar中。打包完的resource中看不到项目目录
  //如果不用他打包的话,那么resource中将会有完整的项目路径
  //当然就算用asar打包的话。也可以下载asar模块,进行解压。 一般为true默认就好
  "asar":false,  
"dmg": { "contents": [ { "x": 410, "y": 150, "type": "link", "path": "/Applications" }, { "x": 130, "y": 150, "type": "file" } ] }, "mac": { "icon": "./icon.png", "artifactName": "${productName}_setup_${version}.${ext}" }, "win": { "icon": "./icon.png",//exe图标 "artifactName": "${productName}_setup_${version}.${ext}" //exe名称 }, "linux": { "icon": "./icon.png", "artifactName": "${productName}_setup_${version}.${ext}" },
  //增加用户体验的配置(说白了就是安装界面的配置)更人性化了一点 "nsis": { "oneClick": false,//一键安装 "allowElevation": true,//如果为false,就必须提升权限重新启动安装 "allowToChangeInstallationDirectory": true,//修改安装目录 "installerIcon": "./tianyiyun.ico",//安装图标 "uninstallerIcon": "./tianyiyun.ico",//卸载图标 "createDesktopShortcut": true,//快捷方式 "createStartMenuShortcut": true,////开始菜单图标 "include": "./installer.nsh" //自定义脚本。比如一些开机启动啊一类的。可以自己写、找。找不到就算了吧。
    "script" : "build/script/installer.nsh" // NSIS脚本的路径,用于自定义安装程序。 默认为build / installer.nsi
    //最后两个一般不要,除非你想花里胡哨! } },
  //文件输出。可以把文件输出到其他目录。(这里我的是找不到exe图标。所以输出了下) "extraResources": { "from": "/icon.png", "to": "./" } }

1.1 安装依赖(electron-bulider和electron-updater)

  推荐使用tyarn或者cnpm。(因为快)

cnpm install electron-builder --save
cnpm install electron-updater--save

  安装完package.json中会出现这样的配置。上边也说过。一定要改到devDependencies里 

  安装updater时。千万别动。就放在dependencies里。如果还有其他的electron-... ,的模块。也都放在dependencies里

"dependencies": {
        ....
    "electron-builder": "^22.8.0"
  },

二.主进程配置

可以放在main.js里。也可以放在main文件夹下的index.js中(我是放在了main.js了)上代码!

  1 const electron = require('electron');
  2 const app = electron.app;
  3 const path = require('path');
  4 const log = require('electron-log')
  5 log.transports.console.level = false
  6 log.transports.console.level = 'silly'
  7 // 注意这个autoUpdater不是electron中的autoUpdater
  8 const { autoUpdater } = require("electron-updater");
  9 // 更新路径
 10 let updateUrl='';
 11 app.on('ready', function () {
 12     //自己的业务代码
 13     .
 14     .
 15     .
 16 
 17   // 判断是否是生产环境
 18   if (!app.isPackaged) {
 19     // 调试功能
 20     mainWindow.openDevTools();
 21     updateUrl  = "http://localhost/"
 22   }else{
 23     // 更新服务器地址
 24     mainWindow.openDevTools();
     //放打包完exe文件和latest.yml文件的路径
25 updateUrl = "http://服务器地址/" 26 27 } 28 //调用检查更新 29 updateHandle() 30 } 31 32 33 // 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写 34 function updateHandle() { 35 let versionInfo = '' 36 let message = { 37 error: '检查更新出错', 38 checking: '正在检查更新……', 39 updateAva: '检测到新版本', 40 updateNotAva: '现在使用的就是最新版本,不用更新', 41 }; 42 // 设置是否自动下载,默认是true,当点击检测到新版本时,会自动下载安装包,所以设置为false 43 autoUpdater.autoDownload = false 44 autoUpdater.logger = log 45 const os = require('os'); 46 47 autoUpdater.setFeedURL(updateUrl); 48 autoUpdater.on('error', function (error) { 49 sendUpdateMessage(message.error) 50 }); 51 autoUpdater.on('checking-for-update', function () { 52 sendUpdateMessage(message.checking) 53 }); 54 autoUpdater.on('update-available', function (info) { 55 sendUpdateMessage(message.updateAva) 56 // 是否下载 57 mainWindow.webContents.send('isDownloadUpdate', versionInfo); 58 }); 59 autoUpdater.on('update-not-available', function (info) { 60 sendUpdateMessage(message.updateNotAva) 61 }); 62 63 // 更新下载进度事件 64 autoUpdater.on('download-progress', function (progressObj) { 65 // log.info(winURL) 66 // log.warn(progressObj) 67 mainWindow.webContents.send('downloadProgress', progressObj) 68 }); 69 70 // 更新下载完成事件 71 autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) { 72 73 ipcMain.on('updateNow', (e, arg) =>{ 74 console.log(arguments); 75 console.log("开始更新"); 76 //some code here to handle event 77 autoUpdater.quitAndInstall(); 78 }); 79 80 mainWindow.webContents.send('isUpdateNow',versionInfo) 81 }); 82 83 ipcMain.on("checkForUpdate",()=>{ 84 //执行自动更新检查 85 let checkInfo = autoUpdater.checkForUpdates() 86 checkInfo.then(function (data) { 87 versionInfo = data.versionInfo // 获取更新包版本等信息 88 }) 89 }); 90 91 ipcMain.on('downloadUpdate', () => { 92 // 下载 93 log.warn('执行下载') 94 autoUpdater.downloadUpdate() 95 }) 96 } 97 98 // 通过main进程发送事件给renderer进程,提示更新信息 99 function sendUpdateMessage(text) { 100 mainWindow.webContents.send('message', text) 101 }

 三.触发监听事件

触发监听事件一般都是在第一个页面来做的。我这里是登录页 login.js

现在登录页的created方法中触发。一启动程序。就会检查是否需要更新

created() {
    .
    .
    .
    // electron应用启动后主动触发检查更新函数
    ipcRenderer.send("checkForUpdate");
}, 

 然后检查到有新版本的时候,main.js里的方法就会调用这些监听事件,来处理升级版本

//下载过程
//downloadProgress事件可能因为下载速度太快,无法触发的问题
ipcRenderer.on("downloadProgress", (event, progressObj)=> {
    // 打开下载进度样式
    app.$data.download=true;
    //progressObj.percent 下载进度
    if( Math.trunc(progressObj.percent)){
        let y = Math.trunc(progressObj.percent)
        var  elem=document.getElementById("ch"); //获取ch
        if (y==100){
            elem.style.backgroundColor="green";//百分百后背景颜色变化
            console.log('下载完成!')
        }
        elem.style.width=y+'%';
        elem.innerHTML=y+"%";// 计数值
    }
    
});
ipcRenderer.on('isUpdateNow', (event, versionInfo) => {
    // 自定义选择效果,效果自行编写
    console.log(versionInfo)
    alert("版本"+versionInfo.version+"下载完成,立即退出升级")
    ipcRenderer.send('updateNow')    
})
ipcRenderer.on('isDownloadUpdate', (event, versionInfo) => {
    // 自定义选择效果,效果自行编写
    console.log(versionInfo)
    if(confirm("检测到新版本,是否立即升级?")){
        console.log('正在升级!')
        ipcRenderer.send('downloadUpdate')
    }else{
        console.log('取消升级!')
    }
})

下载进度的样式可以自己写的炫酷点,我这里比较简单。甚至有点难看【捂脸】

 //html代码,我这里就放在login.html页面了
<div  v-show='download' >
      <div >
  </div>
//css代码
#ch{
   0px;
  height: 50px;
  background-color: pink;
  text-align: right;
  color: green;
  line-height: 50px;
  box-sizing: content-box;
}

现在所有的配置都已经完成了,就可以测试自动升级了

四.自动升级

先把package.json里的版本改成0.0.1,然后执行npm run dist(在package.json里配置的)打包。然后出现一个build的目录,里面有两个非常重要的东西

原生js结合electron。通过electron-builder和electron-updater打包并自动更新

 latest.yml和.exe文件,这两个是要放在服务器下的(package.json里的publish下的url)然后如果有新版本的话,程序就会自动检查到然后更新了

其他的文件就没啥了。第一个是exe的图标,第二个相当于执行.exe文件安装的安装目录。

五.总结

到了现在electron的打包并自动更新就简简单单的配置完成了,如果第一次弄这个,可能会有点懵,没关系,跟着步骤看着注解,一步一步的来就可以了,先看效果。

然后慢慢的就可以了,如果有啥不一样的、或者有问题,欢迎评论留言哦~  咱们一起沟通解决写

ok了!