electron创建应用、打包、自动更新

安装环境

  1. 安装node npm cnpm tomcat
  2. 安装 visual studio 2017
  3. 安装 python27
  4. 安装 Squirrel.Windows
    git bush中执行:
    git clone --recursive https://github.com/squirrel/squirrel.windows
    cd squirrel.windows
    …NuGet\NuGet.exe restore
    msbuild /p:Configuration=Release
  5. 参考官网教程:
    打造你的第一个 Electron 应用
    构建步骤(Windows)
    autoUpdater

创建应用

  1. 新建文件夹znyts,里面新建几个文件
//package.json
{
  "name": "znyts",
  "version": "1.0.0",
  "main": "main.js",
  "author": "lyt",
  "description": "a demo create by lyt",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^4.1.0"
  }
}
//main.js
const { app, BrowserWindow } = require('electron')

// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭
let win

function createWindow () {
  // 创建浏览器窗口。
  win = new BrowserWindow({ width: 800, height: 600 })

  // 然后加载应用的 index.html。
  win.loadFile('index.html')
  // win.loadURL('http://localhost:8080')
  

  // 打开开发者工具
  win.webContents.openDevTools()

  // 当 window 被关闭,这个事件会被触发。
  win.on('closed', () => {
    // 取消引用 window 对象,如果你的应用支持多窗口的话,
    // 通常会把多个 window 对象存放在一个数组里面,
    // 与此同时,你应该删除相应的元素。
    win = null
  })
}

// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)

// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在macOS上,当单击dock图标并且没有其他窗口打开时,
  // 通常在应用程序中重新创建一个窗口。
  if (win === null) {
    createWindow()
  }
})

// 在这个文件中,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。
//index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <style>
      body,html{
        margin:0;padding:0;
      }
    </style>
  </head>
  <body>
  	<div>第一个electron 项目</div>
  </body>
</html>
  1. cnpm i 引入依赖
  2. npm start 运行项目
    至此项目启动成功,如图所示
    electron创建项目

打包更新

  1. 安装依赖
    cnpm i -g grunt-cli
    cnpm i --save-dev electron-packager grunt grunt-electron-installer
    cnpm i --save child_process electron-squirrel-startup os
    package.json的scripts中添加几个命令,最终package.json 变化如下
{
  "name": "znyts",
  "version": "1.0.0",
  "main": "main.js",
  "author": "lyt",
  "description": "a demo create by lyt",
  "scripts": {
    "start": "electron .",
    "package": "electron-packager . znyts --asar --win --out target --overwrite",
    "package32": "electron-packager . znyts --asar --platform=win32 --arch=ia32 --out target --overwrite",
    "package64": "electron-packager . znyts --asar --platform=win32 --arch=x64 --out target --overwrite --icon=favicon.ico"
  },
  "devDependencies": {
    "electron": "^4.1.0",
    "electron-packager": "^13.1.1",
    "grunt": "^1.0.3",
    "grunt-electron-installer": "^2.1.0"
  },
  "dependencies": {
    "child_process": "^1.0.2",
    "electron-squirrel-startup": "^1.0.0",
    "os": "^0.1.1"
  }
}
  1. 创建几个文件
//Gruntfile.js
var grunt=require('grunt');

//配置
grunt.config.init({
    pkg: grunt.file.readJSON('gruntPackage.json'),
    'create-windows-installer': {
        x64:{
            version:'1.0.0',
            authors:'lyt',
            projectUrl:'',
            appDirectory:'./target/znyts-win32-x64',//要打包的输入目录
            outputDirectory:'./output',//grunt打包后的输出目录
            exe:'znyts.exe',
            title:"某项目",//项目中文名
            description:'某项目',
            setupIcon:"favicon.ico",//可以到[http://www.faviconico.org/favicon](http://www.faviconico.org/favicon)生成48X48的ico图标
            loadingGif:"loading.gif",//安装应用时的动画,去百度随便找个gif
            noMsi:true
        }
    }
});

//加载任务
grunt.loadNpmTasks('grunt-electron-installer');

//设置为默认
grunt.registerTask('default', ['create-windows-installer']);
//gruntPackage.json
{
  "name": "znyts",
  "version": "1.0.0",
  "devDependencies": {
    "grunt": "^1.2.0",
    "grunt-electron-installer": "^2.1.0"    
  }
}
  1. 修改几个文件
//main.js底部添加

const electron = require('electron')
//自动更新
const autoUpdater = electron.autoUpdater
function startupEventHandle(){
  if(require('electron-squirrel-startup')) return;
  var handleStartupEvent = function () {
    if (process.platform !== 'win32') {
      return false;
    }
    var squirrelCommand = process.argv[1];
    switch (squirrelCommand) {
      case '--squirrel-install':
      case '--squirrel-updated':
        install();
        return true;
      case '--squirrel-uninstall':
        uninstall();
        app.quit();
        return true;
      case '--squirrel-obsolete':
        app.quit();
        return true;
    }
      // 安装
    function install() {
      var cp = require('child_process');    
      var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe');
      var target = path.basename(process.execPath);
      var child = cp.spawn(updateDotExe, ["--createShortcut", target], { detached: true });
      child.on('close', function(code) {
          app.quit();
      });
    }
    // 卸载
    function uninstall() {
      var cp = require('child_process');    
      var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe');
      var target = path.basename(process.execPath);
      var child = cp.spawn(updateDotExe, ["--removeShortcut", target], { detached: true });
      child.on('close', function(code) {
          app.quit();
      });
    }
  };
  if (handleStartupEvent()) {
    return ;
  }
}
function updateHandle(){
  const { ipcMain } = require('electron')
  ipcMain.on('check-for-update', function(event, arg) {
    let appName='某项目更新';
    let appIcon=__dirname + '/favicon.ico';
    let message={
      error:'检查更新出错',
      checking:'正在检查更新……',
      updateAva:'下载更新成功',
      updateNotAva:'现在使用的就是最新版本,不用更新',
      downloaded:'最新版本已下载,将在重启程序后更新'
    };
    const os = require('os');
    const {dialog} = require('electron');
    autoUpdater.setFeedURL('http://localhost:8080/znyts/');//放最新版本文件的文件夹的服务器地址
    autoUpdater.on('error', function(error){
      return dialog.showMessageBox(win, {
          type: 'info',
          icon: appIcon,
          buttons: ['下一步'],
          title: appName,
          message: message.error,
          detail: '\r'+error
      });
    })
    .on('checking-for-update', function(e) {
        return dialog.showMessageBox(win, {
          type: 'info',
          icon: appIcon,
          buttons: ['下一步'],
          title: appName,
          message: message.checking
      });
    })
    .on('update-available', function(e) {
        var downloadConfirmation = dialog.showMessageBox(win, {
            type: 'info',
            icon: appIcon,
            buttons: ['下一步'],
            title: appName,
            message: message.updateAva
        });
        if (downloadConfirmation === 0) {
            return;
        }
    })
    .on('update-not-available', function(e) {
        return dialog.showMessageBox(win, {
            type: 'info',
            icon: appIcon,
            buttons: ['下一步'],
            title: appName,
            message: message.updateNotAva
        });
    })
    .on('update-downloaded',  function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
        var index = dialog.showMessageBox(win, {
            type: 'info',
            icon: appIcon,
            buttons: ['现在重启此程序','稍后重启此程序'],
            title: appName,
            message: message.downloaded,
            detail: releaseName + "\n\n" + releaseNotes
        });
        if (index === 1) return;
        autoUpdater.quitAndInstall();
    });
    autoUpdater.checkForUpdates();
 });
}

startupEventHandle()
updateHandle()
//index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <style>
      body,html{
        margin:0;padding:0;
      }
    </style>
  </head>
  <body>
    <div>第一个electron 项目</div>
    <button id="update">update</button>
    <script>
      //render请求main的数据
      const { ipcRenderer } = require('electron')
      ipcRenderer.send('asynchronous-message', 'ping');
      update.onclick=function(){
        ipcRenderer.send('check-for-update');
      }
      // console.log("更新成功");
    </script>
  </body>
</html>
  1. 执行npm run package64打包, 生成的文件在target 中,点击 znyts.exe 就可以运行该项目,但没有快捷方式和自动更新。目录如图:
    electron build 目录
  2. 执行grunt打出 安装包 ,生成output文件夹如下:
    electron安装包
  3. 双击Setup.exe即可安装并生成桌面快捷方式。安装成功后,可在程序与功能中卸载,如图
    electron打包
  4. 自动更新:
    gruntPackage.json package.json Gruntfile.js 里面的version:1.0.0 改成1.0.2
    index.html 中的// console.log("更新成功");注释打开
  5. 执行第4步,第5步得到新的output文件夹,注意不要执行第6步了。
  6. 使用iis 或tomcat 部署服务器并可以从 http://localhost:8080/znyts/ 获取到新的内容。
    例如我安装并启动了tomcat服务器,默认端口号8080, 将新的output里面的内容放到tomat中,目录结构如下:
    electron打包
  7. 运行znyts程序并点击update按钮,一直下一步即可更新成功,如图:
    在这里插入图片描述
    更新成功之后运行,会在控制台打印出更新成功
  8. 自动更新原理
    1、根据设置的setFeedURL路径,UpdateManager检查路径下的RELEASES文件,与安装目录下的RELEASES文件进行比对。
    2、如果出现版本不同的情况,将下载路径中的更新包,下载完成后自动进行更新(包括修改快捷方式和清除旧版本)。
    3、更新成功后,会保留上一个版本,并清除上一个版本之前的所有版本。

参考

https://segmentfault.com/a/1190000008287730
https://segmentfault.com/a/1190000007616641

源码下载

github源码下载

(ps:欢迎交流,会及时回复的。觉得写的好的,点个赞吧+_+。)

发布了38 篇原创文章 · 获赞 66 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/lyt_angularjs/article/details/88680779