使用electron進行原生應用的打包(2)---主進程與渲染進程之間的通信


上一篇講了使用electron進行打包的配置相關文件,這篇主要講electron中很重要的通信方式.

 

首先解釋一個概念: electron打包的應用包含兩個部分

  • electron的環境(node),也就是主進程.
  • web渲染環境,副進程.

這兩個環境之間是相互隔離的,無法直接進行數據通信,所以有了這篇文章.

 

三個角色:

  • ipcRender
  • ipcMain
  • webContents

ipcRenderer用於渲染進程

  • ipcRenderer.on(channel, listener) --> channel為事件頻道,字符串.listener為觸發回調函數,用於響應webContent.send()
  • ipcRenderer.send(channel, data) --> 概念同上,用於向ipcMain發送異步信息.
  • ipcRenderer.sendSync(channel, data) --> 用於向ipcMain發送同步信息,此時會阻塞掉渲染進程,除非必須,謹慎使用.

ipcMain用於主進程,響應從渲染進程中發送的消息

  • ipcMain.on(channel,listener) --> 響應從ipcRender中相同channel.
  • ipcMain.once(channel,listener) --> 同上,但是只觸發一次,觸發后自動取消綁定
  • ipcMain.removeListener(channel,listener) --> 移除時事件,listener一定要為函數引用,不能是匿名函數或箭頭函數,否則不能解綁
  • ipcMain.removeAllListener([channel]) --> 移除channel上的所有事件
  • listener (event, data)
    • event.sender.send(channel, data) --> 這是唯一ipcMain可以異步返回消息的方法,通過event參數向渲染進程發送消息.(與ipcRenderer.send對應)
    • event.returnValue(channel,data) --> ipcMain同步返回消息(與ipcRenderer.sendSync對應)
    • data是消息發送者攜帶的data

最后一個是webContent

不知道細心的讀者有沒有發現,ipcMain本身是無法直接發送事件的,只能通過響應事件回調的event來發送,那如果我們想先讓主進程發送消息呢?那就才用這個辦法.這個webcontent是在BrowserWIndow實例中的方法

  • webContent.send(channel,data) --> 主進程向渲染進程發送消息.

注意,這些方法全部需要在主進程已經創建了BrowserWindow之后才有效,下面來一個例子:

在關閉客戶端之前需要判斷已修改的文件已保存.下圖為流程圖:

 

首先是渲染端代碼: 

const electron = require('electron') // 引入electron
const ipcRenderer = electron.ipcRenderer; // 獲取ipcRender渲染進程
let to_close = false // 定義允許關閉變量

ipcRenderer.on('save_complete', () => to_close = true) // 如果保存完成則設置為可以關閉

ipcRenderer.on('not_save', () => to_close = false) // 否則設置為不可關閉

// 全局的點擊關閉按鈕后調用
window.onbeforeunload = (e) => {
  !to_close && (e.returnValue = false) // 如果不允許關閉則return false阻止關閉
  ipcRenderer.send('need_close') // 發送需要進行關閉信息
}

其次是主進程代碼

const electron = require('electron')
const app = electron.app
const dialog = electron.dialog // 創建對話框
const BrowserWindow = electron.BrowserWindow
const ipcMain = electron.ipcMain

let need_close = false // 是否需要關閉(如果只是點擊保存則不需要關閉)

ipcMain.on('need_close', () => need_close = true) // 如果需要,則設為true

// 當點擊保存時
mainWindow.webContents.session.on('will-download', (event, downloadItem,webContents) => {
  // 阻止默認保存行為(點擊a標簽)
  event.returnValue = false;
  // 顯示保存對話框,默認擴展為.txt
  const fileName = dialog.showSaveDialog({
    defaultPath: '新的作品',
    filters: [
      { name: 'txt', extensions: ['txt'] }],
  });
  // 如果沒有正常保存
  if (typeof fileName == 'undefined') {
    // 不能退出
    need_close = false
    // 向渲染端發送沒有保存消息
    webContents.send('not_save')
    // 取消下載
    return downloadItem.cancel();
  }
  // 正常下載
  downloadItem.setSavePath(fileName);
  // 當下載項結束時
  downloadItem.on('done', (event, state) => {
    // 有三種state completed, cancelled, interrupted,此處只監聽完成時
    if (state === 'completed') {
      // 發送完成保存
      webContents.send('save_complete')
      // 如果需要關閉的話則退出app
      need_close && app.quit();      
    }
  });
})

這是很簡單的展示了如何在渲染端以及服務端進行消息傳遞.可以基本滿足通信需求.

 


免責聲明!

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



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