前言
Electron帮助我们突破浏览器的界限,通过Electron构建的桌面应用拥有各种浏览器应用梦寐以求的能力。
Electron提供的autoUpdater还可以帮助我们实现桌面应用的自动更新。
文件结构
首先,我们已经有了一个基于Electron做的应用,项目中有两个package.json。这样做的一个原因是将devDependencies和dependencies分开了,另外就是不需要在打包的时候再去指定哪些依赖不需要一起打到安装包里面去了(通过ignore参数)。
目录结构类似于这样:
myapp -node_modules -package.json -app -js -css -index.html -main.js -package.json
外面的package.json内容类似于:
{ "name": "myapp", "main": "app/main.js", "scripts": { "start": "electron ." }, "devDependencies": { "electron-prebuilt": "^1.2.7" } }
里面的package.json的内容类似于:
{ "name": "myapp", "version": "1.0", "main": "main.js", "description": "my app", "scripts": { "start": "electron ." }, "dependencies": {} }
注意里面的package.json中的name,version,description是必填的,接下来打包会用到。
electron-squirrel-startup
为了使最后的安装包能够实现自动更新,我们需要对现有的应用做一些改动,使它可以处理一些启动或者安装时的事件。
我们可以在main.js里面加入一些处理的代码或者方便起见,我们可以直接使用electron-squirrel-startup。
先安装:
npm install electron-squirrel-startup --save
因为需要在main.js里面用到,我们需要将其安装在app里面。
在main.js里面使用它,第一行加入如下代码即可:
if (require('electron-squirrel-startup')) return;
有兴趣的童鞋可以一起跟我去看看electron-squirrel-startup做了什么事情,急着打包的童鞋可以直接忽略这一段:
在myapp/app/node_modules/electron-squirrel-startup下面有一个index.js:
var path = require('path'); var spawn = require('child_process').spawn; var debug = require('debug')('electron-squirrel-startup'); var app = require('electron').app; var run = function(args, done) { var updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); debug('Spawning `%s` with args `%s`', updateExe, args); spawn(updateExe, args, { detached: true }).on('close', done); }; var check = function() { if (process.platform === 'win32') { var cmd = process.argv[1]; debug('processing squirrel command `%s`', cmd); var target = path.basename(process.execPath); if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { run(['--createShortcut=' + target + ''], app.quit); return true; } if (cmd === '--squirrel-uninstall') { run(['--removeShortcut=' + target + ''], app.quit); return true; } if (cmd === '--squirrel-obsolete') { app.quit(); return true; } } return false; }; module.exports = check();
它的代码只有短短几十行,做的事情也很简单,注意返回值为true的那几行,基本上来说就是安装时,更新完成时,卸载时 main.js都会被调用,我们需要根据不同的情况做不同的事情,完成这些事情后不要启动应用(会出错),直接退出就好。
正常启动前我们需要去检测是否有新的安装包,之后下载新包,重新安装,重启应用,为了做到这一点,我们需要在main.js里面加入如下代码:
app.on('ready', () => { //安装后第一次启动不去检测更新,go做的事情就是启动我们的应用 if (process.argv[1] == '--squirrel-firstrun') { go(); return; } /* 设置自动更新的feedURL,本地测试可以设置为类似于http://127.0.0.1:8080/latest * 在latest文件夹下放着三个我们的安装文件(Setup.exe,RELEASES,myapp-1.0-full.nupkg),下面会讲到 * / autoUpdater.setFeedURL(feedURL); autoUpdater.on('update-downloaded', function() { // 下载完成,更新前端显示 autoUpdater.quitAndInstall(); }); try { // 不是安装应用的情况下启动下回出错,此时直接正常启动应用 autoUpdater.checkForUpdates(); } catch (ex) { go(); return; } // createWindow是我们自己定义的方法,用来创建窗口,此处用来创建检测更新的窗口 createWindow({ name: 'updateWindow', url: 'check-for-updates.html', title: "checkForUpdates", icon: icon, frame: false, width: 1306, height: 750 }); });
自动更新后台搭建
var express = require('express'); var app = express(); app.use(express.static('releases')); var server = app.listen(8080, function() { var host = server.address().address var port = server.address().port console.log("应用实例,访问地址为 http://%s:%s", host, port); });
文件结构如下:
autoupdate-backend -package.json -index.js -node_modules -releases -latest
此时latest文件夹里面还是空的,之后我们开始打包,将打包出来的三个文件放在此处即可。
electron-packager
在myapp下安装:
npm install electron-packager --save-dev npm install electron-packager -g
两种安装方式对应两种使用方式,第一种在脚本中使用,第二种的命令行使用。
脚本中使用,小姐姐在这里借助了gulp,所以需要安装gulp:
npm install gulp --save-dev npm install gulp -g
新建GulpFile.js,定义一个task:
var gulp = require('gulp'); var platform = 'win32'; var arch = 'ia32'; var appPath = 'app'; var packageOutPath = 'production/package'; var iconPath = 'app/favicon.ico'; gulp.task('generate-package', () => { generatePackage(); }); function generatePackage(callback) { var packager = require('electron-packager') packager({ dir: appPath, platform: platform, arch: arch, out: packageOutPath, icon: iconPath, /*桌面快捷方式名称以及开始菜单文件夹名称*/ 'version-string': { CompanyName: 'MyCompany Inc.', ProductName: 'myapp' } }, function (err) { if (err) { console.log(err); } else { callback && callback(); } }); }
需要打包的时候,打开命令行:
gulp generate-package
这样做的好处是调用方便,当然我们也可以直接通过命令行调用electron-packager,前提是我们全局安装了它或者将其安装目录添加到了环境变量中:
更多参数一一加上即可。
贴上官方文档链接:
github链接:https://github.com/electron-userland/electron-packager
下面两个链接在上面的文档里面都能找到,但是个人感觉比较常用,还是贴出来:
参数使用:https://github.com/electron-userland/electron-packager/blob/master/usage.txt
脚本使用:https://github.com/electron-userland/electron-packager/blob/master/docs/api.md
打包
myapp下安装electron-winstaller:
npm install electron-winstaller --save-dev
还是在gulp里面添加一个task,连同package的代码一起贴上:
var gulp = require('gulp'); var platform = 'win32'; var arch = 'ia32'; var appPath = 'app'; var outName = 'myapp-win32-' + arch; var packageOutPath = 'production/package'; var installerOutPath = 'production/installer'; var packagePath = `${packageOutPath}/${outName}`; var installerPath = `${installerOutPath}/${outName}`; var iconPath = 'app/favicon.ico'; var gifPath = 'loading.gif'; gulp.task('generate-package', () => { generatePackage(); }); gulp.task('generate-installer', () => { isDirExist(packagePath, (exist) => { if (exist) { generateInstaller(); } else { generatePackage(() => { generateInstaller(); }); } }); }); function isDirExist(path, callback) { fs.readdir(path, (err) => { callback && callback(!err); }); } function generatePackage(callback) { var packager = require('electron-packager') packager({ dir: appPath, platform: platform, arch: arch, out: packageOutPath, icon: iconPath, /*桌面快捷方式名称以及开始菜单文件夹名称*/ 'version-string': { CompanyName: 'MyCompany Inc.', ProductName: 'myapp' } }, function (err) { if (err) { console.log(err); } else { callback && callback(); } }); } function generateInstaller() { var electronInstaller = require('electron-winstaller'); electronInstaller.createWindowsInstaller({ appDirectory: packagePath, outputDirectory: installerPath, loadingGif: gifPath, authors: 'ganyouyin', exe: 'myapp.exe', title: 'My APP', iconUrl: `${__dirname}/${iconPath}`, setupIcon: iconPath, setupExe: 'Setup.exe', noMsi: true }).then(() => console.log("It worked!"), (e) => console.log(`No dice: ${e.message}`)); }
之后执行任务:
gulp generate-installer
第一次会非常慢,但是执行完成后我们的安装包就出来了。
此时我们的文件结构是:
myapp -GulpFile.js -package.json -node_modules -app -production -package -myapp-win32-ia32 - 各种文件,包含一个myapp.exe,双击可以直接运行 -installer -myapp-win32-ia32 -Setup.exe -RELEASES -myapp-1.0-full.nupkg
有了三个文件,将他们粘到之前的autoupdate-backend/releases/latest文件夹下面。
测试
- 启动我们的自动更新后台;
- 将myapp/app下的package.json里面的version改为1.1,再次打包;
- 将之前的autoupdate-backend中的latest文件夹重命名为1.0;
- 新建文件夹latest,将新打包产生的三个文件粘进去;
- 双击1.0里面的Setup.exe安装应用;
- 关闭应用,双击桌面上的快捷方式myapp.exe再次打开应用;
不出意外此时就会去进行自动更新的操作,结束后自动重启,再次打开时已经是1.1的应用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】
- 谭咏麟.2022-倾·听【环球】【WAV+CUE】
- 4complete《丛生》[320K/MP3][85.26MB]
- 4complete《丛生》[FLAC/分轨][218.01MB]
- 羽泉《给未来的你&天黑天亮》[WAV+CUE][968M]
- 庄心妍《我也许在等候》[低速原抓WAV+CUE]
- 王雅洁《小调歌后2》[原抓WAV+CUE]
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】