Electron

本文详细介绍了在Electron中主进程与渲染进程的通信方式,包括通过IPC和桥梁contextBridge实现数据交互。同时,强调了启用nodeIntegration和禁用contextIsolation的安全风险,并提供了通过预加载桥梁文件contextBridge确保渲染进程安全访问主进程API的方法。在实际应用中,应当注重进程间的隔离和安全设置,以防止潜在的安全问题。
摘要由CSDN通过智能技术生成

在Electron里面有两个进程分别是主进程与渲染进程主进程可以操作作操作系统,数据库的操作,运行node.js当渲染进程想要电脑系统的信息的时候,通过IPC通信给主进程,通过主进程获取电脑系统的数据,再返回给渲染进程

IPC通信

通信方法1

但是这样不安全,因为主进程与渲染进程没了隔离,在渲染进程这里就直接操作主进程了

 webPreferences: { //让渲染进程直接能够操作node
       nodeIntegration: true, //true就能在渲染进程直接操作node
       contextIsolation: false}//确定渲染进程与主进程是否是隔离的,默认是true,是为了安全考虑,这要就可以在浏览器阶段写一个界面,注入到桌面了,这样太不安全了}

方法2:通过桥梁contextBridge

思路:创建一个preload的文件夹,这里面有个index.js

代码:

const { 
  contextBridge, //上下文的桥
  ipcRenderer
} = require('electron')
// console.log(window)//可以访问window,相当于访问浏览器
// console.log(process)//相当于访问主进程
// window.process = process
const sendSync = () => {
  ipcRenderer.send('sync-send-event', 'from renderer message 1')
}
const sendAsync = async () => {
  const result = await ipcRenderer.invoke('my-invokable-ipc')
  return result
}
const recieveSyncMsg = () => {
  return new Promise((resolve) => { //接收主进程收到信息后,又sent了一个事件,在这里通过promise进行监听
    ipcRenderer.on('sync-receive-event', (event, msg) => {
      console.log(msg)
       resolve(msg)
    })
  })
}
//这里是通过回调的方式,渲染进程来调用
// const recieveSyncMsg=(cb)=>{  
//   ipcRenderer.on('sync-receive-event',(event,msg)=>{
//     //console.log(msg,2);
//     cb(msg)
//   })
// }
contextBridge.exposeInMainWorld('myAPI', { //相当于把myAPI挂载在window 
  versions: process.versions,
  sendSync,
  sendAsync,
  recieveSyncMsg
})

在这个桥里面可以写node,调用主进程里面的Api,在这里可以访问window,把里面的方法,属性都放到window里面,这样在渲染进程就可以通过window里面的方法属性来使用了

在main.js主进程里面

这是主进程里面用到的方法,单独放到一个文件夹里面

const { ipcMain } = require('electron')

// 同步事件监听
ipcMain.on('sync-send-event', (event, msg) => {
  console.log(msg)
  // event.reply('sync-receive-event', '我已经收到:' + msg)
  event.sender.send('sync-receive-event', '我已经收到:' + 'wwwww')
})


function somePromise() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('message from main process.')
    }, 3000)
  })
}

// 异步事件监听
ipcMain.handle('my-invokable-ipc', async (event, ...args) => {
  const result = await somePromise()
  return result
})

main.js

require('./controller/ipcMessage')
const WinState = require('electron-win-state').default //为了记录窗口的位置

// 载入主进程的两个重要的模块
// app: 应用模块
// BrowserWindow: 浏览器窗口的模块
const { app, BrowserWindow } = require('electron')
const path = require('path')


// 应用就绪,可以转载窗口了
const createWindow = () => {
  const winState = new WinState({  //这个插件为了记录窗口位置,下次打开还那样
    defaultWidth: 1400,
    defaultHeight: 600,
    dev: true,
  })

  // 实例化窗口对象, win 是渲染进程对象
  const win = new BrowserWindow({
    ...winState.winOptions,
    minHeight: 300,//最小高度
    minWidth: 400,
    show: false, //优雅打开,不出现白屏
    resizable: true,//允许拖拽
    movable: true, //false的时候锁死窗口
    // frame: false,//无边框窗口
    // titleBarStyle: 'hidden',//显示红绿灯
    backgroundColor: 'aliceblue',
    webPreferences: { //让渲染进程直接能够操作node
      // nodeIntegration: true, //true就能在渲染进程直接操作node
      // contextIsolation: false //确定渲染进程与主进程是否是隔离的,默认是true,是为了安全考虑,这要就可以在浏览器阶段写一个界面,注入到桌面了,这样太不安全了
      preload: path.resolve(__dirname, './preload-js/index.js')
      //在渲染进程还没有加载完,主进程预解析这个桥文件,这个桥即可以访问主进程也可以访问渲染进程
    }
  })

  winState.manage(win) //记录窗口位置

  // 给窗口转载页面
  win.loadFile('./renderer/index.html')
  // win.loadURL('https://www.baidu.com')
  // win.loadURL('http://jx.1000phone.net')
  // win.loadURL('https://www.github.com')

  // 打开调试工具
  win.webContents.openDevTools()
  
  // const win2 = new BrowserWindow({  //创建两个渲染进程
  //   // parent: win,  //win的子窗口
  //   width: 800,
  //   height: 600,
  //   // modal: true,//在父元素下不允许拖拽
  //   // x: 200,
  //   // y: 200
  // })
  // win2.loadURL('http://jx.1000phone.net')

  // win2.on('close', () => {
  //   win.maximize()  //最大化窗口
  // })
   //优雅的显示窗口,避免出现白屏
  win.once('ready-to-show', () => {
    win.show()
  })
  
}

