Messages between `BrowserView` and the `renderer` React page in `Electron - electron

I'm trying to figure out how to exchange messages between the main process and the BrowserView.
I've been using the ipc between the main process and the renderer process within a "simple" react renderer page.
But now, using the same technique, I do not see the received message in the console of the BrowserView, which, as far as I understand, seems to behave differently from a "normal" react renderer page.
And this SOF post seems confirm my hypothesis: Electron BrowserView Renderer process vs WebView
In preload I defined:
declare global {
interface Window {
api: {
electronIpcSend: (channel: string, ...arg: any) => void;
electronIpcOn: (channel: string, listener: (event: any, ...arg: any) => void) => void;
}
}
}
In main I have :
function createWindowTypeC (url_string: string) {
WindowTypeC = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
sandbox: true,
nodeIntegrationInSubFrames: false,
webSecurity: true,
webviewTag: false,
preload: path.join(__dirname, "./preload/preload.js"), /* eng-disable PRELOAD_JS_CHECK */
}
})
// and load the index.html of the app.
// Emitted when the window is closed.
WindowTypeC.on('closed', () => {
WindowTypeC.removeBrowserView(view_C)
WindowTypeC = null
})
enforceInheritance(WindowTypeC.webContents)
// https://www.electronjs.org/docs/latest/api/browser-view
let view_C = new BrowserView()
view_C.webContents.once('did-finish-load', () => {
contents.focus()
view_C.webContents.send('ping', 'whoooooooooh!')
})
view_C.setAutoResize({
width: true,
height: true,
horizontal: true,
vertical: true
})
WindowTypeC.setBrowserView(view_C)
view_C.setBounds({ x: 0, y: 0, width: 800, height: 600 })
view_C.setBackgroundColor("#1e1e1e")
setTimeout(() => {
view_C.webContents.loadURL(url_string)
}, 200)
view_C.webContents.openDevTools({
mode: 'left'
})
}
While in the App_C.tsx I have:
import * as React from 'react';
function App_C(props) {
window.api.electronIpcOn('ping', (event, message) => {
console.log("App_C-window.api.electronIpcOn-ping-message: ", message)
})
window.api.electronIpcSend('pong', "Hello from App_C.tsx")
return (
<div id="outer-container" className='outer-container'>
<h1>App_C</h1>
</div>
);
}
export default App_C;
Executing the code, the page gets correctly rendered, but I do not see any message sent from the BrowserView to the renderer process.
Second, collateral, question, is: how to send a message on the way back, in the BrowserView sent by the renderer process?
And third question: how to interact with the page rendered by the BrowserView?

Related

Electron build failed to load index.html

I'm trying to build my electron application with electron-builder, I have successfully built front-end which was react and did also pass homepage: "./" in my package.json. I have also used hashbrowser as it was mentioned here
but still when I build my app, I get this message in console with white screen:
Not allowed to load local resource. I have passed webSecurity: false in webPreferences electron, It made error go away but didn't fix the problem and still getting white page.
this is my electron index.ts:
let mainWindow: BrowserWindow;
const createWidnow = () => {
mainWindowFunctions();
mainWindow = new BrowserWindow({
minHeight: 600,
minWidth: 800,
x: appXAndY.x,
y: appXAndY.y,
width: appWidthAndHeight.width,
height: appWidthAndHeight.height,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, "preload.js"),web
},
autoHideMenuBar: true,
});
mainWindow.loadURL(
isDev ? "http://localhost:3000/" : `file://${__dirname}/../build/index.html`
);
if (isDev) {
mainWindow.webContents.openDevTools();
}
}
app.whenReady().then(async () => {
createWidnow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWidnow();
}
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
db.close();
app.quit();
}
});
const mainWindowFunctions = () => {
const files = glob.sync(
path.join(__dirname, "./controllers/**/*.js").split(path.sep).join("/")
);
files.forEach((file) => {
require(file);
});
};
I tried webSecurity false but didn't help
The problem is with Electron Packager. Just use Electron Builder. Then you can get the installer using wix3.

Electron App - How do i open link in browser?

