Top

在windows平台下electron-builder实现前端程序的打包与自动更新

由于8月份上旬公司开发一款桌面应用程序,在前端开发程序打包更新时遇到一些困扰多日的问题,采用electron-builder最终还是得到解决~

以下是踩坑的过程及对electron打包与更新思路的梳理,electron打包与更新的正确姿势应该如下图所示

下面将逐一展开描述说明

    一、windows系统下环境配置

NPM是随NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
  • 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。

在windows平台系统下,使用cmd命令设置npm安装模块、electron打包所需环境

npm config set prefix "C:\Program Files (x86)\nodejs\npm_global" 设置全局模块安装路径
npm config set cache "C:\Program Files (x86)\nodejs\npm_cache" 设置缓存文件夹
npm config set registry "https://registry.npm.taobao.org" 设置淘宝镜像
electron npm config set electron_mirror "https://npm.taobao.org/mirrors/electron/"  electron可以通过设置淘宝镜像快速下载
npm config set arch ia32
npm config set target_arch ia32
npm config set disturl https://npm.taobao.org/mirrors/atom-shell
npm config set runtime electron
npm config set build_from_source true

    二、打包成可执行的运行包

electron-quick-start中,配置文件package.json中添加一句,通过npm包管理器npm install依赖模块与 npm install electron-packager --save

"scripts": {
    "package": "electron-packager ./ --overwrite -all"
}

执行npm run package 命令,即可得到可执行运行包,可运行包内部大致说明如下图

 由于"../electron-quick-start/electron-quick-start-win32-ia32/resources/app"路径下开发项目代码资源是裸露的,出于安全性和代码保护性考虑

所以需要asar对开发项目资源进行二进制加密,asar加密文件可读不可写.

    三、将打包成可执行的运行包进行asar二进制加密

安装  npm install --save-dev asar 
安装完成以后,就可以使用asar命令将裸露程序文件打包了 asar pack ./app app.asar 
后将app文件移除掉即可

    四、使用NSIS将可执行的运行包打成安装包

在windows系统下采用NSIS将打包成可安装程序

下载前至NSIS 3.0 .1正式版汉化增强版

使用VNISEdit 编译环境具体教程请参考win7下nsis打包exe安装程序教程

