我的电子应用程序正在使用远程隔离方法(在 this article 中提到)。我的远程 Web 应用程序是一个 Ruby on Rails 应用程序。现在,我想使用 WebSocket 将通知从远程 Web 应用程序推送到电子应用程序。即使用户关闭了应用程序,也要向用户发送消息,我有了一个想法。在 Rails 服务器中,我使用 ActionCable 将通知广播到频道。在主要流程中,我使用 actioncable 包订阅此频道。
import ActionCable from "actioncable";
const websocketUrl = "wss://rt.custom-domain.dev/_/cable";
const cable = ActionCable.createConsumer(websocketUrl);
cable.subscriptions.create(
{ channel: "WallChannel", wall_id: "106" },
{
received(data: any): void {},
disconnect(): void {},
connected(): void {},
disconnected(): void {},
present(): void {},
absent(): void {},
}
);
但是我遇到了一个错误:
<块引用>ReferenceError: window is not defined
然后我深入研究actioncable包的源代码,发现该包使用了浏览器的WebSocket API,所以出现错误。
我尝试使用 ws 包订阅 websocket,而不是跟随 this post。但是我无法连接到 websocket 服务器。当我调用 App.ws.sendmessage
时出现错误:
错误:WebSocket 未打开:readyState 0 (CONNECTING)
有没有人像我尝试过的那样使用 websocket 尝试从远程 Web 应用程序推送通知?你有没有遇到同样的问题?或者如果您对我的情况有更好的解决方案,请与我分享您的想法。非常感谢。
这是我的电子应用程序的 main.ts 文件
import { app, BrowserWindow, ipcMain, Notification } from "electron";
import { createWindow } from "src/main/CreateWindow";
import { showNotification } from "./helpers";
import appConfigs from "src/AppConfigs";
let mainWindow: BrowserWindow;
const createAppWindow = () => {
mainWindow = createWindow(appConfigs.targetUrl, { interop: true });
// Open the DevTools.
if (!app.isPackaged) {
mainWindow.webContents.openDevTools();
}
};
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
// eslint-disable-line global-require
app.quit();
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", () => {
createAppWindow();
});
var App: { ws: any; param: any; connect_server: any; sendmessage: any } = {
ws: null,
param: null,
connect_server: () => {},
sendmessage: () => {},
};
App.sendmessage = function (send: any) {
let data = {
message: send,
action: "speak",
};
let message = {
command: "message",
identifier: JSON.stringify(App.param),
data: JSON.stringify(data),
};
App.ws.send(JSON.stringify(message));
};
App.connect_server = function () {
const WebSocket = require("ws");
App.ws = new WebSocket("wss://rt.custom-domain.dev/_/cable", [
"actioncable-v1-json",
"actioncable-unsupported",
]);
console.log("connect_server", App.ws);
App.param = { channel: "WallChannel", wall_id: 106 };
App.ws.on("open", function open() {
console.log("open channel");
let data = {
command: "subscribe",
identifier: JSON.stringify(App.param),
};
App.ws.send(JSON.stringify(data));
console.log("send JSON");
});
App.ws.on("message", function (event: any) {
console.log("message", event);
});
App.ws.on("error", function (err) {
console.log("Found error: " + err);
});
};
App.connect_server();
CreateWindow.ts
import { BrowserWindow } from "electron";
import appConfigs from "src/AppConfigs";
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: any;
interface BrowserWindowOption {
title?: string;
height?: string;
width?: string;
interop?: boolean;
}
export const createWindow = (
url: string,
options: BrowserWindowOption = {}
): BrowserWindow => {
// Create the browser window.
const mainWindow = new BrowserWindow({
title: options.title || appConfigs.name,
height: options.height || appConfigs.height,
width: options.width || appConfigs.width,
webPreferences: options.interop
? {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
}
: {},
});
// and load the targetUrl.
mainWindow.loadURL(url || appConfigs.targetUrl);
return mainWindow;
};
package.json
{
"name": "electron-forge-app",
"productName": "electron-forge-app",
"version": "1",
"description": "My Electron application description",
"main": ".webpack/main",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts ."
},
"keywords": [],
"author": {
...
},
"license": "MIT",
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-squirrel",
"config": {
"name": "electron_furge"
}
},
{
"name": "@electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
},
{
"name": "@electron-forge/maker-rpm",
"config": {}
}
],
"plugins": [
[
"@electron-forge/plugin-webpack",
{
"mainConfig": "./webpack.main.config.js",
"renderer": {
"config": "./webpack.renderer.config.js",
"entryPoints": [
{
"html": "./src/index.html",
"js": "./src/renderer.ts",
"name": "main_window",
"preload": {
"js": "./src/interop/preload.ts"
}
}
]
}
}
]
]
}
},
"devDependencies": {
"@electron-forge/cli": "^6.0.0-beta.54",
"@electron-forge/maker-deb": "^6.0.0-beta.54",
"@electron-forge/maker-rpm": "^6.0.0-beta.54",
"@electron-forge/maker-squirrel": "^6.0.0-beta.54",
"@electron-forge/maker-zip": "^6.0.0-beta.54",
"@electron-forge/plugin-webpack": "6.0.0-beta.54",
"@marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
"@types/actioncable": "^5.2.4",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"css-loader": "^4.2.1",
"electron": "12.0.5",
"eslint": "^7.6.0",
"eslint-plugin-import": "^2.20.0",
"fork-ts-checker-webpack-plugin": "^5.0.14",
"node-loader": "^1.0.1",
"style-loader": "^1.2.1",
"ts-loader": "^8.0.2",
"typescript": "^4.0.2"
},
"dependencies": {
"actioncable": "^5.2.6",
"electron-squirrel-startup": "^1.0.0",
"ws": "^7.4.5"
}
}