electron環境下使用node-serialport模塊


一、按照慣例先說點廢話

  Electron: Electron是由Github開發,用HTML,CSS和JavaScript來構建跨平台桌面應用程序的一個開源庫。 Electron通過將Chromium和Node.js合並到同一個運行時環境中,並將其打包為Mac,Windows和Linux系統下的應用來實現這一目的。

  Node.js: 簡單的說 Node.js 就是運行在服務端的 JavaScript,是一個基於Chrome JavaScript 運行時建立的一個平台,Node.js是一個事件驅動I/O服務端JavaScript環境,基於Google的V8引擎,V8引擎執行Javascript的速度非常快,性能非常好。

  最近需要做一個客戶端程序,需要考慮UI,簡單說就是需要做的炫,Electron是一個比較好的選擇。由於這個程序需要連接串口的RFID讀寫器,所以故事就開始了。

  • 二、搭建環境
  • 安裝Node.js

    https://nodejs.org/en/ 官網下載安裝,安裝node.js會自動安裝npm。

    NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS代碼部署上的很多問題,常見的使用場景有以下幾種:

    • 允許用戶從NPM服務器下載別人編寫的第三方包到本地使用。
    • 允許用戶從NPM服務器下載並安裝別人編寫的命令行程序到本地使用。
    • 允許用戶將自己編寫的包或命令行程序上傳到NPM服務器供別人使用。

    由於新版的nodejs已經集成了npm,所以之前npm也一並安裝好了。這時候我們檢查一下node.js和npm是否安裝成功。

    

    node.js 和 npm 有版本對應關系,雖然說捆綁安裝一般不會有問題,但最好還是確認一下,避免掉坑。可以到官網查看:https://nodejs.org/zh-cn/download/releases/ 

    

  • 安裝electron

    有了npm安裝 electron就簡單了。直接全局安裝:npm install -g electron。更多詳情參照官網:https://electronjs.org/docs/tutorial/installation

    electron 提供一個初始的項目,可以去github克隆,地址:https://github.com/electron/electron-quick-start。安裝完成后同樣檢查一下是否安裝成功。

    

  • 使用node-serialport

    首先從 https://github.com/electron/electron-quick-start 克隆一個 electron-quick-start。然后cd到這個目錄。運行electron . 查看是否能正常運行,順便也可以檢驗一下我們的環境搭建是否成功。

    

    添加 node-serialport 讀寫串口的代碼

    main.js源碼:

// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow() {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') app.quit()
})

app.on('activate', function () {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) createWindow()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
var SerialPort = require('serialport')
var sp = new SerialPort('COM2', { baudRate: 9600 })

function writeport(senddata){
  sp.write(senddata, function (err) {
        if (err) {
            return console.log('Error on write: ', err.message);
        }
        console.log('send: ' + senddata);
    });
}

function openport(event){
  sp.on('open', function () {
    console.log("open port success.");
  });

  // open errors will be emitted as an error event
  sp.on('error', function (err) {
    console.log('Error: ', err.message);
  })

  sp.on('data', function (data) {
    //hex
    console.log('recv: ' + data.toString('hex'));
    //ascii
    //console.log('recv: ' + data.toString('ascii'));
    event.sender.send('asynchronous-reply', data.toString('hex'))
  });
}

function closeport(){
  sp.on('close', function () {
    console.log("open port success.");
  });
}

const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, cmd) => { //主進程接收渲染進程的請求事件
  console.log("read_serialport")
  switch (cmd) {
    case "read_serialport":
      openport(event)
      break;
  }
});

renderer.js源碼:

// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// No Node.js APIs are available in this process because
// `nodeIntegration` is turned off. Use `preload.js` to
// selectively enable features needed in the rendering
// process.

// 獲取按鈕和容器的DOM節點
var content = document.getElementById('content');
var button = document.getElementById('btn');

const ipcRenderer = require('electron').ipcRenderer;

ipcRenderer.on('asynchronous-reply', (event, arg) => {
    content.innerText = arg;
})

button.addEventListener('click', (e) => {
    ipcRenderer.send('asynchronous-message', 'read_serialport')
});

index.html源碼:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<button type="button" id="btn">讀取串口</button>
<div>串口數據:</div>
<div id="content"></div>

<script src="./renderer.js"></script>
</body>
</html>

  接下來的任務就是這么讓這個代碼在eletron環境中跑起來。先到serialport官網看看serialport文檔 https://serialport.io/docs/guide-about其中有在electron中使用的說明:

  

   如果需要serialport作為Electron項目的依賴項,則必須針對項目使用的Electron版本對其進行編譯。這就是爬坑的開始......  

  (1) 命令行窗口 cd 到我們的electron-quick-start項目目錄。執行npm install 安裝依賴包一切順利。

  (2) 執行 npm install serialport 下載 serialport 包。不過下載下來的是C++源碼,需要我們編譯。不詳的預感越來越強烈。既然需要編譯源碼。那么就需要安裝node-gyp包。

  npm 為了方便干脆就直接源碼分發,用戶裝的時候再現場編譯。 因為node程序中需要調用一些其他語言編寫的 工具 甚至是dll,需要先編譯一下,否則就會有跨平台的問題,例如在windows上運行的軟件copy到mac上就不能用了,但是如果源碼支持,編譯一下,在mac上還是可以用的。node-gyp在較新的Node版本中都是自帶的。

  關於更多 node-gyp的信息請移步https://github.com/nodejs/node-gyp/,一般會自帶,node-gyp -v 看一下,如果沒有就安裝以下,直接 npm install -g node-gyp 一般不會出什么狀況。

  node-gyp 需要依賴其他環境,具體參閱 https://github.com/nodejs/node-gyp/中的 Installation

  

   接下來安裝 electron-rebuild 。其作用就是根據您的Electron項目使用的Node.js版本重建本機Node.js模塊。這樣,您就可以在Electron應用程序中使用本機Node.js模塊,而無需與系統版本的Node.js完全匹配。參見官網: https://github.com/electron/electron-rebuild 。

  npm install --save-dev electron-rebuild 這里說明一下 --save-dev -save 的意思是將模塊安裝到項目目錄下,-save-dev 的意思是將模塊安裝到項目目錄下,並在package文件的devDependencies節點寫入依賴

  到這里,准備工作就好了,進入關鍵的編譯。執行 :  .\node_modules\.bin\electron-rebuild.cmd 開始編譯,如果一切順利編譯成功,任務完成。但是我在編譯的時候發現報錯:

  

   這個地方報錯說沒有重載接收2個參數。用Visual studio 打開代碼 electron-quick-start項目目錄下的 node_modules\@serialport\bindings\build\bindings.vcxproj。編譯發現確實少了參數。

  

  然而定義是這個樣子的:

  

   從github下載了node-seriaport最新代碼與npm install 下載的進行對比,果然發現了問題所在。

  

  這時候我又在node環境測試了一遍,發現node-serialport模塊是能正常工作的。說明我npm install 下載的模塊版本有問題。打開packge.json看了一下,發現里面依賴的版本的7.1.5。

  而node環境里面可以正常工作的版本是 8.0.6  (可以通過 npm list  [module name] 查看模塊版本號)。然后我把修改了pack.json里面依賴的serialport版本,刪除packge-lock.json和node_modules。(執行npm install 重新生成packge-lock.json ,如果沒有生成 修改一下配置 npm config set package-lock true) 重新執行前面的編譯過程。順利編譯成功:

    

  • 最后

   折騰的過程很痛苦!  記錄一下避免自己再次坑,如果能幫到其他人我很榮幸~ !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM