• 使用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();      
        }
      });
    })

    这是很简单的展示了如何在渲染端以及服务端进行消息传递.可以基本满足通信需求.

  • 相关阅读:
    【云图】如何制作附近实体店的地图?-微信微博支付宝
    【云图】如何设置支付宝里的家乐福全国连锁店地图?
    【云图】如何设置微信里的全国实体店地图?
    【云图】如何制作官网上的实体店分布图?
    MYSQL 锁机制 分析
    数据结构-线性表-栈-递归
    mysql 异步执行 query //@todo
    C语言操作mysql
    linux gcc头文件搜索路径
    LINUX下动态库及版本号控制
  • 原文地址:https://www.cnblogs.com/BigJ/p/electron2.html
Copyright © 2020-2023  润新知