Electron – Cross Platform Desktop Apps Made Easy (Part 5) #ibmchampion

Today, I want to show, how we can use Electron’s Notification Api for Windows, Linux and macOS. All three operating systems provide means for applications to send notifications to the user.

Electron conveniently allows developers to send notifications with the HTML5 Notification API, using the currently running operating system’s native notification APIs to display it.

Lets write some code. From the past 4 parts of this tutorial you already know, that we start with a new, empty project. So, create a new folder in your projects folder, run npm init and npm install electron --save-dev to create package.json and add Electron as a dependency. Also add 2 new files; app.js and main.html.

Here is, how your project should look like.

{
  "name": "part5",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "electron ."
  },
  "author": "Ulrich Krause",
  "license": "MIT",
  "devDependencies": {
    "electron": "^1.8.2"
  }
}
const {
    app,
    BrowserWindow
} = require('electron')

// 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 win

function createWindow() {
    win = new BrowserWindow({
        width: 800,
        height: 600
    })
    win.loadURL('file://' + __dirname + '/main.html')
}

app.on('ready', createWindow)
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Desktop Notification</title>
</head>

<body>
    <h1>Desktop Notification</h1>
</body>

</html>

Avoid platform-dependent code

Before we start with our notification, here are some things, you need to know, when creating Electron applications for different platforms. There are some platform specific elements that you already might know from other programming languages.
Temp dir, path delimiter, just to name a few.

According to Electron’s ‘Coding Style

Avoid platform-dependent code:

  1. Use path.join() to concatenate filenames.
  2. Use os.tmpdir() rather than /tmp when you need to reference the temporary directory.

This being said, we will now make some modifications to app.js. We add some core Node.js modules ( lines 2, 3 ) to handle path and URL. Then we use methods from those modules to build the URL for main.html in line 23

// add core Node.js modules
const url = require('url')
const path = require('path')

const {
    app,
    BrowserWindow
} = require('electron')

// 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 win

function createWindow() {
    win = new BrowserWindow({
        width: 640,
        height: 480
    })
    
    // use url and path to make loading of main.html
    // platform independend
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'main.html'),
        protocol: 'file:',
        slashes: true
    }))
}

app.on('ready', createWindow)

Next, we will add code to handle window and application closing, because macOS behaves a little bit different than Windows or Linux. Read the code comments for explaination.

// add core Node.js modules
const url = require('url')
const path = require('path')

const {
    app,
    BrowserWindow
} = require('electron')

// 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 win

function createWindow() {
    win = new BrowserWindow({
        width: 640,
        height: 480
    })

    // use url and path to make loading of main.html
    // platform independend
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'main.html'),
        protocol: 'file:',
        slashes: true
    }))

    // Emitted when the window is closed.
    // 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.
    win.on('closed', function () {
        win = null
    })
}

app.on('ready', createWindow)

// Quit when all windows are closed.
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

// 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.
app.on('activate', function () {
    if (mainWindow === null) {
        createWindow()
    }
})

With these modifications, you now have a boilerplate that you can use when creating new Electron applications. You can also use electron-quick-start from GitHub which is similar.

Notifications

HINT: if you are working on Windows, the following sample will not work with all versions. It should work on Win 7 & 8, but might fail on Windows 10. Especially, if you have ‘Windows 10 fall creators update’ installed. This is a known issue. Notifications on Windows only work, if the application is packaged and installed on the target platform. Packaging and Installation is planned to be a topic for an upcoming article. If you are on Linux or macOS, you can keep on reading.

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Desktop Notification</title>
</head>

<body>
    <h1>Desktop Notification</h1>
    <button type="button" name="button" onclick="doNotify()">Notify me</button>
    <script src="main.js"></script>
</body>

</html>

We add a button to our main.html ( line 11 ) that will call doNotify() when clicked and also add a script tag ( line 12 ). We then create a new main.js file in our project folder. main.js will contain the doNotify() function.

function doNotify() {
    const notification = {
        title: 'Basic Notification',
        body: 'This is an Electron notification'
    }
    const myNotification = new window.Notification(notification.title, notification)
}

I have created this example on a Windows 10 machine. As it is not showing the notification there, I moved my project folder to my Mac, and I get

And when I click the ‘Notify me‘ button, the notification appears.

This is just a simple example. For more information see https://electronjs.org/docs/api/notification.

You can download the source code for this part of the tutorial here.