electron打包更新與整合sqlite小總結

coderlfy發表於2019-04-03

本文主要講以下幾點

  • 簡單介紹electron
  • electron的程式與渲染層通訊
  • electron的打包配置
  • electron的自動更新
  • electron如何整合sqlite3
  • electron的資料分享
  • electron在內網開發的一點點建議
  • electron主程式的生命週期

快速開始一個electron與簡介

electron是什麼

開啟官網第一眼就是使用 JavaScript, HTML 和 CSS 構建跨平臺的桌面應用,更加通俗一點就是一個桌面瀏覽器,實際上這樣理解也是對的。因為electron就是通過javaScript使chromium來展示web頁面

我為啥用它

  • 前端可用製作跨平臺應用
  • 生態圈好
  • 由github開發維護
  • electron(70+k)比nw.js (35+k)Star多兩倍
  • electron產品我使用過表現優秀
    • Vscode
    • Atom
    • gitHub桌面端
    • ...

如何快速上手electron

我認為以下是快速開始的最好辦法

  • 一定要多讀官方文件,可以減少大部分時間
  • 官方提供的快速開始模板
  • 官方提供快速熟悉的API的模板

直接使用electron官方提供的例子

// 看這個的原始碼,很簡單可以快速上手
# 克隆這倉庫
$ git clone https://github.com/electron/electron-quick-start
# 進入倉庫
$ cd electron-quick-start
# 安裝依賴庫
$ npm install
# 執行應用
$ npm start
複製程式碼

如果想了解這個electron的API可以克隆這個庫並執行

git clone https://github.com/electron/electron-api-demos

cd electron-api-demos

npm install

npm start

複製程式碼

如何除錯electron

渲染程式除錯(web頁面) 渲染器程式這chrome瀏覽器一樣,BrowserWindow建立視窗後新增視窗例項.webContents.open

主程式Electron除錯 使用vsCode中的debug,注意除錯路徑,如果需要增加變數環境依照配置增加即可

electron中主程式的生命週期以及常用事件和渲染層

主要聊electron中主程式的生命週期,渲染器的部分生命週期,一般只介紹通用都存在的,如果只有某個系統有的api就不寫在這裡了,大家可以自行查閱

主程式中的生命週期

生命週期圖

生命週期圖

正常流程會觸發的生命週期

  • will-finish-launching:當應用程式完成基礎的啟動的時候被觸發
  • web-contents-created:webContents被建立完成
  • browser-window-created:BrowserWindow被建立完成
  • ready:當 Electron 完成初始化時被觸發
  • remote-require: 引入remote時被呼叫
  • before-quit: 在應用程式開始關閉視窗之前觸發
  • will-quit:當所有視窗都已關閉並且應用程式將退出時發出
  • quit: 在應用程式退出時發出
  • window-all-closed:當所有的視窗都被關閉時觸發

這裡要注意如果是程式殺死退出的所有都不觸發,如果是cmd+Q或者開發者使用app.quit()退出的window-all-closed是不會被觸發的,基本操作一般在ready中處理

程式相關

  • gpu-process-crashed: 當 gpu 程式崩潰或被殺時觸發。

其他

  • browser-window-focus: 在 browserWindow 獲得焦點時發出
  • browser-window-blur:在 browserWindow 失去焦點時發出

渲染程式--(瀏覽器)-BrowserWindow

  • ready-to-show:當頁面已經渲染完成(但是還沒有顯示) 並且視窗可以被顯示時觸發
  • move: 視窗移動
  • resize: 調整視窗大小後觸發
  • close: 在視窗要關閉的時候觸發。 它在DOM 的beforeunload 和 unload 事件之前觸發.
  • blur: 失去焦點,同app
  • focus: 獲得焦點,同app
  • maximize:視窗最大化時觸發
  • unmaximize: 當視窗最大化退出狀態觸發
  • minimize: 視窗最小化時觸發
  • restore: 當視窗從最小化還原觸發
  • ...

渲染程式 BrowserWindow例項中的webContents

  • did-finish-load:導航完成時觸發,即選項卡的旋轉器將停止旋轉,並指派onload事件後
  • did-finish-load: 這個事件類似於 did-finish-load, 不過是在載入失敗或取消後觸發
  • dom-ready: 一個框架中的文字載入完成後觸發該事件
  • crashed: 當渲染程式崩潰或被結束時觸發
  • unresponsive: 頁面未響應觸發
  • devtools-opened: 當開發者工具被開啟時,觸發該事件。
  • devtools-closed: 當開發者工具被關閉時,觸發該事件。
  • ...