生成脚本

  1 ; 该脚本使用 HM VNISEdit 脚本编辑器向导产生
  2 
  3 ; 安装程序初始定义常量
  4 !define PRODUCT_NAME "My application"
  5 !define PRODUCT_VERSION "1.0"
  6 !define PRODUCT_PUBLISHER "My company, Inc."
  7 !define PRODUCT_WEB_SITE "http://www.mycompany.com"
  8 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\electron-quick-start.exe"
  9 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
 10 !define PRODUCT_UNINST_ROOT_KEY "HKLM"
 11 
 12 SetCompressor lzma
 13 
 14 ; ------ MUI 现代界面定义 (1.67 版本以上兼容) ------
 15 !include "MUI.nsh"
 16 
 17 ; MUI 预定义常量
 18 !define MUI_ABORTWARNING
 19 !define MUI_ICON "app.ico"
 20 !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
 21 
 22 ; 欢迎页面
 23 !insertmacro MUI_PAGE_WELCOME
 24 ; 许可协议页面
 25 !insertmacro MUI_PAGE_LICENSE "..\YourSoftwareLicence.txt"
 26 ; 安装目录选择页面
 27 !insertmacro MUI_PAGE_DIRECTORY
 28 ; 安装过程页面
 29 !insertmacro MUI_PAGE_INSTFILES
 30 ; 安装完成页面
 31 !define MUI_FINISHPAGE_RUN "$INSTDIR\electron-quick-start.exe"
 32 !insertmacro MUI_PAGE_FINISH
 33 
 34 ; 安装卸载过程页面
 35 !insertmacro MUI_UNPAGE_INSTFILES
 36 
 37 ; 安装界面包含的语言设置
 38 !insertmacro MUI_LANGUAGE "SimpChinese"
 39 
 40 ; 安装预释放文件
 41 !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
 42 ; ------ MUI 现代界面定义结束 ------
 43 
 44 Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
 45 OutFile "Setup.exe"
 46 InstallDir "$PROGRAMFILES\My application"
 47 InstallDirRegKey HKLM "${PRODUCT_UNINST_KEY}" "UninstallString"
 48 ShowInstDetails show
 49 ShowUnInstDetails show
 50 
 51 Section "MainSection" SEC01
 52   SetOutPath "$INSTDIR"
 53   SetOverwrite ifnewer
 54   File /r "*.*"
 55   CreateDirectory "$SMPROGRAMS\My application"
 56   CreateShortCut "$SMPROGRAMS\My application\My application.lnk" "$INSTDIR\electron-quick-start.exe"
 57   CreateShortCut "$DESKTOP\My application.lnk" "$INSTDIR\electron-quick-start.exe"
 58   File "electron-quick-start.exe"
 59 SectionEnd
 60 
 61 Section -AdditionalIcons
 62   WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
 63   CreateShortCut "$SMPROGRAMS\My application\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
 64   CreateShortCut "$SMPROGRAMS\My application\Uninstall.lnk" "$INSTDIR\uninst.exe"
 65 SectionEnd
 66 
 67 Section -Post
 68   WriteUninstaller "$INSTDIR\uninst.exe"
 69   WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\electron-quick-start.exe"
 70   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
 71   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
 72   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\electron-quick-start.exe"
 73   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
 74   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
 75   WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
 76 SectionEnd
 77 
 78 /******************************
 79  *  以下是安装程序的卸载部分  *
 80  ******************************/
 81 
 82 Section Uninstall
 83   Delete "$INSTDIR\${PRODUCT_NAME}.url"
 84   Delete "$INSTDIR\uninst.exe"
 85   Delete "$INSTDIR\electron-quick-start.exe"
 86 
 87   Delete "$SMPROGRAMS\My application\Uninstall.lnk"
 88   Delete "$SMPROGRAMS\My application\Website.lnk"
 89   Delete "$DESKTOP\My application.lnk"
 90   Delete "$SMPROGRAMS\My application\My application.lnk"
 91 
 92   RMDir "$SMPROGRAMS\My application"
 93 
 94   RMDir /r "$INSTDIR\resources"
 95   RMDir /r "$INSTDIR\locales"
 96 
 97   RMDir "$INSTDIR"
 98 
 99   DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
100   DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
101   SetAutoClose true
102 SectionEnd
103 
104 #-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--#
105 
106 Function un.onInit
107   MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "您确实要完全移除 $(^Name) ,及其所有的组件?" IDYES +2
108   Abort
109 FunctionEnd
110 
111 Function un.onUninstSuccess
112   HideWindow
113   MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机移除。"
114 FunctionEnd
View Code

    五、windows系统安装程序更新

安装npm install  electron-updater 在应用中触发更新检查, electron-updater 自动会通过对应url下的yml文件检查更新

在入口文件main.js中需注意

1 //if you don't use ES6: const autoUpdater = require("electron-updater").autoUpdater
2 const autoUpdater = require('electron-updater').autoUpdater
//ipcMain 主线程
const ipcMain = require('electron').ipcMain

