我做了我的第一次尝试,并希望使用电子apis的角度渲染过程。我按照指示进
因此,在我的main.js文件中,我添加了:
const {app, BrowserWindow, ipcMain} = require('electron')我还补充说
function openModal(){
const { BrowserWindow } = require('electron');
let modal = new BrowserWindow({ parent: mainWindow, modal: true, show: false })
modal.loadURL('https://www.sitepoint.com')
modal.once('ready-to-show', () => {
modal.show()
})
}
ipcMain.on('openModal', (event, arg) => {
openModal()
})在我的app.component.ts文件中添加了导入import { IpcRenderer } from 'electron';
我添加了以下构造函数
private ipc: IpcRenderer
constructor(){
if ((<any>window).require) {
try {
this.ipc = (<any>window).require('electron').ipcRenderer;
} catch (e) {
throw e;
}
} else {
console.warn('App not running inside Electron!');
}
}由于我的CLI不完全清楚icp是否属于IpcRenderer类型,所以我在这一行中添加了
private ipc: IpcRenderer | any;有此功能
openModal(){
console.log("Open a modal");
this.ipc.send("openModal");
}它应该能够向“主”进程发送某种东西。但是如果我调用这个函数,就会得到错误
TypeError:无法读取未定义的属性“发送”
我做错什么了?
发布于 2022-01-28 11:57:17
我也面临着同样的问题,但发现了一个长期的黑客攻击。
致因
看一看这一行:
(<any>window).require这一行搜索全局窗口对象中的require()方法,该对象是一个NodeJS函数,因此如果使用电子版本> 5,则不会在运行时注入该方法,因为默认情况下,BrowserWindow类的webPreferences -> nodeIntegration属性设置为false。
解决方案
有两种解决办法:
contextIsolation: false的应用程序将如预期的那样工作,但此次黑客攻击存在安全问题。如这个答案中所引用的电子应用是伟大的,因为我们可以使用节点,但这种力量是一把双刃剑。如果我们不小心,我们会通过我们的应用程序给某人访问节点的权限,而使用节点,一个坏的参与者可能会破坏您的计算机或删除您的操作系统文件(我想,其中包括其他事情)。
contextBridge 和preload.js:这是从上面的答案和对这个问题的其他答案中派生出来的。我将提出一个使用角度的解决办法。
在webPreferences中,在main.js中创建mainWindow时,进行以下修改:
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, "preload.js")
}在main.js所在的同一个目录中,创建一个preload.js文件并在那里添加以下代码(对于这个用例,您可以省略receive()声明,因为它不是必需的)。
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["openModal"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);PS:添加这段代码的原因已经在引用的答案中提到了,所以我不会在这里重复。
现在,在运行时,电子将将window.api.send()和window.api.receive()方法注入全局window对象中。如果您试图直接访问角组件中的它们,linter将给出错误,因为它们不是在标准窗口对象上定义的。为了解决这个问题,我们将创建一个角服务并注入到我们的应用程序中。此服务将引用在运行时创建的浏览器的窗口对象,并添加上述两个函数。
创建一个WindowRefService并添加以下代码:
window-ref-service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class WindowRefService {
getWindow(): any {
return window;
}
constructor() { }
get nativeWindow(): Window{
return this.getWindow();
}
}不要忘记在AppModule中注册服务:
...
import { WindowRefService } from './window-ref.service';
...
@NgModule{
...
providers: [WindowRefService]
}之后,将其注入组件中:
import { WindowRefService } from './window-ref.service';
...
private _window:any;
constructor(windowRef: WindowRefService){
this._window = windowRef.nativeWindow;
}
...
//openModal function
openModal(){
console.log("Open a modal");
this._window.api.send("openModal", /* data to be sent, if any*/);
}删除构造函数中的private ipc: IpcRenderer | any;和其他现有代码,因为它不是必需的。
https://stackoverflow.com/questions/66636943
复制相似问题