im trying to open a link in a new browser window using a Electron App.
const test = () => {
const shell = window.require('electron').shell;
shell.openExternal("https://google.com");
}
When i do this, i get error "window.require is not a function"
I have ofcourse made my research on this, and found several "fixes" but none has worked for me. I have edited my webpack.config.js to this:
module.exports = {
configureWebpack: {
externals: {
'./cptable': 'var cptable'
},
resolve: {
fallback: {
'fs': false,
'crypto': false,
'path': false,
}
}
},
}
I have also made sure nodeIntegration enabled like so:
const mainWindow = new BrowserWindow({
width: 1280,
height: 720,
webPreferences: {
nodeIntegration: true
},
autoHideMenuBar: true,
resizable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
```
still no success. any idea?
renderer.js - from your renderer send request.
const response = await window.electronAPI.openLinkPlease()
preload.js - you have this middleware where your request will receive to send to electron.
process.once("loaded", () => {
contextBridge.exposeInMainWorld('electronAPI', {
openLinkPlease: () => ipcRenderer.invoke('openLinkPlease'),
})
});
electron.js - here you will get your request to open and electron will open this url in your default browser.
First add at the very beginning const {shell} = require("electron"); to add shell capabilities and than after
preload: path.join(__dirname, 'preload.js'),
},
});
add
ipcMain.handle('openLinkPlease', () => {
shell.openExternal("https://google.com");
})
This is the screen how it works from my application

Electron - ERROR:print_render_frame_helper.cc(2224) Printing failed

I have no idea what is happening here, basically I tried to print a document in electron using webContents.print, by silent print, but this error occurs and the printer only prints the document a single time, after that the print queue is filled with new orders, but the error still happening and the file is not printed.
Some code of what I am trying to do:
ipcMain.handle('imprimir', async (event, args) => {
console.log(args);
const ticket = new BrowserWindow({
width: 300,
height: 400,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false
}
});
ticket.loadFile('src/views/ticket.html')
.then(() => {
ticket.webContents.send('enviar-pedido', args);
var options = {
silent: true,
deviceName: 'HP Deskjet 2000 J210 series',
printBackground: true,
color: false,
margin: {
marginType: 'printableArea'
},
landscape: false,
pagesPerSheet: 1,
collate: false,
copies: 1,
/*pageSize: { height: 600, width: 353 }*/
}
ticket.webContents.print(options, (success, failureReason) => {
if (!success) {
console.log(failureReason);
}
console.log('Print Initiated');
ticket.close();
});
});
Note: I do not speak fluent English and this is my first question here, I am sorry if I commited some mistake.
I ran into this just the other day.
I determined the error does not appear with the BrowserWindow option
nodeIntegration: false
If you do not need nodeIntegration in the HTML loaded into the ticket window you should be able to turn this off.

Electron how to redirect users between various .html files

I am looking to try to redirect users from "home.html" to "dashboard.html". I've searched far and wide, yet I haven't found an answer.
When creating your window with the BrowserWindow module, you would have used the method win.loadFile(filePath[, options]) to load your html file.
Once the logic to change pages is successful, all you need to do is execute the win.loadFile(filePath[, options]) line of code again with the path to your new file.
As win.loadFile(filePath[, options]) returns a promise, let's add a .then() statement as well (though not requried).
main.js (main thread)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('home.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
// Run when logic to change to dashboard is successful.
function showDashboard() {
window.loadFile('dashboard.html')
.then(() => { window.show(); })
}

Electron: loadURL from buffer

In my renderer I can emit an event to create a PDF. However, before writing to disk I'd like to first open the newly cerated PDF in another window. How can I circumvent the writing to the file system and use data as my source for loadURL?
My code so far:
ipcMain.on('view-pdf', (event, url) => {
let pdf
mainWindow.webContents.printToPDF({}, (error, data) => {
if (error) throw error
pdf = data
// what's the magic here to make pdf work?
})
const pdfWindow = new BrowserWindow({
width: 1024,
height: 800,
webPreferences: {
plugins: true,
webSecurity: false
}
})
pdfWindow.loadURL(pdf)
})
The async nature of Javascript is a beast. This works as expected:
ipcMain.on('view-pdf', (event, url) => {
mainWindow.webContents.printToPDF({}, (error, data) => {
if (error) throw error
const pdf = data.toString('base64')
const pdfWindow = new BrowserWindow({
width: 1024,
height: 800,
webPreferences: {
plugins: true,
webSecurity: false
}
})
pdfWindow.loadURL('data:application/pdf;base64,' + pdf)
})
})
The code is not perfect but this is how it works.

Resources