electron的程式與渲染層通訊

  • 主程式和渲染器程式
  • 主程式和渲染器程式的區別

electron主程式與渲染程式

chrome瀏覽器由於每個標籤頁都是一個程式,而electron所執行的程式稱為主程式並且只有一個,主程式要操控瀏覽器的每個標籤的網頁稱為渲染器程式,如何通訊呢?

主程式和渲染器程式

程式

程式是正在執行的程式的例項(狹義定義)

electron中的主程式

Electron 執行 package.json 的 main 指令碼的程式被稱為主程式。 在主程式中執行的指令碼通過建立web頁面來展示使用者介面。 一個 Electron 應用總是有且只有一個主程式。

electron中的渲染器程式

由於 Electron 使用了 Chromium 來展示 web 頁面,所以 Chromium 的多程式架構也被使用到。 每個 Electron 中的 web 頁面執行在它自己的渲染程式中。

渲染器程式與主程式之間的區別

  • 主程式是從開始執行一直存在,渲染器程式通過BrowserWindow來建立例項,例項銷燬則渲染程式銷燬

主程式使用 BrowserWindow 例項建立頁面。 每個 BrowserWindow 例項都在自己的渲染程式裡執行頁面。 當一個 BrowserWindow 例項被銷燬後,相應的渲染程式也會被終止。

  • 主程式管理所有渲染程式,渲染程式是獨立且自我管理(web頁面)

主程式管理所有的web頁面和它們對應的渲染程式。 每個渲染程式都是獨立的,它只關心它所執行的 web 頁面。

  • 主程式中可以呼叫底層所有的GUI的API,渲染程式則因為安全問題不能隨意呼叫。如果要呼叫則需要通訊讓主程式來呼叫。

在頁面中呼叫與 GUI 相關的原生 API 是不被允許的,因為在 web 頁面裡操作原生的 GUI 資源是非常危險的,而且容易造成資源洩露。 如果你想在 web 頁面裡使用 GUI 操作,其對應的渲染程式必須與主程式進行通訊,請求主程式進行相關的 GUI 操作。

主程式與渲染器程式如何通訊

主程式與渲染器程式通過ipcMain與ipcRenderer來通訊

ipcMain與ipcRenderer通訊

主程式向渲染器程式通訊

這個方式主要是主程式中使用ipcMain使用on監聽,監聽獲取後通過event.sender(相當於webContent)send來傳送一個事件,渲染程式中使用ipcRenderer通過on來接收,如果是同步可以通過evnet.returnValue來返回主程式的結果程式碼如下:

渲染器程式向主程式通訊

渲染器程式主要通過ipcRenderer這個模組中的send來傳送,該方法中可以同步與非同步傳送訊息,接收訊息使用on來接收

通訊簡化

electron的打包

常用方式:

  1. electron-builder(本人主要用這個)
  2. electron-pakager
  3. electron-forge

electron-builder

electron-builder 是一個完整的解決方案,並且自帶自動更新策略

electron-builder打包在package的script配置好

打包常用引數:

  "build": {
    "appId": "your.id", // appid
    "productName": "程式名稱", // 程式名稱
    "files": [    // 打包需要的不過濾的檔案
      "build/**/*",
      "main.js",
      "node_modules/**/*"
    ],
    "directories": { 
      "output": "./dist-out", // 打包輸出的目錄
      "app": "./",  // package所在路徑
      "buildResources": "assets"   
    },
    "nsis": {
      "oneClick": false,  // 是否需要點選安裝,自動更新需要關掉
      "allowToChangeInstallationDirectory": true, //是否能夠選擇安裝路徑
      "perMachine": true // 是否需要輔助安裝頁面
    },
    "win": {
      "target": [
        {
          "target": "nsis",  // 輸出目錄的方式
          "arch": [ // 輸出的配置ia32或者x64/x86
            "x64"
          ]
        }
      ],
      "publish": [ // 自動更新的配置
        {
          "provider": "generic", // 自己配置更新的伺服器要選generic
          "url": "http://127.0.0.1:8080/updata/" //更新配置的路徑
        }
      ]
    }
  }
複製程式碼

在package.json中增加的快速啟動項

"scripts": {
  "pack": "electron-builder --dir",
  "dist": "electron-builder"
}
複製程式碼

啟動打包

通常需要注意的點

  • 注意路徑,由於打包後的路徑會有問題最好使用path.join()來處理一下。
  • 碰到 The process cannot access the file because it is being used by another process.這個問題多數是vscode佔用了關掉重開就好了

