<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Electron升級更新服務

          共 28835字,需瀏覽 58分鐘

           ·

          2021-08-31 11:43

          目錄
          一、 背景 2
          二、 目標 2
          三、 新插件的應用 3
          (一) vue-cli-plugin-electron-builder是什么 3
          (二) 打包服務electron-builder的配置 5
          (三) 更新服務electron-updater 10
          (四) 應用打包 18
          (五) 測試更新 24

          一、 背景

          很久前寫了一篇《Electron自動更新》介紹了當時存在的問題、自動更新的方案、打包的兩種方式和開發(fā)中存在的問題。當時文中應用采用的是 squirrel.windows 的更新機制和 nsis 的自定義安裝策略。通過 electron-builder 將兩者配置后,產(chǎn)出不同的安裝程序 setup.exe 和更新程序 nupkg。然后將 nsissetup.exesquirrel.windows 中的 nupkg 上傳到 electron-release-server 中。利用 electron-release-server 定時檢查策略,對比本地版本和線上版本,自動下載依賴和程序,進行更新并且替換,做到用戶無感知,操作不繁瑣。

          二、 目標

          《Electron自動更新》中的方案完成了當時的目標。

          但是方案中的問題很多。

          問題:

          1. 更新不受用戶控制,無法停止更新。沒法提示用戶是否更新。如果帶寬很小,應用下載完成后就更新,打斷了正在執(zhí)行的腳本;
          2. 更新方案在linux環(huán)境中不適用;
          3. electron-vue項目作者很久不維護;
          4. 官方提供的方案不詳細,自己編寫腳本偏多,考慮可能不全面。

          現(xiàn)在的目標是:

          1. 更為完善的自動更新;
          2. 更新需要提示用戶,需要控制應用是否更新;
          3. 申請管理員權限;
          4. 更新時加入loading。
            這時候,新插件 「vue-cli-plugin-electron-builder」 就出世了。

          三、 新插件的應用

          (一) vue-cli-plugin-electron-builder是什么

          是一款構建帶有 electron 桌面應用的 vue.js 應用程序的插件。

          它的 github 地址:https://github.com/nklayman/vue-cli-plugin-electron-builder。

          它的文檔:https://nklayman.github.io/vue-cli-plugin-electron-builder/。

          具體配置,大家可以去查看文檔,寫的很詳細。

          優(yōu)點:

          1. 一次編寫,到處可用
          2. 可以定制
          3. 支持測試和調試

          飛鴻覺得這個框架很友好,不需要開發(fā)者重寫更新服務,只需要管理好業(yè)務代碼并且提供靜態(tài)服務器用于更新,其他不需要開發(fā)者操心,一步到位。

          創(chuàng)建步驟:

          1. 先用vue-cli3或4創(chuàng)建vue項目
          2. 在項目中添加electron-builder依賴
          3. 啟動應用:npm run electron:serve
          4. 打包應用:npm run electron:build

          備注:當然這些命令你可以在package.json中修改。

          vue create electron-builder-demo 創(chuàng)建項目,

          在項目中添加插件 vue add electron-builder 開始下載 vue-cli-plugin-electron-builder

          vueAddElectronBuilder

          選擇 electron 版本,最好選擇最新的。

          選擇electron版本

          選擇后項目會去拉去electron,這個過程很漫長。如果等不了,看看之前有沒有electron項目,將依賴復制過來。

          npm run electron:serve啟動應用:

          啟動應用

          那么這個命令他做了什么?

          1. 啟動內置開發(fā)服務器,并進行一些修改配合electron正常工作;
          2. 捆綁主進程;
          3. 啟動electron應用并告訴它加載上述開發(fā)服務器的 url。

          最后自動打開應用界面:

          打開應用界面

          你以為完了?不不不,還有很多步驟。

          接下來我們要將打包配置和更新配置都要加上,才能將更新服務打通。

          (二) 打包服務electron-builder的配置

          此時還缺少打包配置,我們可以根據(jù) electron-builder文檔進行配置。之所以不使用electron-packager,是因為這個插件是基于electron-builder開發(fā)的。

          其官網(wǎng)地址如下:https://www.electron.build/。

          在根目錄下新增vue.config.js文件,填寫配置。

          vue.config.js是一個可選的配置文件,如果@vue/cli-service存在于項目根目錄package.json中,項目會自動加載配置文件。

          完整配置如下:

          const path = require('path')
          module.exports = {
              // 部署應用包時的基本 URL
              publicPath'/',
              // 生成的生產(chǎn)環(huán)境構建文件的目錄
              outputDir'dist',
              // 放置生成的靜態(tài)資源 (js、css、img、fonts) 的 (相對于 outputDir 的) 目錄
              assetsDir'assets',
              // 指定生成的 index.html 的輸出路徑 (相對于 outputDir)。也可以是一個絕對路徑。
              indexPath'index.html',
              // 文件名中包含hash
              filenameHashingtrue,
              // 在 multi-page 模式下構建應用, 單頁面一般不需要考慮(詳情查看文檔配置)
              pagesundefined,
              // 保存時自動觸發(fā)eslint
              lintOnSave: process.env.NODE_ENV !== 'production',
              // 是否使用包含運行時編譯器的 Vue 構建版本
              runtimeCompilerfalse,
              // babel 顯示轉譯一個依賴
              transpileDependencies: ['socket.io-client'],
              // 生產(chǎn)環(huán)境source map 關閉可提升打包速度
              productionSourceMapfalse,
              // crossorigin: undefined,
              // integrity: false,
              css: {
                  // modules: false,
                  requireModuleExtensiontrue,
                  extract: process.env.NODE_ENV === 'production',
                  sourceMapfalse,
                  loaderOptions: {
                      less: {
                          prependData``
                      }
                  }
              },
              // 并行打包
              paralleltrue// 默認值require('os').cpus().length > 1,
              pluginOptions: {},
              // 本地開發(fā)服務器配置
              devServer: {
                  // 自動打開瀏覽器
                  opentrue,
                  // 設置為0.0.0.0則所有的地址均能訪問
                  host'0.0.0.0',
                  port8888,
                  httpsfalse,
                  hotOnlyfalse,
                  compresstrue,
                  disableHostChecktrue,
                  // 使用代理
                  proxy: {
                      '/api': {
                          // 目標代理服務器地址
                          target'http://10.66.194.44:8081/',
                          // 允許跨域
                          changeOrigintrue,
                      },
                  },
              },
              // 針對webpack的配置,如果遇到上述配置,能使用的盡量不要改動webpack的配置
              configureWebpackconfig => {
                  if (process.env.NODE_ENV === 'production') {
                      // 為生產(chǎn)環(huán)境修改配置...
                      config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true;
                  } else {
                      // 為開發(fā)環(huán)境修改配置...
                  }
              },
              // chain模式下的webpack plugin配置
              chainWebpackconfig => {
                  // 使用svg-sprite-loader的vue.config配置 只應用于src/icons目錄下
                  const svgRule = config.module.rule('svg')
                  svgRule.uses.clear()
                  svgRule
                      .test(/\.svg$/)
                      .include.add(path.resolve(__dirname, './src/icons')).end()
                      .use('svg-sprite-loader')
                      .loader('svg-sprite-loader')
                      .options({
                          symbolId'icon-[name]'
                      })
                  const fileRule = config.module.rule('file')
                  fileRule.uses.clear()
                  fileRule
                      .test(/\.svg$/)
                      .exclude.add(path.resolve(__dirname, './src/icons'))
                      .end()
                      .use('file-loader')
                      .loader('file-loader')
                  config
                      .plugin('env')
                      .use(require.resolve('webpack/lib/ProvidePlugin'), [{
                          jQuery'jquery',
                          $'jquery',
                          "windows.jQuery""jquery"
                      }]);
                  config.resolve.alias.set('@', path.join(__dirname, './src'))
              },
              pluginOptions: {
                  electronBuilder: {
                      externals: ['log4js'],
                      // 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'],
                      nodeIntegrationtrue,
                      chainWebpackMainProcess(config) => {
                          // 修復HMR
                          config.resolve.symlinks(true);
                          config.resolve.alias.set('@', path.join(__dirname, './src'))
                          // Chain webpack config for electron main process only
                      },
                      chainWebpackRendererProcess(config) => {
                          // 修復HMR
                          config.resolve.symlinks(true);
                          // 使用svg-sprite-loader的vue.config配置 只應用于src/icons目錄下
                          const svgRule = config.module.rule('svg')
                          svgRule.uses.clear()
                          svgRule
                              .test(/\.svg$/)
                              .include.add(path.resolve(__dirname, './src/icons')).end()
                              .use('svg-sprite-loader')
                              .loader('svg-sprite-loader')
                              .options({
                                  symbolId'icon-[name]'
                              })
                          const fileRule = config.module.rule('file')
                          fileRule.uses.clear()
                          fileRule
                              .test(/\.svg$/)
                              .exclude.add(path.resolve(__dirname, './src/icons'))
                              .end()
                              .use('file-loader')
                              .loader('file-loader')
                          config.resolve.alias.set('@', path.join(__dirname, './src'))
                          // Chain webpack config for electron renderer process only (won't be applied to web builds)
                      },
                      // Changing the Output Directory
                      outputDir"dist_electron",
                      // Electron's Junk Terminal Output https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/configuration.html#electron-s-junk-terminal-output
                      removeElectronJunkfalse,
                      // Use this to change the entrypoint of your app's main process
                      mainProcessFile'background/main.js',
                      // Use this to change the entry point of your app's render process. default src/[main|index].[js|ts]
                      rendererProcessFile'src/main.js',
                      // Provide an array of files that, when changed, will recompile the main process and restart Electron
                      // Your main process file will be added by default
                      mainProcessWatch: ['background/main.js'],
                      // Provide a list of arguments that Electron will be launched with during "electron:serve",
                      // which can be accessed from the main process (src/background.js).
                      // Note that it is ignored when --debug flag is used with "electron:serve", as you must launch Electron yourself
                      // Command line args (excluding --debug, --dashboard, and --headless) are passed to Electron as well
                      //   mainProcessArgs: ['--arg-name', 'arg-value']
                      builderOptions: {
                          "productName""Vue Electron",
                          "appId""com.VueElectron",
                          "publish": [{
                              "provider""generic",
                              "url""http://localhost:7777/dist_electron/"
                          }],
                          "win": {
                              "target": [
                                  "nsis"
                              ],
                              "icon""./public/favicon.ico",
                              "requestedExecutionLevel""highestAvailable"
                          },
                          "nsis": {
                              "oneClick"false,
                              "allowElevation"true,
                              "allowToChangeInstallationDirectory"true,
                              "installerIcon""./public/favicon.ico",
                              "uninstallerIcon""./public/favicon.ico",
                              "installerHeaderIcon""./public/favicon.ico",
                              "createDesktopShortcut"true,
                              "createStartMenuShortcut"true,
                              "perMachine"false,
                              "unicode"true,
                              "deleteAppDataOnUninstall"false
                          }
                      }
                  }
              }
          }

          electron-builder 配置可以在 「pluginOptions」 配置,也可以通過外部配置導入的方式。

          (三) 更新服務electron-updater

          當然,要想要更新的話,需要加上更新插件。

          之前飛鴻是使用 electron 自帶的 autoUpdater 插件,現(xiàn)在根據(jù)文檔建議,轉投 electron-updaterautoUpdater 懷抱了。

          electron-updaterelectron 內置的 autoUpdater 還是有區(qū)別的:

          1. 只需要靜態(tài)服務器存放更新文件和版本文件,不需要專用的更新版本服務器,后者使用的就是electron-release-server服務器,優(yōu)缺點很明顯,這里我就不做比較了,可以參考飛鴻之前寫的《Electron自動更新》;
          2. 代碼簽名驗證不僅適用于macOS,也適用于Windows;
          3. 所有必須更新包都會自動生成并發(fā)布;
          4. 支持下載進度。

          Windows 平臺是按照 nsis 更新,mac 是按照 DMG 更新,linux 是按照 AppImage 更新。

          事件區(qū)別

          事件作用Electron自帶的autoUpdaterelectron-updater
          Checking-for-update開始檢查更新的時候觸發(fā)無法差異無法差異
          Update-available又可以使用的更新的時候觸發(fā)更新。自動下載,不可以阻斷默認自動下載,可以阻斷轉化為手動。如果autoDownload為true,則會自動下載更新。提供 info
          Update-not-available沒有可以使用的更新的時候觸發(fā)
          提供 info
          Update-downloaded更新下載完成的時候觸發(fā)更新包下載完成后可以阻斷自動更新。但是應用退出后會自動更新。更新包下載完成后可以阻斷。如果autoInstallOnAppQuit為true,則應用退出后自動更新。為false,則應用退出后不會更新。
          Before-quit-for-update
          調用quitAndInstall()方法之后觸發(fā)
          Error當更新遇到錯誤的時候觸發(fā)提供error信息提供error信息
          Download-progress
          顯示更新進度,提供progress 進度信息 bytesPerSecond percent total transferred

          方法區(qū)別

          方法作用Electron自帶的autoUpdaterelectron-updater
          autoUpdater.setFeedURL(url)設置檢查更新用的url,還初始化自動更新提供url、headers、serverType(適用于mac)跟electron-builder配置的發(fā)布配置選項強相關,如provider、package、repo、owner等
          autoUpdater.getFeedURL()獲得當前更新的url地址

          autoUpdater.checkForUpdates()詢問服務器是否有更新輪詢時間可以開發(fā)自己設置輪詢時間可以開發(fā)自己設置
          autoUpdater.quitAndInstall()重啟應用并在下載后安裝更新。只能在update-download事件后被調用調用這個方法將首先關閉應用,并在關閉后自動調用app.quit()。執(zhí)行一次自動更新可以不調用這個方法。但是在下一次打開應用的時候,應用檢測到更新包下載完成后會自動更新。提供選項isSilent和isForceRunAfter isSilent默認false,windows平臺應用按照靜默模式安裝程序。isForceRunAfter即使是靜默安裝,也可以在完成后運行應用程序。
          autoUpdater.checkForUpdatesAndNotify()
          詢問服務器是否有更新,并且下載提示用戶
          autoUpdater.downloadUpdate()
          如果autoDownload選項設置為false,就可以使用這個方法手動下載更新。
          autoUpdater.channel()
          更換自動更新的channel,可以參考https://www.electron.build/tutorials/release-using-channels#release_using_channels
          ?

          靜默模式安裝

          ?

          安裝時無需任何用戶干預,直接按默認設置安裝。就是更新的時候,應用不需要重新讓用戶選擇安裝路徑等操作,應用直接讀取之前的配置,按照第一次的安裝配置安裝,不顯示任務配置選項。

          ?
          ?

          注意事項:

          1. 靜默模式安裝需要相同數(shù)量的臨時磁盤空間,并使用與標準安裝相同的臨時存儲目錄。如果臨時目錄中沒有足夠的空間,安裝程序不會提醒用戶。
          2. 靜默模式安裝需要與標準安裝相同的時間。在靜默模式安裝開始時,會短暫顯示初始安裝程序窗口或消息,指示安裝已啟動。沒有消息顯示,表明安裝正在進行或已成功完成。

          類型配置選項

          electron-updater獨有的類型配置選項

          參數(shù)作用備注
          autoDownload是否在找到更新時自動下載更新。默認為true這個需要和autoUpdater.downloadUpdate()搭配使用
          autoInstallOnAppQuit是否在應用退出時自動安裝下載的更新默認為true這個和autoUpdater.quitAndInstall()方法有關
          allowPrerelease 是否允許更新到預發(fā)布版本默認為false這個和allowDowngrade有關。只支持github
          fullChangelog獲取所有發(fā)行說明(從當前版本到最新版本),而不僅僅是最新版本。默認為false只支持github
          allowDowngrade只支持github 默認為false
          channel獲取更新channel不支持github
          requestHeaders請求頭
          logger日志
          signals為了類型安全,我們可以使用singals
          currentVersion當前應用程序版本信息

          這樣看來,electron-updater基本上兼容了原生autoUpdater,而且提供的東西功能更多更有用。現(xiàn)在,飛鴻肯定是選擇electron-updater。相信大家肯定也是這樣的。

          安裝使用

          下載electron-updater依賴

          npm install --save-dev electron-updater

          使用依賴包

          const {
            autoUpdater
          } = require("electron-updater");

          Vue-cli-plugin-electron-builder 的更新,也是提供好幾個方案,如 github 這類的第三方托管平臺,參考更新例子:https://github.com/nklayman/electron-auto-update-example。

          還有比如 minio 這類私有平臺,參考更新例子:https://github.com/iffy/electron-updater-example。

          在electron-builder配置的publish中加入url參數(shù),指向minio指定的項目桶。當然我們的應用是可以區(qū)分環(huán)境的。

                      builderOptions: {
          ……
                          "publish": [{
                              "provider""generic",
                              "url": process.env.VUE_APP_PUBLISHMINIO
                          }],
          ……
                      }

          在主進程中,加入更新服務

          ……
          autoUpdater.autoInstallOnAppQuit = false
          autoUpdater.on('checking-for-update', () => {
            logger.info('正在檢查更新……')
          })
          autoUpdater.on('update-available', (ev, info) => {
            logger.info('下載更新包成功')
          })
          autoUpdater.on('update-not-available', (ev, info) => {
            logger.info('現(xiàn)在使用的就是最新版本,不用更新')
          })
          autoUpdater.on('error', (ev, err) => {
            logger.info('檢查更新出錯')
            logger.info(ev)
            logger.info(err)
          })
          autoUpdater.on('download-progress', (ev, progressObj) => {
            logger.info('正在下載...')
          })
          autoUpdater.on('update-downloaded', (ev, releaseNotes, releaseName) => {
            logger.info('下載完成,更新開始')
            // Wait 5 seconds, then quit and install
            // In your application, you don't need to wait 5 seconds.
            // You could call autoUpdater.quitAndInstall(); immediately
            const options = {
              type'info',
              buttons: ['確定''取消'],
              title'應用更新',
              message: process.platform === 'win32' ? releaseNotes : releaseName,
              detail'發(fā)現(xiàn)有新版本,是否更新?'
            }
            dialog.showMessageBox(options).then(returnVal => {
              if (returnVal.response === 0) {
                logger.info('開始更新')
                setTimeout(() => {
                  autoUpdater.quitAndInstall()
                }, 5000);
              } else {
                logger.info('取消更新')
                return
              }
            })
          });
          ……

          開頭需要導入 autoUpdaterdialog 等方法

          import {
            autoUpdater
          from 'electron-updater'
          import {
            app,
            protocol,
            BrowserWindow,
            dialog
          from 'electron'

          最后需要加入更新檢測,什么時候加入檢測,看業(yè)務的需求,飛鴻在應用啟動的時候加入檢測。

          app.on('ready'async () => {
            createWindow()
            autoUpdater.checkForUpdates()
          })

          在這里飛鴻將更新提示使用electron提供的dialog寫的,其實功能和checkForUpdatesAndNotify()一樣。

          (四) 應用打包

          打包生成兩個不同版本號的應用進行檢測更新。

          執(zhí)行命令:

          npm run electron:build

          那它做了什么呢?

          1. 先用webpack打包渲染進程,打包出來的產(chǎn)物放在dist_electron,這個地址可以在配置中的outputDir中修改;
          2. 打包生成chunk-vendors.xxx.js、app.xxx.js和app.xxx.css放在其中的bundled\assets中;
          3. 渲染進程構建完成后,緊跟著構建主進程,捆綁后臺文件,還是打包進dist_electron/bundled下,生成background.js;
          4. 最后用electron-builder構建app,將web應用程序代碼構建成electron提供的桌面程序;
          5. 生成配置文件builder-effective-config.yaml;
          6. 最后用nsis構建應用。

          electron-builder的配置:

          electronBuilder配置

          builder-effective-config.yaml 就是 electron-builder 的配置項文件。

          配置項文件

          0.1.0版本打包成功:

          0.1.0版本打包成功

          0.1.0版本打包成功2

          雙擊打開應用

          雙擊打開應用

          雙擊打開應用2

          雙擊打開應用3

          點擊完成,自動運行應用

          點擊完成

          又能看到應用界面了

          到應用界面

          桌面自動生成快捷方式

          快捷方式

          Windows開始菜單也會出現(xiàn)應用

          Windows開始菜單

          (五) 測試更新

          接下來就是打包一個高版本的應用來測試更新是否生效。

          當前版本是0.1.0,我們來打包一個0.2.0的吧。

          修改一下package.json中的version,最后重新打包。

          打包0.2.0:

          打包0.2.0

          dist_electron目錄下就會出現(xiàn)兩個安裝包

          兩個安裝包

          應用是通過打包配置publish中的url提供的地址請求,檢測更新。

          根據(jù)electron-builder的配置:

          配置

          需要啟動一個端口為7777的靜態(tài)文件服務器。

          python -m SimpleHTTPServer 7777

          重啟0.1.0,打開就檢測到有新版本:

          檢測到有新版本

          點擊取消,應用不更新,用戶可以進行這個版本的繼續(xù)操作。

          查看日志

          查看日志

          重啟0.1.0應用,再次出現(xiàn)應用提示界面,點擊確定,應用消失,緊接著回到應用安裝界面,當然可以選擇靜默安裝。

          回到應用安裝界面

          然后下一步安裝,最后啟動應用,就更新到了0.2.0。

          0.2.0

          再打開日志:

          再打開日志

          其中靜態(tài)服務器是用 python 起的,大家可以采用其他方式。

          應用先拿取 latest.yml 文件,比較其中的哈希碼。

          如果和本地不同,再去拉取最新的安裝包進行安裝。

          應用和功能、桌面快捷方式、Windows開始菜單的應用從0.1.0都變成了0.2.0。

          0.1.0都變成了0.2.0

          最后,希望大家一定要點贊三連。

          可以閱讀我的其他文章,見blog地址

          一個學習編程技術的公眾號。每周推送高質量的優(yōu)秀博文、開源項目、實用工具、面試技巧、編程學習資源等等。目標是做到個人技術與公眾號一起成長。歡迎大家關注,一起進步,走向全棧大佬的修煉之路

          瀏覽 128
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  九哥操屄网| 俄美女与黑人一级A片 | 最新三级在线 | 欧美一级操逼网 | 色婷婷91视频 |