Configuración de aplicaciones desktop en Electron mediante la creación de manejadores de eventos del ciclo de vida y la ejecución de código personalizado dependiendo del sistema operativo del usuario.
En el artículo anterior hemos conseguido crear y arrancar nuestra primera aplicación con Electron y ahora vamos a personalizar un poco más su funcionamiento, profundizando en el código NodeJS que teníamos en el archivo main.js
.
Qué es app y qué es BrowserWindow
En el comienzo de este archivo main.js
habíamos hecho el require de un par de artefactos:
- app: es el objeto que nos permite controlar los eventos del ciclo de vida de la aplicación
- BrowserWindow: es un objeto que nos permite crear y gestionar ventanas de la aplicación.
Puedes apreciar que
app
es un objeto yBrowserWindow
una clase por sus nombres y las convenciones que sigue la comunidad de Javascript y el propio Electron, de nombrar las clases con la primera en mayúscula.
Qué significa que la aplicación está "ready"
Una de las cosas que podemos hacer con el objeto app
es enganchar código a ejecutar cuando la aplicación está lista para recibir acciones. Ese estado "ready" es muy importante porque si no esperamos a que la aplicación esté lista no seremos capaces de crear ventanas.
Muchos de los objetos que te ofrece Electron para desarrollar tus aplicaciones trabajan con la arquitectura dirigida por eventos de Node. Esta es una de las características de desarrollo de Javascript que explota la asincronía del lenguaje. El objeto app
es uno de esos artefactos que trabaja con eventos.
Existen diversos métodos que te devuelven promesas a las que puedes enganchar código cuando éstas se resuelven. Este es el código para hacer cosas cuando la aplicación está lista (ready).
app.whenReady().then(() => {
// Hacer cosas cuando la aplicación está lista
});
Típicamente en Node a los eventos se les colocan funciones callback o manejadores con el método on()
, para ejecutar código cuando se producen, por lo que también podría funcionar un código como el siguiente:
app.on('ready', () => {
// Hacer cosas...
});
Electron no obstante nos ofrece el método whenReady()
para ser más expresivos y para que no corra el riesgo de equivocarnos al escribir el nombre del evento sobre el que queremos enganchar el código. Además whenReady()
también nos permite escribir el código con el estilo de promesas, con el then()
, que es más claro.
Más métodos del ciclo de vida básico de la aplicación
Vamos a avanzar un poco más en nuestros primeros pasos con el framework abordando nuevos métodos del app
, el objeto con el que controlamos el ciclo de vida de la aplicación.
Primero debemos saber que, aunque Electron se encargue de manejar las diferentes plataformas por nosotros (Windows, Linux o Mac), sí que hay algunos eventos específicos que atañen a uno u otro sistema operativo en concreto.
Evento activate
El que vamos a conocer a continuación es exclusivo de MacOS y se llama "activate
". Este evento permite hacer cosas en el momento en el que una aplicación se activa, lo que puede ocurrir ante diversas situaciones:
- Arrancar la aplicación que se encontraba totalmente parada
- Tratar de arrancar la aplicación cuando ésta estaba ya en ejecución
- Hacer clic en el icono del dock de MacOS
Podemos ejecutar código cuando se produce la activación de la ventana de esta manera:
app.on('activate', () => {
console.log('activada!!');
});
Gracias a este mensaje en la consola cuando se produce la activación puedes reconocer las situaciones que pueden desencadenar este método "activate
".
Recuerda que si lanzas un mensaje a la consola éste aparecerá en el terminal desde el que arrancaste la aplicación con "
npm run start
".
Evento window-all-closed
Ahora vamos a conocer otro método interesante, en este caso que atañe a todas las plataformas y no solo a MacOS. Se trata del evento 'window-all-closed
' que ocurre cuando todas las ventanas de una aplicación han sido cerradas.
Puedes ejecutar código frente a este evento de la siguiente manera:
app.on('window-all-closed', () => {
console.log('Todas las ventanas han sido cerradas');
});
Ahora, al cerrar la ventana de la aplicación recibirás un mensaje en la consola.
Gestionar comportamientos especiales para cada plataforma
Al dejar la aplicación escuchando eventos como los anteriores podrás observar que el comportamiento de la aplicación ha variado un poco.
En concreto, al cerrar las ventanas de la aplicación no se libera el proceso dentro de nuestro terminal, por lo que la aplicación en realidad permanece abierta.
Este comportamiento no es tan extraño en un sistema MacOS, ya que a menudo las aplicaciones funcionan justamente así. Sin embargo, en Windows o Linux no es un comportamiento esperado, por lo que lo correcto de cara al usuario sería terminar el proceso de la aplicación que se está ejecutando al cerrar todas las ventanas.
Si queremos que nuestra aplicación funcione de maneras distintas en cada plataforma, de modo que en Windows y Linux se detenga completamente y en Mac se quede en el Dock, podemos usar una propiedad de NodeJS llamada process.platform
.
En Node process nos ofrece información sobre el proceso que está ejecutando el código y su propiedad platform puede tener tres valores distintos.
- "win32" en sistemas Windows
- "linux" en sistemas Linux
- "darwin" en sistemas MacOS
De modo que, si deseamos que al cerrar la aplicación se cierre completamente el proceso pero solamente para sistemas que no sean MacOS, podríamos usar este código.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Simplemente nos quedamos escuchando el evento window-all-closed
y cuando se detecta realizamos una comprobación para saber si no estamos en Mac. En caso de que sea así, ejecutamos el método app.quit()
y la aplicación se cerrará.
Ahora en Windows y Linux el sistema funcionará tal como espera el usuario, que la aplicación se detenga completamente al cerrar la ventana. Sin embargo, en MacOS ahora se queda abierta, por ello veremos que en el Dock permanece el icono de la aplicación como si estuviera ejecutándose todavía.
El problema que nos encontramos ahora en MacOS es que, al hacer clic sobre el icono del Dock no ocurre nada. Esto es también normal, pues la ventana la había cerrado el usuario. Pero lo que el usuario también podría esperar es que la aplicación se recupere al pulsar de nuevo el icono y eso lo tenemos que programar.
Para ello creamos un manejador de evento para activate
, en el que preguntamos si todas las ventanas de la aplicación están cerradas. Si fuera el caso, abrimos una nueva ventana.
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
No tenemos que hacer en este caso comprobaciones de plataforma porque el evento
activate
solamente aplica a MacOS.
Código completo de personalización de la aplicación
Veamos el código completo de nuestro ejemplo de aplicación, en el archivo main.js, para ver cómo se ha conseguido este comportamiento:
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 400,
height: 300,
})
win.loadFile('index.html')
}
app.whenReady().then(createWindow);
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
Los cambios efectuados son los siguientes:
- Se ha separado el procedimiento de creación de la ventana de la aplicación a una función, para poder reutilizarlo.
- Al detectar el
app.whenReady
se invoca esa función de creación de la ventana. - El detectar el evento
activate
, que solo funciona en MacOS, por lo que no necesitamos hacer ninguna comprobación de la plataforma, se pregunta si no hay ventanas abiertas, en cuyo caso se vuelve a abrir una. - Al detectar el evento
window-all-closed
se comprueba si estamos en plataformas distintas de Mac, en cuyo caso hacemos que la aplicación termine.
Eso es todo de momento en esta primera aplicación con Electron. De momento sigue siendo muy sencilla, pero hemos podido aprender nuevas utilidades sobre la aplicación y la gestión del flujo de su ciclo de vida.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...