app.on('window-all-closed', () => {
  console.log('window-all-closed')

  // 对于 MACOS 系统,关闭窗口时,不会直接推出应用
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

// app.on('will-finish-launching', () => {  //主进程完成加载
//   console.log('will-finish-launching')
// })

// app.on('ready', () => {//app准备就绪
//   console.log('ready')
// })

// app.on('will-quit', () => { //app将要关闭
//   console.log('will-quit')
// })

// app.on('before-quit', () => { //app将要关闭之前
//   console.log('before-quit')
// })

// app.on('quit', () => { //app已经关闭
//   console.log('quit')
// })

// app.on('browser-window-blur', (e) => {
//   console.log('App unfocused')
// }) 这里的失去焦点就是AUT+Tab 把屏幕切换出去就是失焦,切换回来就是聚焦

// app.on('browser-window-focus', (e) => {
//   console.log('App focus')
// })

// app.on('browser-window-blur', (e) => {
//   setTimeout(() => { //当失焦3秒后就会把窗口给关掉,执行app.quit()
//     app.quit()
//   }, 3000)
// })

app.whenReady().then(() => {
  createWindow()
  // 在 MacOS 下,当全部窗口关闭,点击 dock 图标,窗口再次打开。
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })

  // console.log(app.isReady())
  // console.log(app.getPath('desktop')) //获取路径
  // console.log(app.getPath('music'))
  // console.log(app.getPath('temp'))
  // console.log(app.getPath('userData'))

  // console.log(BrowserWindow.getAllWindows().length)
})


// console.log(process)

process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' //不让出现安全策略的警告,不让渲染进程引入外部文件

在渲染进程里面

// const path = require('path')
// console.log(path)

// const fs = require('fs')
// fs.writeFileSync('/Users/felixlu/desktop/temp.txt', 'hello electron') //当在主进程打开权限,在渲染进程就可以直接在桌面写入一个文件了

const versions = window.myAPI.versions //通过桥拿来的

const app = Vue.createApp({
  template: `
    <p>Chrome version: {{chromeVersion}}</p>
    <p>Node version: {{NodeVersion}}</p>
    <p>Electron version: {{electronVersion}}</p>
    <div>
      <button @click="sendSyncMsg">发送同步消息</button>
    </div>
    <div>
      <button @click="sendAsyncMsg">发送异步请求</button>
    </div>
  `,

  data() {
    return {
      // process能访问,要得益于 nodeIntegration: true, contextIsolation: false
      chromeVersion: versions.chrome,
      NodeVersion: versions.node,
      electronVersion: versions.electron
    }
  },

  methods: {
    sendSyncMsg() {
      // 从渲染进程里发送同步数据给主进程
      myAPI.sendSync('from renderer message 1')
    },

    // 如果有桥接的方法,建议IPC通信,全部应用异步。
    async sendAsyncMsg() {
      const result = await myAPI.sendAsync()
      console.log(result)
    }
  },

  async mounted() {
    //传递 ipcRender 对象有问题,不能这样用。
    // await this.$nextTick();
    // console.log(myAPI.ipcRenderer)
    // myAPI.on('sync-receive-event', (event, msg) => {
    //   console.log(0)
    // })

    let result = await myAPI.recieveSyncMsg()
    console.log(result)
    //下面是通过回调的方法调用桥里面的方法
    // myAPI.recieveSyncMsg((msg)=>{
    //   console.log(msg,1);
   // })
  },
})

app.mount('#root')

插件nodemon

打开方式

 --exec 是打开该文件, --watch ./ --ext 是监听有.html,.js  .css的文件名,当这些文件改动保存的时候就会自动执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值