Cai*_*kai 5 javascript reactjs electron
I have an Electron app that is displayed using BrowserWindow. I want to open an external URL in the same window so that the user can log in (to an external website) and after the user logs in it should display the Electron application again instead of the external website that the user used to log in.
I've been able to open the external url in the same window by using:
<a href="https://loginsite-example.com" target="_blank" rel="noreferrer">
site where you have to log in
</a>
Run Code Online (Sandbox Code Playgroud)
However, I don't know how to show the Electron application again after the user successfully logs in to the external website. Also, I would like to keep the session from the external website so that I could consume its API inside the electron application.
window.loadFile(...)在窗口源之间移动,无论是本地(文件)还是远程(URL),都可以通过调用或 来完成window.loadURL(...),但前提是创建窗口实例之后。
main.js(主线程)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
// Prevent garbage collection
let window;
function createWindow() {
return new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
}
function showMainWindow() {
window.loadFile('index.html')
.then(() => { window.show(); })
}
function showLoginWindow() {
// window.loadURL('https://www.your-site.com/login')
window.loadFile('login.html') // For testing purposes only
.then(() => { window.show(); })
}
electronApp.on('ready', () => {
window = createWindow();
showMainWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ----- IPC -----
electronIpcMain.on('message:loginShow', (event) => {
showLoginWindow();
})
electronIpcMain.on('message:loginSuccessful', (event, session) => {
showMainWindow();
})
Run Code Online (Sandbox Code Playgroud)
index.html(渲染线程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Main Window</title>
</head>
<body>
<div>Main Window</div><hr>
<button type="button" id="show-login">Login</button>
</body>
<script>
document.getElementById('show-login').addEventListener('click', () => {
window.ipcRender.send('message:loginShow');
});
</script>
</html>
Run Code Online (Sandbox Code Playgroud)
login.html(渲染线程)
仅用于测试目的,因为我们无法访问真正的登录页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login Window</title>
</head>
<body>
<div>Login Window</div><hr>
<label for="username">Username: </label>
<input type="text" id="username"><br>
<label for="password">Password: </label>
<input type="password" id="password"><br>
<button type="button" id="login">Login</button>
</body>
<script>
// For testing purposes only.
document.getElementById('login').addEventListener('click', () => {
window.ipcRender.send('message:loginSuccessful');
});
</script>
</html>
Run Code Online (Sandbox Code Playgroud)
最后,一个preload.js在主线程和渲染线程之间安全通信的脚本。
preload.js(主线程)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'message:loginShow',
'message:loginSuccessful'
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Run Code Online (Sandbox Code Playgroud)
需要克服的一个问题是,一旦您将登录凭据提交到服务器,您将如何获取会话数据?您的 html Javascript 将需要检测必要的会话数据是否可用以及何时可用。一旦会话数据可用,通过 IPC 将会话从渲染线程传输到主线程就是一个简单的过程。要弄清楚这一点,需要一些额外的信息并了解您的登录系统(一个单独的 StackOverflow 问题)。
作为前驱者,我怀疑需要在主线程中检测登录页面何时通过类似window.webContents.on('did-navigate', ...). 一旦检测到,请快速检查下一个加载的页面以查看会话是否存在。如果是,则获取它,将其发送到主线程,然后重定向回页面index.html。
我认为如果您可以通过 API 登录,应该会有一种更简单的方法。然后整个过程就可以独立于您的 Electron 应用程序中。IE:显示本地(文件)login.html,将数据提交到服务器并等待“成功”或“失败”响应。如果成功,则在响应中传递会话数据。如果不成功,则显示相应的错误消息。
| 归档时间: |
|
| 查看次数: |
10997 次 |
| 最近记录: |