autoUpdater

  1 // 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
  2 function updateHandle(){
  3     //minimize
  4     ipcMain.on('hide-window', () => {
  5         mainWindow.minimize();
  6     });
  7     //maximize
  8     ipcMain.on('show-window', () => {
  9         mainWindow.maximize();
 10     });
 11     //unmaximize
 12     ipcMain.on('orignal-window', () => {
 13         mainWindow.unmaximize();
 14     });
 15     //打开默认浏览器
 16     ipcMain.on('open-office-website', function(event, arg){
 17         shell.openExternal(arg)
 18     })
 19     
 20     ipcMain.on('check-for-update', function(event, arg) {
 21         let message={
 22             appName:'智卡桌面应用讨论',
 23             error:'检查更新出错, 请联系开发人员',
 24             checking:'正在检查更新……',
 25             updateAva:'检测到新版本,正在下载……',
 26             updateNotAva:'现在使用的就是最新版本,不用更新',
 27             downloaded: '最新版本已下载,将在重启程序后更新'
 28         };
 29         //设置检查更新的 url,并且初始化自动更新。这个 url 一旦设置就无法更改。
 30         const updateFeedUrl='http://www.baidu.com/updates/latest/win/';
 31         if(os.platform()==='darwin'){
 32             updateFeedUrl='http://www.baidu.com/updates/latest/mac/';
 33         }
 34         autoUpdater.setFeedURL(updateFeedUrl);
 35 
 36         autoUpdater.on('error', function(error){
 37             return dialog.showMessageBox(mainWindow, {
 38                     type: 'info',
 39                     buttons: ['OK'],
 40                     title: message.appName,
 41                     message: message.errorTips,
 42                     detail: '\r' + message.error
 43                 });
 44 
 45             sendUpdateMessage(message.error)
 46         });
 47 
 48         //当开始检查更新的时候触发
 49         autoUpdater.on('checking-for-update', function() {
 50             sendUpdateMessage(message.checking)
 51             return dialog.showMessageBox(mainWindow, {
 52                     type: 'info',
 53                     buttons: ['OK'],
 54                     title: message.appName,
 55                     message: message.checking
 56                 });
 57         });
 58 
 59         //当发现一个可用更新的时候触发,更新包下载会自动开始
 60         autoUpdater.on('update-available', function(info) {
 61             sendUpdateMessage(message.updateAva)
 62             var downloadConfirmation = dialog.showMessageBox(mainWindow, {
 63                 type: 'info',
 64                 buttons: ['OK'],
 65                 title: message.appName,
 66                 message: message.updateAva
 67             });
 68             if (downloadConfirmation === 0) {
 69                 return;
 70             }
 71         });
 72 
 73         //当没有可用更新的时候触发
 74         autoUpdater.on('update-not-available', function(info) {
 75             return dialog.showMessageBox(mainWindow, {
 76                 type: 'info',
 77                 buttons: ['OK'],
 78                 title: message.appName,
 79                 message: message.updateNotAva
 80             });
 81             sendUpdateMessage(message.updateNotAva)
 82         });
 83         
 84         // 更新下载进度事件
 85         autoUpdater.on('download-progress', function(progressObj) {
 86             mainWindow.webContents.send('downloadProgress', progressObj)
 87         })
 88         /**
 89          *  event Event
 90          *  releaseNotes String - 新版本更新公告
 91          *  releaseName String - 新的版本号
 92          *  releaseDate Date - 新版本发布的日期
 93          *  updateURL String - 更新地址
 94          * */
 95         autoUpdater.on('update-downloaded',  function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
 96             var index = dialog.showMessageBox(mainWindow, {
 97                 type: 'info',
 98                 buttons: ['现在重启', '稍后重启'],
 99                 title: message.appName,
100                 message: message.downloaded,
101                 //detail: releaseName + "\n\n" + releaseNotes
102             });
103             console.log(index);
104             if (index === 1) return;
105             //在下载完成后,重启当前的应用并且安装更新
106             autoUpdater.quitAndInstall();
107             //通过main进程发送事件给renderer进程,提示更新信息
108             //mainWindow.webContents.send('isUpdateNow')
109         });
110         
111         //执行自动更新检查
112         autoUpdater.checkForUpdates();
113     });
114 }

 Squirrel.Windows 是windows系统下electron-updater 检查更新lib库 

关于Squirrel.Windows 更详细说明,请连接至 https://github.com/Squirrel/Squirrel.Windows

Squirrel is both a set of tools and a library, to completely manage both installation and updating your Desktop Windows application, 
written in either C# or any other language (i.e., Squirrel can manage native C++ applications).  

    六、主线程与渲染线程之间通信

点击更新按钮后

1 //检查更新
2  $("#accLogin").find(".T-updateApp").on("click", function() {
3          setTimeout(function() {
4              //update 渲染进程 
5              ipcr.send('check-for-update', 'event-update');
6          }, 20);
7 });

