Build and sign an Electron application

Creating an Electron application can be done in many ways, and there are many examples available around the web.

When developing Humlix, it was hard to find up to date information on how to get from code to a signed and released application.

After looking at other Electron packagers (e.g., Electron Forge), the decision landed at going with Electron Builder. The reason for this was that we quickly could tick off the following list:

  • Easily include a JAVA jar-file as an ExtraResource
  • Possible to build and sign for Mac OS and Windows from a Mac OS build machine.

Here is the package.json file used in this example.

"build": {
    "appId": "the-app.id",
    "productName": "The-app",
    "extraResources": ["the-app-resource.jar"],
    "mac": {
      "category": "public.app-category.developer-tools",
      "hardenedRuntime": true,
      "gatekeeperAssess": false,
      "entitlements": "entitlements.plist",
      "entitlementsInherit": "entitlements.plist"
    },
    "win": {
      "target": "nsis",
      "sign": "scripts/sign.js"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    },
    "publish": {
      "provider": "spaces",
      "name": "the-bucket",
      "region": "sfo2",
      "channel": "latest",
      "acl": "public-read"
    },
    "afterSign": "scripts/notarize.js"
  }

How to include a file as an extra resource

In the package.json file above, we can see how to include a jar-file using the "extraResources" option.

"extraResources": ["the-app-resource.jar"]

That adds the file "the-app-resource.jar" to the resources directory of the installed application.

Code signing and certifications

Humlix is code signed using a certificate from comodosslstore.com and a certificate generated from an Apple Developer Program account.

Prerequisites

Add both the code signing certificate for Windows and Mac OS to the Mac OS Keychain Access.
Export the code signing certificate for Windows (with password) as a .p12 file and store it on disk. In your .env file, you can add the path and password as variables.

WINDOWS_CERTIFICATE_FILE=the_password
WINDOWS_CERTIFICATE_PASSWORD=path/to/the-cert.p12

Code signing for Windows application

To sign an application for Windows on Mac OS, we can use the JSign tool. Download the jsign-3.1.jar file and place it in the folder where you build your application.

In the "win" part of package.json, we could see that we include a sign.js file.

"win": {
      "target": "nsis",
      "sign": "scripts/sign.js"
    }

sign.js

    exports.default = async function (configuration) {
    const { electronPlatformName, appOutDir, path } = configuration;

    // Filter other files that we don´t sign
    if (path.indexOf("The-app Setup") < 0) {
        return;
    }

    var pathLib = require('path');

    console.log('Custom sign...');
    const CERTIFICATE_NAME = process.env.WINDOWS_CERTIFICATE_FILE;
    const TOKEN_PASSWORD = process.env.WINDOWS_CERTIFICATE_PASSWORD;
    const CERT_ALIAS = 'cert-alias';
    const FILE_TO_SIGN = './dist/' + pathLib.basename(path);

    console.log(FILE_TO_SIGN);

    require("child_process").execSync(
        `java -jar ./jsign-3.1.jar --keystore ${CERTIFICATE_NAME} --storepass '${TOKEN_PASSWORD}' --storetype PKCS12 --tsaurl http://timestamp.digicert.com --alias ${CERT_ALIAS} '${FILE_TO_SIGN}'`,
        {
            stdio: "inherit"
        }
    );
};

Sign and notarize dmg file

For the .dmg file, we need to sign and notarize it with Apple. In the package.json notice:
That will make the the-app.dmg file notarized with apple.

"afterSign": "scripts/notarize.js"

notarize.js

require('dotenv').config();
const { notarize } = require('electron-notarize');

const buildOutput = require('path').resolve(
  __dirname,
  '..',
  'dist',
  'mac',
  'The-app.app'
);

exports.default = async function notarizing(context) {
  const { electronPlatformName, appOutDir } = context;  
  if (electronPlatformName !== 'darwin') {
    return;
  }

  console.log('Notarizing...');

  const appName = context.packager.appInfo.productFilename;

  return await notarize({
    appPath: buildOutput, //`${appOutDir}/${appName}.app`,
    appBundleId: 'com.electron.The-app',
    appleId: process.env.APPLEID,
    appleIdPassword: process.env.APPLEIDPASS,
    ascProvider: 'Organizational ID',
  });
};

This will make the the-app.dmg file notarized with apple.

Summary

In this article, we showed a quick overview of how to include extra resources, build and sign your Electron application for both Windows and Mac OS.

Using a setup like the one above makes it possible to build, sign, and publish on Windows and Mac OS from a Mac computer.