From 8b932531b22e932629f3e40a70e2b488e482a2a9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 Dec 2025 15:06:42 +1000 Subject: [PATCH 1/8] Add Mac Store guide --- SUMMARY.md | 1 + guides/mac-store.md | 259 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 guides/mac-store.md diff --git a/SUMMARY.md b/SUMMARY.md index 6a8685c..24b932a 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -61,6 +61,7 @@ * [React with TypeScript](guides/framework-integration/react-with-typescript.md) * [Vue 3](guides/framework-integration/vue-3.md) * [Developing with WSL](guides/developing-with-wsl.md) +* [Mac and Windows Distribution](guides/mac-store.md) ## Advanced diff --git a/guides/mac-store.md b/guides/mac-store.md new file mode 100644 index 0000000..9f36109 --- /dev/null +++ b/guides/mac-store.md @@ -0,0 +1,259 @@ +--- +description: 'This is a step-by-step guide to distributing your app either inside or outside of the Mac App Store, or to the Windows Store' +--- + +# Mac and Windows Distribution + +Follow the documentation on how to add Electron Forge to your project. This is fairly straight-forward, so I won't go into it. + +Once this is done, a ```forge.config.js``` file will be in your project's root folder. You can convert this to ESM syntax if you want, but if you are creating a universal application, your project will have to be converted back into CJS for the final publishing step as this part of the Electron Forge toolchain does not yet support ESM. + +```js + const config = { + asar: true, + appBundleId: 'com.example.appname', + appVersion: '1.0.0', + buildVersion: '1.0.0', + icon: './app' + } + ``` + +```appBundleId```: At some point, you need to sign up for an Apple Developer Account and create an app. This is where you create a bundle Id that you then provide to Forge in this field. + +```buildVersion```: This needs to be incremented each time you upload the app to Apple. + +```icon```: You can find templates online that provide the right dimensions for the Mac app icon. You need to create rounded corners and provide some space around the icon. + +## Signing Configuration + +If you want to submit your app to the Mac App Store, you will need to create the following certificates: + +- Apple Development +- Apple Distribution +- Mac Installer Distribution + +If you want to distribution your app outside of the App Store, you will need the following certificates: + +- Developer ID Application +- Developer ID Installer + +All of these certificates should be created through Xcode after you have signed up for an Apple Developer Account. If you have created them any other way, you will have to delete them. + +Once you have created these certificates, you need to go to your Apple Developer Account and create provisioning profiles. If you are submiting your app to the app store, you will need a development profile and a distribution profile. If you are submiting it outside of the app store, you will need a profile for the ```Developer ID Application``` certificate. + +You need to download these after creating them and double clicking them to install them on your computer. Not all of them can be installed locally, but just double-click on them anyway. + +Back to the config: + +```js +const osxSign = { + binaries: [ + './resources/bin/ffmpeg_intel_mac', + './resources/bin/ffmpeg_mac' + ], + identity: 'Apple Development', + platform: 'mas', + type: 'development', + provisioningProfile: 'development.provisionprofile', + optionsForFile: (filePath) => { + const entitlements = filePath.includes('.app/') ? 'entitlements.child.plist' : 'entitlements.plist'; + return { + hardenedRuntime: false, + entitlements + } + } +} +``` + +```binaries```: if your electron app calls any binaries, they need to be listed here so that they can be signed. + +```identity```: the name of the certificate. + +- App store development: Apple Development +- App store distribution: Apple Distribution: FirstName LastName (TEAMID) +- Outside distribution: Developer ID Application: FirstName LastName (TEAMID) + +```platform```: for the app store it is ```mas``` and for outside the app store it is ```darwin``` + +```provisioningProfile```: the appropriate provisioning profile, as mentioned earlier. + +```optionsForFile```: for distribution outside of the app store, you may be able to rely on the defaults if you app doesn't need any extra entitlements. For the app store, you will definitely need to provide this. + +The documentation fails to mention that you need to add logic to determine which set of entitlements to use. If you specify more entitlements then your app uses, it will probably be rejected by the review process. + +For submission to the app store, ```hardenedRuntime``` should be false, but for distribution outside of the app store, it should be true. + +Here is an example main entitlements file. Add or remove entitlements depending on the needs of your app. + +```xml + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-write + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.network.client + + com.apple.security.print + + com.apple.security.device.usb + + com.apple.security.files.downloads.read-write + + + +``` + +Here is an example child entitlements file. + +```xml + + + + + com.apple.security.app-sandbox + + com.apple.security.inherit + + + +``` + +Forge will add additional keys related to your provisioning profile. You should remove the ```app-sandbox``` key in both files when creating the set of entitlements you want to use outside of the app store, as that version does not run in a sandbox. + +For distribution outside of the app store, you will need to add ```osxNotarize``` to the packager config section. + +```js +const osxNotarize = { + tool: 'notarytool', + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_ID_PASSWORD, + teamId: process.env.TEAM_ID +} +``` + +```appleId```: usually the email address you used to create your Apple account. + +```appleIdPassword```: a one-time password you can create. This is mentioned in the documentation. You create it via the Apple Developer website or something like that. + +```teamId```: that set of characters inside the brackets at the end of your identity name. + +## Other Packager Configuration + +```js +const other = { + platform: 'mas', + osxUniversal: { + x64ArchFiles: '*_mac' + }, + extraResource: [ + './resources/bin', + './resources/app.db' + ], + appCategoryType: 'public.app-category.utilities' +}; +``` + +```platform```: same as inside the ```osxSign``` configuration. + +```osxUniversal```: only necessary if you have a mixture of intel and apple silicon binary files. You can avoid this by using ```lipo``` to combine these binaries into a single file if you want. + +```extraResources```: files that you want to copy across to the ```resources``` folder of the containerized environment. + +```appCategoryType```: The category that is appropriate for your application. + +## Other Configuration + +After the packager configuration, there is the ```maker``` configuration and some types of configuration that you can just leave as they are unless you have a use for them. + +I don't think you need any makers just for testing. Maybe add this if nothing is created. + +```js +const makers = [ + { + name: '@electron-forge/maker-zip', + platforms: ['mas'], + } +]; +``` + +For distribution on the mac store you need to create a ```pkg``` file, so you can use this configuration: + +```js +const makers = [ + { + name: '@electron-forge/maker-pkg', + platform: ['mas'], + config: { + identity: '3rd Party Mac Developer Installer: FirstName LastName (TEAMID)' + } + } +]; +``` + +For distribution outside of the app store, you should create a ```dmg``` file using this configuration: + +```js +const makers = [ + { + name: '@electron-forge/maker-dmg', + config: { + format: 'ULFO' + } + } +]; +``` + +For Windows, you don't need to do any of the above steps related to signing. You just have to add a maker like this: + +```js +const makers = [ + { + name: '@electron-forge/maker-appx', + config: { + publisher: 'CN=UUID', + publisherDisplayName: 'CompanyName', + displayName: 'AppName', + version: '1.0.0', + identityName: 'CompanyName.AppName' + } + } +]; +``` + +The uuid in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. The only trick is that Windows doesn't like dashes in any file or folder names. + +## Package Configuration + +Inside your ```package.json``` you might need to add a ```productName``` field. Here are some of the fields I have added, beyond what is already in the standard file. + +```json +{ + "productName": "AppName", + "scripts": { + "build": "./node_modules/.bin/esbuild main.js --bundle --platform=node --format=cjs --packages=external --outfile=bundle.js", + "mac": "npm run make -- --arch=universal --platform=darwin", + "mas": "npm run make -- --arch=universal --platform=mas" + } +} +``` + +```npm run mac``` will create a ```dmg``` file for distribution outside of the app store, and ```npm run mas``` will create a ```pkg``` file for distribution inside the app store, assuming you have used the appropriate forge configuration. For testing, you don't need to use any of the ```makers``` so you can just use ```npm run package```. + +## Testing and Submission + +To test your application before submitting it to the app store, you need to make sure you are actually running inside an app store sandbox, and not just running like a normal mac application. + +App containers are located in ```~/Library/Containers```. If there is not a folder named after your app there, then your app is not running inside a container and therefore you have messed up one of the steps in the configuration section. + +Before packaging your application, you should also check that every file has user read permissions, and that every folder has user read and user execute permissions. Every binary should have user read and user execute permissions as well. + +You will also need a working help section in the menu of your app. The help section can link to a website. The electron documentation provides a basic template that you can copy and paste to make sure you have the right menu items. You just need to fix up the help section. + +If your app only has one window, the app should close completely when the window is closed. + +Once everything is ready, you need to download Transporter from the mac app store and upload your ```pkg``` file. From b300fbd84c3f5d23abc90e33eb2470a6ed4ec8fe Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 13:43:28 +1000 Subject: [PATCH 2/8] spread --- config/makers/appx.md | 10 +- config/makers/pkg.md | 4 +- guides/code-signing/code-signing-macos.md | 131 +++++++++--- guides/mac-store.md | 233 ++++------------------ 4 files changed, 150 insertions(+), 228 deletions(-) diff --git a/config/makers/appx.md b/config/makers/appx.md index 2517dd1..e9034c7 100644 --- a/config/makers/appx.md +++ b/config/makers/appx.md @@ -29,9 +29,11 @@ module.exports = { { name: '@electron-forge/maker-appx', config: { - publisher: 'CN=developmentca', - devCert: 'C:\\devcert.pfx', - certPass: 'abcd' + publisher: 'CN=UUID', + publisherDisplayName: 'CompanyName', + displayName: 'AppName', + version: '1.0.0', + identityName: 'CompanyName.AppName' } } ] @@ -39,6 +41,8 @@ module.exports = { ``` {% endcode %} +The UUID in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. The only trick is that Windows doesn't like dashes in any file or folder names. + Configuration options are documented in [`MakerAppXConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_appx.MakerAppXConfig.html). ## Debugging diff --git a/config/makers/pkg.md b/config/makers/pkg.md index 63bf0aa..46349c1 100644 --- a/config/makers/pkg.md +++ b/config/makers/pkg.md @@ -35,9 +35,9 @@ module.exports = { makers: [ { name: '@electron-forge/maker-pkg', + platform: ['mas'], config: { - keychain: 'my-secret-ci-keychain' - // other configuration options + identity: '3rd Party Mac Developer Installer: FirstName LastName (TEAMID)' } } ] diff --git a/guides/code-signing/code-signing-macos.md b/guides/code-signing/code-signing-macos.md index 7e68047..d011a1d 100644 --- a/guides/code-signing/code-signing-macos.md +++ b/guides/code-signing/code-signing-macos.md @@ -29,12 +29,18 @@ Although Electron does not integrate tightly with the IDE itself, Xcode is a hel Code signing certificates for macOS apps can only be obtained through Apple by purchasing a membership to the [Apple Developer Program](https://developer.apple.com/programs/). -To sign Electron apps, you may require two separate certificates: +If you want to submit your app to the Mac App Store, you will need to create the following certificates: -* The **Developer ID Installer** certificate is for apps distributed to the Mac App Store. -* The **Developer ID Application** certificate is for apps distributed outside the Mac App Store. +- Apple Development +- Apple Distribution +- Mac Installer Distribution -Once you have an Apple Developer Program membership, you first need to install them onto your machine. We recommend [loading them through Xcode](https://help.apple.com/xcode/mac/current/#/dev3a05256b8). +If you want to distribution your app outside of the App Store, you will need the following certificates: + +- Developer ID Application +- Developer ID Installer + +All of these certificates should be created through Xcode after you have signed up for an Apple Developer Account. If you have created them any other way, you will have to delete them. {% hint style="success" %} **Verifying your certificate is installed** @@ -46,6 +52,12 @@ security find-identity -p codesigning -v ``` {% endhint %} +### Creating provisioning profiles + +Once you have created the certificates, you need to go to your Apple Developer Account and create provisioning profiles. If you are submiting your app to the app store, you will need a development profile and a distribution profile. If you are submiting it outside of the app store, you will need a profile for the ```Developer ID Application``` certificate. + +You need to download these after creating them and double clicking them to install them on your computer. Not all of them can be installed locally, but just double-click on them anyway. + ## Configuring Forge In Electron Forge, macOS apps are signed and notarized at the **Package** step by the `electron-packager` library. There is a separate option within your Forge `packagerConfig` for each one of these settings. @@ -62,44 +74,98 @@ To enable code signing on macOS, ensure that `packagerConfig.osxSign` exists in ```javascript module.exports = { packagerConfig: { - osxSign: {} // object must exist even if empty + osxSign: { + binaries: [ + './resources/bin/ffmpeg_intel_mac', + './resources/bin/ffmpeg_mac' + ], + identity: 'Apple Development', + platform: 'mas', + type: 'development', + provisioningProfile: 'development.provisionprofile', + optionsForFile: (filePath) => { + const entitlements = filePath.includes('.app/') ? 'entitlements.child.plist' : 'entitlements.plist'; + return { + hardenedRuntime: false, + entitlements + } + } + } } }; ``` {% endcode %} -The `osxSign` config comes with defaults that work out of the box in most cases, so we recommend you start with an empty configuration object. +```binaries```: if your electron app calls any binaries, they need to be listed here so that they can be signed. -For a full list of configuration options, see the [`OsxSignOptions`](https://js.electronforge.io/modules/\_electron\_forge\_shared\_types.InternalOptions.html#OsxSignOptions) type in the Forge API docs. For more detailed information on how to configure these options, see the [`@electron/osx-sign` documentation](https://github.com/electron/osx-sign). +```identity```: the name of the certificate. -#### Customizing entitlements +- App store development: Apple Development +- App store distribution: Apple Distribution: FirstName LastName (TEAMID) +- Outside distribution: Developer ID Application: FirstName LastName (TEAMID) -A common use case for modifying the default `osxSign` configuration is to customize its entitlements. In macOS, **entitlements** are privileges that grant apps certain capabilities (e.g. access to the camera, microphone, or USB devices). These are stored within the code signature in an app's executable file. +```platform```: for the app store it is ```mas``` and for outside the app store it is ```darwin``` -By default, the `@electron/osx-sign` tool comes with a set of entitlements that should work on both MAS or direct distribution targets. See the complete set of default entitlement files [on GitHub](https://github.com/electron/osx-sign/tree/main/entitlements). +```provisioningProfile```: the appropriate provisioning profile, as mentioned earlier. -{% code title="forge.config.js" %} -```javascript -module.exports = { - // ... - packagerConfig: { - // ... - osxSign: { - optionsForFile: (filePath) => { - // Here, we keep it simple and return a single entitlements.plist file. - // You can use this callback to map different sets of entitlements - // to specific files in your packaged app. - return { - entitlements: 'path/to/entitlements.plist' - }; - } - } - } - // ... -}; +```optionsForFile```: for distribution outside of the app store, you may be able to rely on the defaults if you app doesn't need any extra entitlements. For the app store, you will definitely need to provide this. + +You need to add logic to determine which set of entitlements to use. If you specify more entitlements then your app uses, it will probably be rejected by the review process. + +For submission to the app store, ```hardenedRuntime``` should be false, but for distribution outside of the app store, it should be true. + +For a full list of configuration options, see the [`OsxSignOptions`](https://js.electronforge.io/modules/\_electron\_forge\_shared\_types.InternalOptions.html#OsxSignOptions) type in the Forge API docs. For more detailed information on how to configure these options, see the [`@electron/osx-sign` documentation](https://github.com/electron/osx-sign). + +#### Entitlements + +In macOS, **entitlements** are privileges that grant apps certain capabilities (e.g. access to the camera, microphone, or USB devices). These are stored within the code signature in an app's executable file. + +Here is an example main entitlements file. Add or remove entitlements depending on the needs of your app. + +{% code title="entitlements.plist" %} +```xml + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-write + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.network.client + + com.apple.security.print + + com.apple.security.device.usb + + com.apple.security.files.downloads.read-write + + + +``` +{% endcode %} + +Here is an example child entitlements file. + +{% code title="entitlements.child.plist" %} +```xml + + + + + com.apple.security.app-sandbox + + com.apple.security.inherit + + + ``` {% endcode %} +Forge will add additional keys related to your provisioning profile. You should remove the ```app-sandbox``` key in both files when creating the set of entitlements you want to use outside of the app store, as that version does not run in a sandbox. + For further reading on entitlements, see the following pages in Apple developer documentation: * [Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) @@ -225,6 +291,7 @@ module.exports = { packagerConfig: { osxSign: {}, osxNotarize: { + tool: 'notarytool', appleId: process.env.APPLE_ID, appleIdPassword: process.env.APPLE_PASSWORD, teamId: process.env.APPLE_TEAM_ID @@ -233,3 +300,9 @@ module.exports = { }; ``` {% endcode %} + +```appleId```: usually the email address you used to create your Apple account. + +```appleIdPassword```: a one-time password you can create. This is mentioned in the documentation. You create it via the Apple Developer website or something like that. + +```teamId```: that set of characters inside the brackets at the end of your identity name. diff --git a/guides/mac-store.md b/guides/mac-store.md index 9f36109..7509d4c 100644 --- a/guides/mac-store.md +++ b/guides/mac-store.md @@ -1,22 +1,36 @@ --- -description: 'This is a step-by-step guide to distributing your app either inside or outside of the Mac App Store, or to the Windows Store' +description: 'This is a step-by-step guide to distributing your app via the Mac App Store' --- -# Mac and Windows Distribution +# App Store Follow the documentation on how to add Electron Forge to your project. This is fairly straight-forward, so I won't go into it. Once this is done, a ```forge.config.js``` file will be in your project's root folder. You can convert this to ESM syntax if you want, but if you are creating a universal application, your project will have to be converted back into CJS for the final publishing step as this part of the Electron Forge toolchain does not yet support ESM. +{% code title="forge.config.js" %} ```js - const config = { +module.exports = { + packagerConfig: { asar: true, appBundleId: 'com.example.appname', appVersion: '1.0.0', buildVersion: '1.0.0', - icon: './app' - } + icon: './app', + osxSign: {}, + platform: 'mas', + osxUniversal: { + x64ArchFiles: '*_mac' + }, + extraResource: [ + './resources/bin', + './resources/app.db' + ], + appCategoryType: 'public.app-category.utilities' + } +} ``` +{% endcode %} ```appBundleId```: At some point, you need to sign up for an Apple Developer Account and create an app. This is where you create a bundle Id that you then provide to Forge in this field. @@ -24,139 +38,7 @@ Once this is done, a ```forge.config.js``` file will be in your project's root f ```icon```: You can find templates online that provide the right dimensions for the Mac app icon. You need to create rounded corners and provide some space around the icon. -## Signing Configuration - -If you want to submit your app to the Mac App Store, you will need to create the following certificates: - -- Apple Development -- Apple Distribution -- Mac Installer Distribution - -If you want to distribution your app outside of the App Store, you will need the following certificates: - -- Developer ID Application -- Developer ID Installer - -All of these certificates should be created through Xcode after you have signed up for an Apple Developer Account. If you have created them any other way, you will have to delete them. - -Once you have created these certificates, you need to go to your Apple Developer Account and create provisioning profiles. If you are submiting your app to the app store, you will need a development profile and a distribution profile. If you are submiting it outside of the app store, you will need a profile for the ```Developer ID Application``` certificate. - -You need to download these after creating them and double clicking them to install them on your computer. Not all of them can be installed locally, but just double-click on them anyway. - -Back to the config: - -```js -const osxSign = { - binaries: [ - './resources/bin/ffmpeg_intel_mac', - './resources/bin/ffmpeg_mac' - ], - identity: 'Apple Development', - platform: 'mas', - type: 'development', - provisioningProfile: 'development.provisionprofile', - optionsForFile: (filePath) => { - const entitlements = filePath.includes('.app/') ? 'entitlements.child.plist' : 'entitlements.plist'; - return { - hardenedRuntime: false, - entitlements - } - } -} -``` - -```binaries```: if your electron app calls any binaries, they need to be listed here so that they can be signed. - -```identity```: the name of the certificate. - -- App store development: Apple Development -- App store distribution: Apple Distribution: FirstName LastName (TEAMID) -- Outside distribution: Developer ID Application: FirstName LastName (TEAMID) - -```platform```: for the app store it is ```mas``` and for outside the app store it is ```darwin``` - -```provisioningProfile```: the appropriate provisioning profile, as mentioned earlier. - -```optionsForFile```: for distribution outside of the app store, you may be able to rely on the defaults if you app doesn't need any extra entitlements. For the app store, you will definitely need to provide this. - -The documentation fails to mention that you need to add logic to determine which set of entitlements to use. If you specify more entitlements then your app uses, it will probably be rejected by the review process. - -For submission to the app store, ```hardenedRuntime``` should be false, but for distribution outside of the app store, it should be true. - -Here is an example main entitlements file. Add or remove entitlements depending on the needs of your app. - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-write - - com.apple.security.files.bookmarks.app-scope - - com.apple.security.network.client - - com.apple.security.print - - com.apple.security.device.usb - - com.apple.security.files.downloads.read-write - - - -``` - -Here is an example child entitlements file. - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -Forge will add additional keys related to your provisioning profile. You should remove the ```app-sandbox``` key in both files when creating the set of entitlements you want to use outside of the app store, as that version does not run in a sandbox. - -For distribution outside of the app store, you will need to add ```osxNotarize``` to the packager config section. - -```js -const osxNotarize = { - tool: 'notarytool', - appleId: process.env.APPLE_ID, - appleIdPassword: process.env.APPLE_ID_PASSWORD, - teamId: process.env.TEAM_ID -} -``` - -```appleId```: usually the email address you used to create your Apple account. - -```appleIdPassword```: a one-time password you can create. This is mentioned in the documentation. You create it via the Apple Developer website or something like that. - -```teamId```: that set of characters inside the brackets at the end of your identity name. - -## Other Packager Configuration - -```js -const other = { - platform: 'mas', - osxUniversal: { - x64ArchFiles: '*_mac' - }, - extraResource: [ - './resources/bin', - './resources/app.db' - ], - appCategoryType: 'public.app-category.utilities' -}; -``` +```osxSign```: The code signing configuration. Following the instructions [here](code-signing/code-signing-macos.md) ```platform```: same as inside the ```osxSign``` configuration. @@ -170,79 +52,42 @@ const other = { After the packager configuration, there is the ```maker``` configuration and some types of configuration that you can just leave as they are unless you have a use for them. -I don't think you need any makers just for testing. Maybe add this if nothing is created. - -```js -const makers = [ - { - name: '@electron-forge/maker-zip', - platforms: ['mas'], - } -]; -``` - -For distribution on the mac store you need to create a ```pkg``` file, so you can use this configuration: - -```js -const makers = [ - { - name: '@electron-forge/maker-pkg', - platform: ['mas'], - config: { - identity: '3rd Party Mac Developer Installer: FirstName LastName (TEAMID)' - } - } -]; -``` - -For distribution outside of the app store, you should create a ```dmg``` file using this configuration: - -```js -const makers = [ - { - name: '@electron-forge/maker-dmg', - config: { - format: 'ULFO' - } - } -]; -``` - -For Windows, you don't need to do any of the above steps related to signing. You just have to add a maker like this: +I don't think you need any makers just for testing. Maybe add the ```zip``` maker if nothing is created. For distribution on the Mac store you need to create a ```pkg``` file. +{% code title="forge.config.js" %} ```js -const makers = [ - { - name: '@electron-forge/maker-appx', - config: { - publisher: 'CN=UUID', - publisherDisplayName: 'CompanyName', - displayName: 'AppName', - version: '1.0.0', - identityName: 'CompanyName.AppName' +module.exports = { + packagerConfig: {}, + makers: [ + { + name: '@electron-forge/maker-pkg', + platform: ['mas'], + config: { + identity: '3rd Party Mac Developer Installer: FirstName LastName (TEAMID)' + } } - } -]; -``` - -The uuid in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. The only trick is that Windows doesn't like dashes in any file or folder names. + ] +} + ``` +{% endcode %} ## Package Configuration -Inside your ```package.json``` you might need to add a ```productName``` field. Here are some of the fields I have added, beyond what is already in the standard file. +Inside your ```package.json``` you might need to add a ```productName``` field. The scripts mentioned below can help you bundle and package your code. +{% code title="package.json" %} ```json { "productName": "AppName", "scripts": { "build": "./node_modules/.bin/esbuild main.js --bundle --platform=node --format=cjs --packages=external --outfile=bundle.js", - "mac": "npm run make -- --arch=universal --platform=darwin", "mas": "npm run make -- --arch=universal --platform=mas" } } ``` +{% endcode %} -```npm run mac``` will create a ```dmg``` file for distribution outside of the app store, and ```npm run mas``` will create a ```pkg``` file for distribution inside the app store, assuming you have used the appropriate forge configuration. For testing, you don't need to use any of the ```makers``` so you can just use ```npm run package```. +```npm run mas``` will create a ```pkg``` file for distribution inside the app store, assuming you have used the appropriate forge configuration. For testing, you don't need to use any of the ```makers``` so you can just use ```npm run package```. ## Testing and Submission From 34f6e65ba88086833ccc468d3d65302320a9b65d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 15:31:26 +1000 Subject: [PATCH 3/8] bug --- SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.md b/SUMMARY.md index 24b932a..9235b31 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -61,7 +61,7 @@ * [React with TypeScript](guides/framework-integration/react-with-typescript.md) * [Vue 3](guides/framework-integration/vue-3.md) * [Developing with WSL](guides/developing-with-wsl.md) -* [Mac and Windows Distribution](guides/mac-store.md) +* [App Store](guides/mac-store.md) ## Advanced From f4dcf49de9b1906e9b5fe2f89ceaf35911a76284 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 15:44:40 +1000 Subject: [PATCH 4/8] bugs --- config/makers/appx.md | 6 +++++- guides/mac-store.md | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/makers/appx.md b/config/makers/appx.md index e9034c7..3ee9560 100644 --- a/config/makers/appx.md +++ b/config/makers/appx.md @@ -41,7 +41,11 @@ module.exports = { ``` {% endcode %} -The UUID in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. The only trick is that Windows doesn't like dashes in any file or folder names. +The UUID in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. + +{% hint style="info" %} +Windows does not like dashes in any file or folder names. +{% endhint %} Configuration options are documented in [`MakerAppXConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_appx.MakerAppXConfig.html). diff --git a/guides/mac-store.md b/guides/mac-store.md index 7509d4c..93112c8 100644 --- a/guides/mac-store.md +++ b/guides/mac-store.md @@ -101,4 +101,4 @@ You will also need a working help section in the menu of your app. The help sect If your app only has one window, the app should close completely when the window is closed. -Once everything is ready, you need to download Transporter from the mac app store and upload your ```pkg``` file. +Once everything is ready, you need to download Transporter from the Mac App Store and upload your ```pkg``` file. From 78952d11a044e7be061bd6cc5db0dbfb40d0d4fe Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 16:47:24 +1000 Subject: [PATCH 5/8] bug --- config/makers/appx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/makers/appx.md b/config/makers/appx.md index 3ee9560..acadf39 100644 --- a/config/makers/appx.md +++ b/config/makers/appx.md @@ -44,7 +44,7 @@ module.exports = { The UUID in the ```publisher``` field can be found on the Microsoft website that you use to create the app listing. {% hint style="info" %} -Windows does not like dashes in any file or folder names. +Windows does not like dashes in file or folder names. {% endhint %} Configuration options are documented in [`MakerAppXConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_appx.MakerAppXConfig.html). From fdd40c691615f683b32f4c09e3d736c6c369ed4a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 16:55:16 +1000 Subject: [PATCH 6/8] bug --- guides/code-signing/code-signing-macos.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/guides/code-signing/code-signing-macos.md b/guides/code-signing/code-signing-macos.md index d011a1d..db11745 100644 --- a/guides/code-signing/code-signing-macos.md +++ b/guides/code-signing/code-signing-macos.md @@ -193,9 +193,9 @@ There are two mandatory fields for `osxNotarize` if you are using this strategy: | Field | Type | Description | | ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `appleId` | string | Apple ID associated with your Apple Developer account | -| `appleIdPassword` | string | App-specific password | -| `teamId` | string | The Apple Team ID you want to notarize under. You can find Team IDs for team you belong to by going to [`https://developer.apple.com/account/#/membership`](https://developer.apple.com/account/#/membership) | +| `appleId` | string | usually the email address you used to create your Apple Developer account. | +| `appleIdPassword` | string | a one-time password that can be create via the Apple Developer website. | +| `teamId` | string | The Apple Team ID you want to notarize under. It is the set of characters inside the brackets at the end of your identity name. | {% code title="forge.config.js" %} ```javascript @@ -204,6 +204,7 @@ module.exports = { packagerConfig: { // ... osxNotarize: { + tool: 'notarytool', appleId: process.env.APPLE_ID, appleIdPassword: process.env.APPLE_PASSWORD, teamId: process.env.APPLE_TEAM_ID @@ -300,9 +301,3 @@ module.exports = { }; ``` {% endcode %} - -```appleId```: usually the email address you used to create your Apple account. - -```appleIdPassword```: a one-time password you can create. This is mentioned in the documentation. You create it via the Apple Developer website or something like that. - -```teamId```: that set of characters inside the brackets at the end of your identity name. From 417ff35d1dd9e6fa4da35e1774208a3d07c51d21 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 17 Dec 2025 16:55:56 +1000 Subject: [PATCH 7/8] bug --- guides/code-signing/code-signing-macos.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/code-signing/code-signing-macos.md b/guides/code-signing/code-signing-macos.md index db11745..331f424 100644 --- a/guides/code-signing/code-signing-macos.md +++ b/guides/code-signing/code-signing-macos.md @@ -193,8 +193,8 @@ There are two mandatory fields for `osxNotarize` if you are using this strategy: | Field | Type | Description | | ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `appleId` | string | usually the email address you used to create your Apple Developer account. | -| `appleIdPassword` | string | a one-time password that can be create via the Apple Developer website. | +| `appleId` | string | Usually the email address you used to create your Apple Developer account. | +| `appleIdPassword` | string | A one-time password that can be create via the Apple Developer website. | | `teamId` | string | The Apple Team ID you want to notarize under. It is the set of characters inside the brackets at the end of your identity name. | {% code title="forge.config.js" %} From 342aa6028fcbc463c6f2a267bb80384341d3da78 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 18 Dec 2025 12:40:33 +1000 Subject: [PATCH 8/8] final --- guides/code-signing/code-signing-macos.md | 4 ++-- guides/mac-store.md | 20 +++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/guides/code-signing/code-signing-macos.md b/guides/code-signing/code-signing-macos.md index 331f424..4f1ac50 100644 --- a/guides/code-signing/code-signing-macos.md +++ b/guides/code-signing/code-signing-macos.md @@ -54,7 +54,7 @@ security find-identity -p codesigning -v ### Creating provisioning profiles -Once you have created the certificates, you need to go to your Apple Developer Account and create provisioning profiles. If you are submiting your app to the app store, you will need a development profile and a distribution profile. If you are submiting it outside of the app store, you will need a profile for the ```Developer ID Application``` certificate. +Once you have created the certificates, you need to go to your Apple Developer Account and create provisioning profiles. If you are submiting your app to the app store, you will need a Development profile and a Distribution profile. If you are submiting it outside of the app store, you will need a profile for the ```Developer ID Application``` certificate. You need to download these after creating them and double clicking them to install them on your computer. Not all of them can be installed locally, but just double-click on them anyway. @@ -110,7 +110,7 @@ module.exports = { ```optionsForFile```: for distribution outside of the app store, you may be able to rely on the defaults if you app doesn't need any extra entitlements. For the app store, you will definitely need to provide this. -You need to add logic to determine which set of entitlements to use. If you specify more entitlements then your app uses, it will probably be rejected by the review process. +Your list of entitlements should contain only the ones your application needs. Adding extraneous entitlements could be cause for rejection during the review process. For submission to the app store, ```hardenedRuntime``` should be false, but for distribution outside of the app store, it should be true. diff --git a/guides/mac-store.md b/guides/mac-store.md index 93112c8..9794d86 100644 --- a/guides/mac-store.md +++ b/guides/mac-store.md @@ -4,9 +4,7 @@ description: 'This is a step-by-step guide to distributing your app via the Mac # App Store -Follow the documentation on how to add Electron Forge to your project. This is fairly straight-forward, so I won't go into it. - -Once this is done, a ```forge.config.js``` file will be in your project's root folder. You can convert this to ESM syntax if you want, but if you are creating a universal application, your project will have to be converted back into CJS for the final publishing step as this part of the Electron Forge toolchain does not yet support ESM. +Follow the documentation on how to add Electron Forge to your project so that a ```forge.config.js``` file is created in your project's root folder. You can convert this to ESM syntax if you want, but if you are creating a universal application, your project will have to be converted back into CJS for the final publishing step as this part of the Electron Forge toolchain does not yet support ESM. {% code title="forge.config.js" %} ```js @@ -32,7 +30,7 @@ module.exports = { ``` {% endcode %} -```appBundleId```: At some point, you need to sign up for an Apple Developer Account and create an app. This is where you create a bundle Id that you then provide to Forge in this field. +```appBundleId```: When you create an app from within the Apple Developer website, you will be asked to create a Bundle ID which should then be supplied to this field. ```buildVersion```: This needs to be incremented each time you upload the app to Apple. @@ -52,7 +50,7 @@ module.exports = { After the packager configuration, there is the ```maker``` configuration and some types of configuration that you can just leave as they are unless you have a use for them. -I don't think you need any makers just for testing. Maybe add the ```zip``` maker if nothing is created. For distribution on the Mac store you need to create a ```pkg``` file. +For distribution on the Mac store you need to create a ```pkg``` file. {% code title="forge.config.js" %} ```js @@ -73,7 +71,7 @@ module.exports = { ## Package Configuration -Inside your ```package.json``` you might need to add a ```productName``` field. The scripts mentioned below can help you bundle and package your code. +Inside your ```package.json``` add a ```productName``` field. The scripts mentioned below can help you bundle and package your code. {% code title="package.json" %} ```json @@ -87,18 +85,18 @@ Inside your ```package.json``` you might need to add a ```productName``` field. ``` {% endcode %} -```npm run mas``` will create a ```pkg``` file for distribution inside the app store, assuming you have used the appropriate forge configuration. For testing, you don't need to use any of the ```makers``` so you can just use ```npm run package```. +```npm run mas``` will create a ```pkg``` file for distribution inside the app store, assuming you have used the appropriate Forge configuration. For testing, you don't need to use any of the ```makers``` so you can simply use ```npm run package```. ## Testing and Submission -To test your application before submitting it to the app store, you need to make sure you are actually running inside an app store sandbox, and not just running like a normal mac application. +To test your application before submitting it to the App Store, you need to make sure you are actually running inside an App Store sandbox. -App containers are located in ```~/Library/Containers```. If there is not a folder named after your app there, then your app is not running inside a container and therefore you have messed up one of the steps in the configuration section. +App containers are located in ```~/Library/Containers```. If there is not a folder named after your app there, then your app is not running inside a container. This means that a configuration or signing issue has occured. Before packaging your application, you should also check that every file has user read permissions, and that every folder has user read and user execute permissions. Every binary should have user read and user execute permissions as well. -You will also need a working help section in the menu of your app. The help section can link to a website. The electron documentation provides a basic template that you can copy and paste to make sure you have the right menu items. You just need to fix up the help section. +You will also need a working help section in the menu of your app. The help section can link to a website. The Electron documentation provides a basic template that you can copy and paste to make sure you have the right menu items. It is only the help section that needs to be altered. If your app only has one window, the app should close completely when the window is closed. -Once everything is ready, you need to download Transporter from the Mac App Store and upload your ```pkg``` file. +Once everything is ready, you need to download [Transporter](https://apps.apple.com/us/app/transporter/id1450874784?mt=12) from the Mac App Store and upload your ```pkg``` file.