触发主线程(上述步骤五 updateHandle 方法中) ipcMain.on('check-for-update', function(event, arg) { //执行操作 }) 检查更新 autoUpdater各种状态

ipcMain.on('check-for-update', function(event, arg) {
        //设置检查更新的 url,并且初始化自动更新。这个 url 一旦设置就无法更改。
        const updateFeedUrl='http://www.baidu.com/updates/latest/win/';
        if(os.platform()==='darwin'){
            updateFeedUrl='http://www.baidu.com/updates/latest/mac/';
        }
        autoUpdater.setFeedURL(updateFeedUrl);

        autoUpdater.on('error', function(error){});

        //当开始检查更新的时候触发
        autoUpdater.on('checking-for-update', function() {});

        //当发现一个可用更新的时候触发,更新包下载会自动开始
        autoUpdater.on('update-available', function(info) {});

        //当没有可用更新的时候触发
        autoUpdater.on('update-not-available', function(info) {});
        
        // 更新下载进度事件
        autoUpdater.on('download-progress', function(progressObj) {})
        /**
         *  event Event
         *  releaseNotes String - 新版本更新公告
         *  releaseName String - 新的版本号
         *  releaseDate Date - 新版本发布的日期
         *  updateURL String - 更新地址
         * */
        autoUpdater.on('update-downloaded',  function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {});
        
        //执行自动更新检查
        autoUpdater.checkForUpdates();
});

    七、electron-builder 解决方案(项目打包、运行包、安装包、更新、支持多平台)

A complete solution to package and build a ready for distribution Electron app with “auto update” support out of the box

(大致意思 electron-builder一个完整的解决方案,打包和建立一个分发的electron程序与“auto update”支持开箱即用)

通过以上六点知识总结,不难理解electron-builder,这里附一package.json配置文件,后面博主将抽时间写一篇关于electron-builder打包、更新更详细文章

{
  "name": "electron-build",
  "version": "1.6.13",
  "main": "src/main.js",
  "description": "electron-build project",
  "author": "Avenstar",
  "license": "",
  "devDependencies": {
    "electron": "^1.4.15",
    "electron-builder": "^12.3.1"
  },
  "dependencies": {
    "electron-updater": "^1.4.2"
  },
  "scripts": {
    "pack": "electron-builder --dir",
    "build": "electron-builder",
    "dev": "electron src/main.js"
  },
  "keywords": [
    "electron",
    "updater",
    "update",
    "mac",
    "osx",
    "linux",
    "desktop"
  ],
  "build": {
    "appId": "com.cilent.app.electronbuild",
    "productName": "electron-build",
    "directories": {
      "output": "build"
    },
    "files": [
      "src/**/*",
      "node_modules/**/*",
      "package.json"
    ],
    "dmg": {
      "contents": [
        {
          "x": 410,
          "y": 150,
          "type": "link",
          "path": "/Applications"
        },
        {
          "x": 130,
          "y": 150,
          "type": "file"
        }
      ]
    },
    "mac": {
      "category": "your.app.category.type",
       "icon": "static/icons/app.icns",
      "target": [
        "zip",
        "dmg"
      ],
      "publish": [
        {
          "provider":"generic",
          "url":"http://www.baidu.com/updates/latest/mac/"
        }
      ]
    },
    "win": {
      "icon": "static/icons/icon.ico",
      "target": [
        "nsis",
        "zip"
      ],
      "publish": [
        {
          "provider":"generic",
          "url":"http://www.baidu.com/updates/latest/win/"
        }
      ]
    },
    "linux": {
      "icon": "static/icons"
    },
    "nsis":{
      "oneClick":true,
      "artifactName":"${productName}-setup-${version}.${ext}"
    }
  }
}

作者:Avenstar

出处:http://www.cnblogs.com/zjf-1992/p/7354931.html

关于作者:专注于前端开发

本文版权归作者所有,转载请标明原文链接

资料参考

    https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating

    https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating

    https://changkun.us/archives/2017/03/217/?utm_source=tuicool&utm_medium=referral

    https://github.com/amhoho/electron-cn-docs

    https://segmentfault.com/a/1190000010271226

    https://segmentfault.com/a/1190000004863646

    https://github.com/electron-userland/electron-builder

    https://github.com/Squirrel/Squirrel.Windows

    https://segmentfault.com/a/1190000008287730

posted @ 2017-08-15 07:48 Avenstar 阅读(...) 评论(...) 编辑 收藏