如果配合create-react-app建立出來的應用

  • 可以先讓react的程式進行打包成靜態檔案,在把靜態檔案打包到electron應用中
  • 如果electron-builder總是報類似electron.js找不到的警告,並且在上面提示讓你去看網頁中的方法,可以通過electron-builder提示的網址來修改,這實際是一個教程需要科學上網。

electron-builder的自動更新

如果在API中看到autoUpdater這個API,希望在看到這個API之前先參考官方的自動更新這樣會讓你少點坑,因為electron-builder的自動更新機制和electron提供有些不一樣,electron-builder官網也有說明,否則就會一直報error了

這個更新實際上是對比例兩個版本之間的版本號,如果當前版本小於,伺服器版本的話就會進行下載更新

更新機制

在資料裡有一篇專門講更新機制的,很好。這裡簡單總結。

更新步驟.png

autoUpader生命週期

  • error: 如果任意一個環節有問題就會走到這步
  • checking-for-update :當開始檢查更新的時候觸發。
  • update-available: 發現更新
  • update-not-available:當沒有可用更新的時候觸發.
  • update-downloaded: 在更新下載完成的時候觸發。
  • before-quit-for-update : 此事件是在使用者呼叫quitAndInstall()之後發出的。

更新要注意的點:

  • electron-builder中的autoUplader需要使用 electron-updater這個模組,非原生模組
  • package.json中的publish中的url與更新的地址要一致(注意埠),否則會報net::ERR_CONNECTION_REFUSED
  • 如果是未打包也想跑一邊autoUpdater的流程需要一個dev-app-update.yml的檔案放在與main.js同一層級的地方,類似win-ia32-unpacked/resource/app-update.yml這樣的檔案,直接複製改名就能使用
  • 如果更新完成後在package中配置了自動安裝的選項,在關閉應用就能直接安裝,如果想自己控制馬上安裝需要加autoUpdater.quitAndInstall()
  • 如果初次啟動應用在終端輸出了你想要的結果,在渲染選只輸出來了一部分,或者沒有輸出,如果不是報錯的話,不妨監聽一下該渲染程式的did-finish-load這個宣告週期,在這裡面做處理,根據場景可以使用once來監聽
  • 需要一個靜態網站伺服器在你需要的資料夾使用http-server -o,如果沒有就全域性安裝一個npm i http-server -g,在package中需要配置publish中的"provider": "generic"
  • 碰到spawn **/*.exe ENOENT這類的可能是你在開發環境執行了一個未安裝的應用,並且使用了autoUpdater.quitAndInstall()就會報錯,如果是安裝好了就不會報這個錯
//electron-quick-start 
//main.js 主程式中

// 可以沒有這個
const { autoUpdater } = require('electron-updater')

// ================= start 非必須 ===============
const log = require('electron-log');
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
// ================ end 非必須 ==================

// 封裝
function sendStatusToWindow(text) {
  log.info(text);
  mainWindow.webContents.send('message', text);
}

/**
 * 自動更新
 */
