繁体   English   中英

如何在 Electron (Next.js/React) 中实现 websocket 客户端?

[英]How to implement websocket client in Electron (Next.js/React)?

我有一个工作的 websocket 服务器。 我以前在网络浏览器/反应中使用 websocket 作为客户端,但我无法在电子应用程序中使用 Websocket,因为 WebSocket 取决于浏览器的兼容性,并且由于某种原因,此功能在 Electron 中不可用。

我使用 nextron (nextjs/react + electron) 样板。

yarn create nextron-app MY_APP --example with-typescript-material-ui

import React from 'react';
import Head from 'next/head';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import { theme } from '../lib/theme';
import type { AppProps } from 'next/app';

export default function (props: AppProps) {
  const { Component, pageProps } = props;

  // where to put ws here ? this placement generates an error
  const ws = new WebSocket("ws://192.168.100.8:8081/")
  console.log("file: _app.tsx:11 ~ ws", ws)

  React.useEffect(() => {
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return (
    <React.Fragment>
      <Head>
        <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Component {...pageProps} />
      </ThemeProvider>
    </React.Fragment>
  );
}

在此处输入图像描述

显然是做不到的。 Electron 阻止任何在客户端 (React) 内使用 websocket 的尝试。 到目前为止我使用的唯一解决方案是将 websocket 消息和事件转换为ipcRenderer ( https://www.electronjs.org/docs/latest/api/ipc-renderer )

这个过程相当简单:React 接收一个事件并在客户端调用 IPCRenderer,IPCRenderer 在渲染器(node.js)中接收一个事件并调用 node.js 中的ws或 websocket

发送:

React -> IPC -> Node.js -> websocket -> Websocket Server (main server) 

接收:

Websocket Server (main server) -> websocket -> Node.js -> IPC -> React

我从这里使用 node.js 的ws模块

我希望这可以帮助将来的人或我自己

如果你想发送/广播事件到 websocket

// in the client side usually the root component, or in my case _app.tsx:
import electron from 'electron'
const ipcRenderer = electron.ipcRenderer

class _app extends React.Component<any, any> {
  constructor(props: any) {...}
  componentDidMount() {...}

  // this will send a message for a button click
  handleClick(msg: string) {
      // reply will be true if it succeed
      let reply = ipcRenderer.sendSync('some-event', msg)
  }
}

稍后在主窗口 app.js 中:

import { app, ipcMain } from 'electron'
import WebSocket from 'ws'

// connect with ws
let ws = new WebSocket(`ws://${YOUR_WS_SERVER_IP}:${YOUR_WS_PORT}/`)

// find the electron main window, mine's in background.ts
const mainWindow = createWindow('main', {
    width: 1366,
    height: 768,
    minWidth: 1366,
    minHeight: 768
})

// .... some electron code here ....

// when ipcMain receive an event named 'some-event'
ipcMain.on('some-event', (event, msg) => {
  ws.send(msg) // send message using websocket here
  event.returnValue = true // give a return value true 
})

如果你想处理从 websocket 接收到的事件

import { app, ipcMain } from 'electron'
import WebSocket from 'ws'

// connect with ws
let ws = new WebSocket(`ws://${YOUR_WS_SERVER_IP}:${YOUR_WS_PORT}/`)

// find the electron main window, mine's in background.ts
const mainWindow = createWindow('main', {
  width: 1366,
  height: 768,
  minWidth: 1366,
  minHeight: 768
})

ws.on("message", (message: any) => {
   var str = message.toString()
   console.log("Message received: ", str)
   
   mainWindow.webContents.send('some-event', str)
})

在反应组件(App.tsx)上:

// in the client side usually the root component, or in my case _app.tsx:
import electron from 'electron'
const ipcRenderer = electron.ipcRenderer

class _app extends React.Component<any, any> {
  constructor(props: any) {
      super(props)
      // I put this since I use class based component. 
      // a functional ones won't need this
      this.handleIpc = this.handleIpc.bind(this)
  }
  componentDidMount() {
      this.handleIpc() // to make sure the ipcRenderer manipulate the component state AFTER the whole component was loaded first
  }

  handleIpc() {
    var self = this
    ipcRenderer.on("some-event", function (e, data) {
       console.log("Message received: ", data)
    })
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM