By Steve Carey - Last updated June 20, 2023. Originally published Feb 4, 2020.
Example Code: Github electron-app-store-example
You have three options for distributing an Electron App for MacOS. Through the Mac App Store (MAS), through a third party platform like GitHub Marketplace, or directly (e.g, download from your website). Apple prefers you distribute through the Mac App Store. Partly because they review all apps before they can be put on the Mac App Store so end users can feel confident that the app is safe. And partly because they take a cut of app revenue purchased through the MAS. This tutorial focuses on the steps required to put your app on the MAS.
All apps distributed though the MAS must be sandboxed, meaning they are completely self contained except for any approved entitlements.
There are a few options for packaging the app. We will use Electron-Builder.
You will need to package two versions of your app. A development version for testing, and a distribution version for submission to Apple.
Apple Reference: developer.apple.com/app-store/review
developer.apple.com/app-store/review/guidelines
Electron Reference: electronjs.org/docs/tutorial/mac-app-store-submission-guide
Electron-builder Reference: electron.build/configuration/mac
and electron.build/configuration/mas
Electron should be a development dependency.
npm install -D electronYou need an Apple Developer Account. Costs ~$100/year. Sign up at developer.apple.com.
And sign up for the App Store's Small Business Program (for developers with revenue under $1 million/year):
developer.apple.com/app-store/small-business-program
If approved, Apple's commission drops from 30% to 15%.
- Apple Development: used to sign apps for development and testing on machines that have been registered on the Apple Developer website.
- Apple Distribution: used to sign apps submitted to the Mac App Store.
- Mac Installer Distribution: used to sign the Mac Installer Package in addition to the app itself.
You can create the signing certificates with either XCode or using the Keychain Access app.
Create and install these three certificates with XCode. Repeat the below process for each certificate.
Open XCode > Click the XCode menu > Select Preferences > Click Accounts > Click the Manage Certificates button > Click the + button in the lower left corner > Select the certificate type to create (Apple Development, Apple Distribution, Mac Installer Distribution).
Alternatively, you can create and install these three certificates with the Keychain Access app. Repeat the below two-step process for each certificate.
Keychain Access App - Step 2) Import the new certificate from your developer account to your Keychain:
- Platform: MacOS
- Bundle ID: Explicit. Apple recommends using a reverse-domain name style string (i.e., com.domainname.appname). This does not need to correspond with an actual website. This will need to match the appId property in the package.json file.
- When done click continue, review it, then click register.
Reference: developer.apple.com/help/app-store-connect
Official instructions for adding an app: developer.apple.com/help/app-store-connect/create-an-app-record/add-a-new-app
- Enter the name you want your app to appear on the Mac App Store as. Two apps can't have the same name so your preferred app name may be taken.
- Your app needs a privacy policy URL and (in another section) a support URL.
- Select the appropriate category for your app. See Category list.
- Add a license agreement. You can use Apple's Standard License Agreement apple.com/legal/internet-services/itunes/dev/stdeula
- Select the price you want to charge for your app. Be aware that Apple keeps 30%, or 15% if you enroll in the Small Business Program.
- You can also select specific countries to make your app available in. Default is the whole world.
- For marketing you can add up to 10 screenshots and up to 3 15-30 second videos. Be aware that these must be in specific dimensions.
- The App Store Icon is taken from your app's icon.icns file so you don't need to upload them separately.
- Enter the version number using semantic versioning (e.g., starting with 1.0.0).
- If your app requires any entitlements enter them here along with the explanation as to why you need that entitlement. The app will be rejected if you request entitlements you don't need. See the Entitlements section below for details.
- Enter the support URL (required) and a marketing URL (optional).
- When you upload your app (using the Transporter App - discussed below) you need to select it here.
- You can add attachments that may be useful to the reviewer such as a video of how to use the app (can be any dimensions).
Reference: electron.build/icons | developer.apple.com/design/human-interface-guidelines/app-icons
- Make a folder called icon.iconset (or any name that has .iconset as the extension) to hold the images.
- Use Apple's naming convention for the image files (e.g., icon_512x512.png, [email protected], etc.).
- The @2x files are double the size stated in terms of pixels. However in terms of display, Apple just doubles the density of the pixels instead of doubling the width and height. As such, some of the files will be the same image dimensions but two different files (e.g., [email protected] and icon_512x512.png are two separate files but are the same image size). If you are simplifying the images at smaller sizes, make sure the @2x image is the same as the 1x, just at double the size.
- When you get down to the small sizes such as icon_16x16.png you'll likely need to simplify the image, otherwise it will just look blurry.
- Convert the iconset into an icns file in the Terminal from the directory holding the icon.iconset folder with the png images. Enter the iconutil command:
iconutil -c icns icon.iconset- Put the resulting icon.icns file into the build folder of your electron project.
You can build a local version of your app not for distribution, by excluding the "mac" key from the package.json file. This will build a packaged version of your app, a zipped version, and a dmg installer. All are unsigned so they are cannot be distributed to other users that way.
The values in italics need to be changed to your info.
{
"name": "AppName",
"version": "1.0.0",
"scripts": {
"start": "electron .",
"dist": "electron-builder",
"postinstall": "electron-builder install-app-deps"
},
...
"author": "AuthorName",
"build": {
"appId": "com.companyname.appname",
"productName": "App Name (can include spaces & special characters)",
"buildVersion": "1.0.0",
"copyright": "Copyright © 2023 Developer or Company Name",
"files": [
"!file-or-directory-name-to-exclude"
]
}
...
}
This is a test version of the MAS build, which you can run on your development computer.
The values in italics need to be changed to your info.
{
"name": "AppName",
"version": "1.0.0",
"scripts": {
"start": "electron .",
"dist": "electron-builder",
"postinstall": "electron-builder install-app-deps"
},
...
"author": "AuthorName",
"build": {
"appId": "com.companyname.appname",
"productName": "App Name (can include spaces & special characters)",
"buildVersion": "1.0.0",
"copyright": "Copyright © 2023 Developer or Company Name",
"files": [
"!file-or-directory-name-to-exclude"
],
"mac": {
"category": "public.app-category.categoryName",
"icon": "build/icon.icns",
"target": "mas-dev",
"type": "development",
"hardenedRuntime": false,
"provisioningProfile": "build/AppleDevelopment.provisionprofile",
"entitlements": "build/entitlements.mas.plist",
"entitlementsInherit": "build/entitlements.mas.inherit.plist"
}
}
...
}
This builds a pkg installer for submission to the MAS. It changes the target, type, and provisioningProfile from 7b above.
The values in italics need to be changed to your info.
{
"name": "AppName",
"version": "1.0.0",
"scripts": {
"start": "electron .",
"dist": "electron-builder",
"postinstall": "electron-builder install-app-deps"
},
...
"author": "AuthorName",
"build": {
"appId": "com.companyname.appname",
"productName": "App Name (can include spaces & special characters)",
"buildVersion": "1.0.0",
"copyright": "Copyright © 2023 Developer or Company Name",
"files": [
"!file-or-directory-name-to-exclude"
],
"mac": {
"category": "public.app-category.categoryName",
"icon": "build/icon.icns",
"target": "mas",
"type": "distribution",
"hardenedRuntime": false,
"provisioningProfile": "build/MacAppStore.provisionprofile",
"entitlements": "build/entitlements.mas.plist",
"entitlementsInherit": "build/entitlements.mas.inherit.plist"
}
}
...
}
Only include the postinstall script above if you have native dependencies that need to be recompiled by Electron (see Native Node NPM packages at the bottom).
Reference:package.json keys:
Keys you don't need to set because the default is already correct:
Reference: electronjs.org/docs/tutorial/mac-app-store-submission-guide
<?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.app-sandbox</key><true/>
<key>com.apple.security.application-groups</key>
<array>
<string>TEAM_ID.com.companyname.appname</string>
</array>
<!-- Put any entitlements your app requires here. Below is an example -->
<key>com.apple.security.files.user-selected.read-write</key><true/>
</dict>
</plist>
/build/entitlements.mas.inherit.plist
<?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.app-sandbox</key><true/>
<key>com.apple.security.inherit</key><true/>
</dict>
</plist>
security cms -D -i build/AppleDevelopment.provisionprofilesecurity cms -D -i build/MacAppStore.provisionprofilenpm install -D electron-builder
npm run dist
npm run dist
If you get a "command not found" error, then include the relative path. Here are the direct commands with the path:
Mac: ./node_modules/.bin/electron-builder
Windows: .\node_modules\.bin\electron-builder.cmd
Test the Development version of the app before building the distribution version. Make sure it works as expected.
Then build the distribution version. This version will crash and give you a signing error if you try to open it on your computer. It must be re-signed by Apple to be able to run, which will only be possible after being downloaded from the Mac App Store. However, there are some checks you can make before submitting it to Apple.
codesign --display --verbose=2 MyApp.apppkgutil --check-signature MyApp-1.0.0.pkgReference: electronjs.org/docs/latest/tutorial/using-native-node-modules
Native node modules are npm packages that include C or C++ code.
C/C++ code must be compiled into executable binaries. Even if the modules are precompiled when installed, they must be recompiled for Electron. Electron-builder will do that automatically when you run the electron-builder script npm run dist.
To recompile native modules in development, you can add the below script to your package.json file:
"postinstall": "electron-builder install-app-deps"
Then after installing native modules, run the script: npm run postinstall
If you don't recompile native modules, and try to run the app, you will get an error that says something like:
Error: The module '/path/to/native/module.node' was compiled against a different Node.js version using NODE_MODULE_VERSION $XYZ. This version of Node.js requires NODE_MODULE_VERSION $ABC. Please try re-compiling or re-installing the module (for instance, using `npm rebuild` or `npm install`).
Native modules must be pulled out of your built binary app and code signed separately. This is done automatically by electron-builder.