function checkUpdata() {
  autoUpdater.setFeedURL('http://127.0.0.1:8080/updata/')
  // autoUpdater.on('error', (error) => {
  //   sendStatusToWindow( `[error]:${error}`)
  // })
  autoUpdater.on('checking-for-update', () => {
    sendStatusToWindow('Checking for update...');
    // mainWindow.webContents.send('downlaod')

  })
  autoUpdater.on('update-available', (info) => {
    sendStatusToWindow('Update available.');
  })
  autoUpdater.on('update-not-available', (info) => {
    sendStatusToWindow('Update not available.');
  })
  autoUpdater.on('error', (err) => {
    sendStatusToWindow('Error in auto-updater. ' + err);
  })
  autoUpdater.on('download-progress', (progressObj) => {
    let log_message = "Download speed: " + progressObj.bytesPerSecond;
    log_message = log_message + ' - Downloaded ' + progressObj.percent + '%';
    log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
    sendStatusToWindow(log_message);
    mainWindow.webContents.send('downloadExe', progressObj.percent)
  })
  autoUpdater.on('update-downloaded', (info) => {
    mainWindow.webContents.send('downloaded')


    sendStatusToWindow('Update downloaded');
    // autoUpdater.quitAndInstall();
  });

複製程式碼

electron中新增sqlite3

需要的環境

如果是windows環境需要準備 vs2015 與python2.7的環境

  1. python2.7.x 網上下載安裝即可
  2. vs2015 以下方式可選其一
    1. 工具包 npm install --vs2015 -g windows-build-tools(推薦)
    2. 安裝visual studio 中安裝vs2015工具包(超久)

程式中可新增的本地資料庫,最多使用的兩款

  • sqlite3(關係型)
  • neDB(非關係型)

為自己的資料加上本地資料庫sqlite3

sqlite3【gitHub】 為程式新增sqlite3npm i sqlite3 或者yarn add sqlite3

如何使用?

// 官網例子
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(':memory:'); // 這裡是把資料存入記憶體
db.serialize(function() {
var db = new sqlite3.Database()
  db.run("CREATE TABLE lorem (info TEXT)");
  var stmt = db.prepare("INSERT INTO lorem VALUES (?)");
  for (var i = 0; i < 10; i++) {
      stmt.run("Ipsum " + i);
  }
  stmt.finalize();

  db.each("SELECT rowid AS id, info FROM lorem", function(err, row) {
      console.log(row.id + ": " + row.info);
  });
});

db.close();
複製程式碼

sqilte3在安裝的時候自動生成sqlite所需要的檔案包,這個二進位制檔案需要使用node-pre-gyp或者是node-gyp這也就是為什麼需要安裝環境的原因,在這一步鬼知道當時報了多少東西,尤其是還要把這玩意弄進內網。 比如說:

  • 開始執行的時候就報Error: Cannot find module 'E:\electronjs\electron-quick-start\node_modules\sqlite3\lib\binding\electron-v4.0-win32-x64\node_sqlite3.node'類似這樣的東西,實際上確實沒有這個東西,怎麼解決呢?
    • 使用node-gyp這個模組直接重新編譯一個版本正確的
node-gyp rebuild 
--target=4.0.4 --arch=x64
--target_platform=win32 --dist-url=https://atom.io/download/electron/
--module_name=node_sqlite3 --module_path=../lib/binding/electron-v4.0-win32-x64

// 使用到的模組解析
// target                => electron的版本號一定要一直
// target_platform       => 需要打包的平臺ia32/x64等
// dist-url              => 這個是需要下載相關內容的地址
// module_name           => 需要打包的模組名稱
// module_path           => 打包輸出的地方
複製程式碼

如果覺得麻煩可以試試npm i electron-rebuild -D然後在使用./node_modules/.bin/electron-rebuild重新編譯一遍,有時候可能是快取問題,把快取清除npm cache clear -f清除一下,還有就是npm i重新安裝一下,因為環境的問題會跳出各種問題,可以多多嘗試這些方法

was compiled against a different Node.js version using
NODE_MODULE_VERSION 64. This version of Node.js requires
NODE_MODULE_VERSION 69. Please try re-compiling or re-installing
複製程式碼

如讓你選擇node編譯版本的github【issues】====>也有可能是編譯問題,利用electron-rebuild 重新編譯一遍或者把sqlite3降級

需要注意的

  • 打包的時候如果報error MSB4019: 未找到匯入的專案Microsoft.WebApplication.targets重新安裝一下vs2015工具包,或者以前安裝的有問題重新安裝(我就碰到了)
  • 用node-gyp編譯sqlite3打包需要binding.gyp這個python檔案以及其他配置所以直接進入node_modules\sqlite3這個檔案執行 node-gyp的操作
  • 打包的時候要注意在渲染程式中使用sqlite3在打包的時候會出現打包問題,解決可以選在在主程式操作本地資料庫
  • 打包之後使用DB會出現一個問題,在當前目錄怎麼都生成不了DB,在網上查了要麼就通過手動授權為管理員開啟,要麼手動管理員開啟,這根本就不能行,後來參考electron-vue發現可以使用app.getPath('userData')這個方法進行獲取app可快取地址,然後使用path.join合併一下路徑就解決了無法生成DB檔案的問題,事實上indexDB,locaStore這個兩個的儲存檔案也在這個目錄下

其他模組

  • globalShortcut: 註冊全域性快捷鍵
  • Tray: 托盤
  • Menu:選單事件

內網開發需要注意

內網開發真的很煩。。 首先需要環境,然後就是需要下載的包,其次就是需要編譯後的各種檔案如sqlite3編譯後的檔案等如果在內網開發electron就需要把這些需要的包全都複製到對應位置

大部分需要配置的檔案都在C:\Users\xxxxxx代表你所在的資料夾, 部分下載快取檔案在C:\Users\xxx\AppData\Local目錄下的electron 和 electron-builderer裡

內網01.png

參考的學習資料

以下文章大部分閱讀過,覺得不錯推薦給大家

electron

electron構建相關

electron打包相關

electron更新

electron

electron編譯

electron tips

相關文章