Electron starts unfocused (responds to double clicks only) - node.js

I'm developing a test application using Electron 18.
I noticed that sometimes on mac the app starts without the focus.
If I click on the window nothing change, I noticed that performing a double click the html buttons are pressed but the window remain unfocused.
My code if very very easy:
Html:
<button>Test</button>
<hr>
Also the main.js is basic:
const { app, BrowserWindow, ipcMain, screen, globalShortcut } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
Nothing more..
I start the app with elecrtron ./ and sometime, I get the windows unfocus as the following image (as you can see the app name is gray, unfocused):
It happen more ofter when I press ctrl+R to refresh the page

Related

Electron Global Shortcut alternative without reserving the key

How can i capture keypress in Electron without globalShortcut and without losing the key functionality. For example i want to capture Tab press but without losing it's ability to indent for example in visual studio code.
I use Electron 13.0 because if i use higher some required modules don't work.
I tried iohook but throws iohook.node module not found. I think it doens't have support for Electron 13 yet.
Anyone ideea how can i do accomplish this? Thank you !
Electron can be a bit of a headache when it comes to communicate between the window and the main process, and for good reason: Security.
However, this problem has two solutions:
Not recommended: plain ipcRenderer required with { nodeIntegration: true } and window.electron in index.html, that can cause a lot of trouble, don't do that, you give access to the user to all nodejs functions, like fs, child_process, ...
Recomended: preload. Preload makes the bridge between the process and the window allowing you to pick what you want to share with the window, in this case, ipcRenderer without the whole electron access.
Read more about Electron secuity here
First, create a preload.js to pass scope isolated ipcRenderer.send function to the window
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
const exposedAPI = {
sendMessage: (message) => {
ipcRenderer.send('my-event', string);
}
};
contextBridge.exposeInMainWorld("electron", exposedAPI);
More about contextBridge here
In the main electron script
// main.js
const { ipcRenderer } = require('electron');
...
const window = new BrowserWindow({
...
preload: 'my/preload/path/preload.js', // Here preload is loaded when the window is created
})
...
ipcRenderer.on('my-event', (string) => {
// do struff with string
});
Great full example here
Finally, the window where you want to capture the event from without changing the behaviour
// index.html or your-script.js
document.addEventListener('keydown', (evt) => { // keyup, keydown or keypress
window.electron.exposedAPI.sendMessage('key was pressed');
});

White Screen issue with Electron/Node app

I've recently created an app with a Java backend and a React frontend, and I was using Electron and some Node features to bundle the app and create a desktop app for it. Basically, I decided to use Java for some Java-specific libraries I needed. The app will run on port 8080, with the React/JS stuff being served from the static folder, and the Electron wrapper will use some Node libraries to start up the Java process and then after a few seconds connect to localhost:8080.
This works like a charm about half the time, and the other half instead shows me a white screen with no errors! I have debugged this countless times and the only way to fix it is to force reload the Chromium page which sometimes works, and other times doesn't. Obviously this isn't acceptable for users to do with my app. The problem is, I have run out of ideas as to what could be causing this issue.
Here is my main.js for the electron app
const {app, BrowserWindow} = require('electron')
function createWindow () {
try {
var jarPath = './app.jar';
var kill = require('tree-kill');
var child = require('child_process').spawn('java', ['-jar', jarPath, '']);
let win = new BrowserWindow({width: 1000, height: 730});
setTimeout(function() {
win.loadURL('http://localhost:8080/index.html');
}, 2000);
console.log("PID: " + child.pid);
win.on('closed', function () {
kill(child.pid);
mainWindow = null
}
)
} catch(e) {
console.log(e);
}
}
app.on('ready', createWindow)

Cordova Electron app, openFileDialog event

In my app I open a new window with an external web pagte. This page let users to choose a file. I need to intercept the openFileDialog opened.
Is there a way to do this?
Alternatively ss there a way to execute a script from the external page that runs some function on my electron app?
Thank you
Example:
// open an external page
const { remote } = require('electron');
const { BrowserWindow } = remote;
win = remote.getCurrentWindow();
newWin = new BrowserWindow(
{
parent: win,
modal: false,
show: false,
width: 1280,
height: 1024,
webPreferences: {
nodeIntegration: false,
plugins: true
}
}
);
newWin.loadURL(url);
//Page into newWin will open a file choose dialog and i need to know this is happened...
Did you tried electron dialog, below code snippet uses a same electron thread
const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
To exchange information between process you may look into
ipc-main AND webContents

Chrome Dev tools in electron app?

I have found that, while running some Electron app, I can access Chrome Dev Tools by pressing Cmd-Alt-I, while on some others I can't. I am wondering which is the setting to avoid/enable this behaviour.
There are a couple of options. You can initialize your BrowserWindow without devtools:
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
devTools: false
}
});
Or you can catch the opened event on the webContents and close it:
mainWindow.webContents.on("devtools-opened", () => {
mainWindow.webContents.closeDevTools();
});

How to integrate and run existing ReactJS Application in Electron

For instance, I have an ReactJS application: https://iaya-664f3.firebaseapp.com/
You can see in the HTML source the bundle.js file.
I have tried to run this application as desktop application using Electron, which should launch this web application in chromium window but it is not working.
Following is my main React application file app.js sitting in root directory. However compiled files bundle.js and index.html are in ./public/directory.
./app.js
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';
import routes from './routes';
import {Provider} from "react-redux";
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';
import rootReducer from './reducers/index';
const store = applyMiddleware(ReduxPromise)(createStore)(rootReducer);
ReactDOM.render( <Provider store={store}>
<Router history={browserHistory} routes={routes} />
</Provider> ,
document.getElementById('react-app'));
./index.js
In this file I'm embedding my application to Electron to run in chromium.
var app = require("./app");
var BrowserWindow = require("browser-window");
// on electron has started up , booted up, everything loaded (Chromium ,goen, live)
app.on("ready", function(){
var mainWindow = new BrowserWindow({
width:800,
height:600
});
mainWindow.loadUrl("file://" + __dirname+ "/public/index.html");
});
But this give some error on import React from 'React' line in my ./app.js.
So I assume that, I should only give ./public/index.html file to load which includes the compiled bundle.js. But I wonder, how that will work as the line app.on("ready", function(){ expect an app.
Moreover I have also tried following way in ./index.js but it gives some other error.
const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600});
// and load the index.html of the app.
/*mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'public/index.html'),
protocol: 'file:',
slashes: true
}));*/
mainWindow.loadURL("file://" + __dirname+ "/public/index.html");
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
Basically the thing is very simple. Electron acts just like a desktop chromium wrapper, that displays your any (any) type of web page inside desktop chromium.
So for example, we want to display http://www.google.com then you simply pass this URL to your loadURL() function.
Here is the working copy of code (asked in the question):
const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
app.on('ready', function(){
var mainWindow = new BrowserWindow({width: 800, height: 600});
mainWindow.loadURL("http://localhost:8080/"); // option1: (loading a local app running on a local server)
//mainWindow.loadURL("https://iaya-664f3.firebaseapp.com"); // option2: (loading external hosted app)
// loading developer tool for debugging
mainWindow.webContents.openDevTools();
});
I hope this will clarify the confusion for many people, who are new to Electron. So the final words are that Electron only loads existing and running web application. It does not compile, does not act as a server. It is just a box in which you can put anything and give it a desktop sort of look e.g. menues, desktop notification, local file system access, etc.

Resources