How to notarize electron app

Issue #430

Use electron builder

1
npm install electron-builder@latest --save-dev

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"name": "icon_generator",
"version": "1.3.0",
"description": "A macOS app to generate app icons",
"main": "babel/main.js",
"repository": "https://github.com/onmyway133/IconGenerator",
"author": "Khoa Pham",
"license": "MIT",
"scripts": {
"start": "npm run babel && electron .",
"babel": "babel ./src --out-dir ./babel --copy-files",
"dist": "npm run babel && electron-builder"
},
"build": {
"appId": "com.onmyway133.IconGenerator",
"buildVersion": "20",
"productName": "Icon Generator",
"icon": "./Icon/Icon.icns",
"mac": {
"category": "public.app-category.productivity",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "./entitlements.plist",
"entitlementsInherit": "./entitlements.plist"
},
"win": {
"target": "msi"
},
"linux": {
"target": [
"AppImage",
"deb"
]
},
"afterSign": "./afterSignHook.js"
}
}

Declare entitlements

entitlements.plist

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>

Use electron-notarize

afterSignHook.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const fs = require('fs');
const path = require('path');
var electron_notarize = require('electron-notarize');

module.exports = async function (params) {
// Only notarize the app on Mac OS only.
if (process.platform !== 'darwin') {
return;
}
console.log('afterSign hook triggered', params);

// Same appId in electron-builder.
let appId = 'com.onmyway133.IconGenerator'

let appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
if (!fs.existsSync(appPath)) {
throw new Error(`Cannot find application at: ${appPath}`);
}

console.log(`Notarizing ${appId} found at ${appPath}`);

try {
await electron_notarize.notarize({
appBundleId: appId,
appPath: appPath,
appleId: process.env.appleId,
appleIdPassword: process.env.appleIdPassword,
});
} catch (error) {
console.error(error);
}

console.log(`Done notarizing ${appId}`);
};

Run

Generate password for Apple Id because of 2FA

1
2
3
export appleId=onmyway133@gmail.com
export appleIdPassword=1234-abcd-efgh-7890
npm run dist

Check

1
spctl --assess --verbose Icon\ Generator.app

Troubleshooting

babel

  • Since electron-builder create dist folder for distribution, for example dist/mac/Icon Generator, I’ve renamed babel generated code to babel directory

babel 6 regeneratorRuntime is not defined

It is because of afterSignHook. Ignore in .babelrc not work

1
2
3
4
5
6
7
8
9
{
"plugins": [
"transform-react-jsx-source"
],
"presets": ["env", "react"],
"ignore": [
"afterSignHook.js"
]
}

Should use babel 7 with babel.config.js

1
2
npm install --save @babel/runtime 
npm install --save-dev @babel/plugin-transform-runtime

Use electron-forge

https://httptoolkit.tech/blog/notarizing-electron-apps-with-electron-forge/

Read more

Comments