electron webview通信的桥梁

preload.js (https://www.electronjs.org/zh/docs/latest/api/webview-tag#preload)

//!! 重要文件 误删除
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { contextBridge, ipcRenderer } = require('electron') // electron 19.0.0版本
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ypTalkBridge } = require('@yp_cloud/common')
// 桥接
contextBridge.exposeInMainWorld(
  '_ypTalkApi',
  {
    ...ypTalkBridge(ipcRenderer),
    isMainFrame: process.isMainFrame
  }
)

 

ypTalkBridge.js
/*
 * @Date: 2022-07-12 15:57:39
 * @Description: 此文件不需要改动什么东西
 */
import { apiData } from '../config'

// apiData = [ // 选择人员 {name: 'choose', 'channel': 'choose'}] 
interface IpcRequestListenerParams { onSuccess: (v?: any) => void onFail: (v?: any) => void } let ipcRenderer = null let msgKey = 0 // 消息标识 let requestListenerMap: Map<string, IpcRequestListenerParams> = new Map() // 事件订阅 let requestPromiseMap: Map<number, Function> = new Map() // 回调中心 /** * 添加ipc请求回报 * @enerKey 当前通信的标识key * @channelName 回报时的 标识 channel * @params 回调时的参数 */ const addIpcRequestListener = (enerKey: string, channelName: string, params: IpcRequestListenerParams) => { if (!requestListenerMap.has(enerKey)) { // 回复信息时 ipcRenderer.on(channelName, (_event: any, params) => { const {msgno, data, eventName} = params // 找出事件中心是否存在 if (msgno && requestPromiseMap.has(msgno)) { const resolve = requestPromiseMap.get(msgno) // 如果eventName存在,代表是params方法参数的回调 const eventListener = requestListenerMap.get(enerKey) if (eventName) { // 触发回调 eventListener?.[eventName]?.(data) resolve(data) } else { resolve(data) } // 删除回调 requestPromiseMap.delete(msgno) } }) // 添加到事件中心 requestListenerMap.set(enerKey, params) } } /** * 发送请求 * @ipcKey 通信的key * @params 参数 */ const ipcRequest = (ipcKey: string, params?: any) => { return new Promise(resolve => { // 防止sdk,事件名和渲染进程重复,这里对传递进来的事件名重新定义 const channel = 'talk-' + ipcKey // 明确告知渲染层回信时的key,通过channel发送消息 const eventName = channel + '-reply' // 添加唯一辨识 const msgno = ++msgKey // 添加回调 requestPromiseMap.set(msgno, resolve) // 添加事件 addIpcRequestListener(channel, eventName, { onSuccess: params?.onSuccess, onFail: params?.onFail }) // 过滤数据,发送 Functions, Promises, Symbols, WeakMaps, 或 WeakSets 将抛出异常 const data = params ? JSON.parse(JSON.stringify(params)) : null // 发送消息给渲染进程webview ipcRenderer.sendToHost(channel, { eventName, msgno, data }) }) } // sdk暴露给h5的方法 const ypTalkBridge = (copyIpcRenderer) => { const api = {} ipcRenderer = copyIpcRenderer || null apiData.forEach(item => { api[item.name] = (params) => ipcRequest(item.channel, params) }) return api } export default ypTalkBridge

 

 渲染层的webview:

  

 // 接受webview页面通信
      webview.addEventListener('ipc-message', (event) => {
        if (event.channel == 'talk-choose') {
          // 吊起人员选择
          permissionDialog({
            onConfirm: (data) => {
              const params = event.args[0]
              webview.send(params?.eventName, { msgno: params?.msgno, data, eventName: 'onSuccess' }) }
          })
        }
      })

 

 

ypTalkApi.js
interface Ichoose {
  name: string,
  onSuccess?: (v: any) => void
}
const tip = '请在桌面端调用此方法'

const {_ypTalkApi } = window as any

// 是否在桌面端运行
const isYpTalk: boolean = _ypTalkApi?.isMainFrame || false

// 选择人员
const choose = (params: Ichoose) => {
  return new Promise(async (resolve, reject) => {
      if (!isYpTalk) {
        reject(tip)
      } else {
        const data = await _ypTalkApi?.choose(params)
        resolve(data)
      }
  })
}
  
export default {
  isYpTalk,
  choose
}

 

 

 web网页 嵌入的页面:

  // electron通讯方法(向客户端发送消息)
  const sendToElectronPage = async () => {
    ypTalkApi.choose({
      name: '哈哈哈'
    }).then(data => {
      console.log(data)
    })
  }
  useEffect(() => {
    sendToElectronPage()
  }, [])

 

posted @ 2020-10-23 13:20  simple-love  阅读(2902)  评论(1编辑  收藏  举报