Yoann Moinet

@yoannm

Electron on the AppStore — Ship it

This article is part of a 5 articles series about the publication of an Electron application into the Mac AppStore, Fenêtre.

Fenêtre, fənɛtʁ, lets you better multitask on your mac. It enables a picture-in-picture mode for any website/web-app, image, video or flat file.
You can find the free version and the paid version on the Mac App-Store.

Ship it

This is the last mile, and also where I almost lost it. By far the most painful part of the whole project.

Working with Electron, you won’t publish, sign or handle entitlements from XCode, and Apple seems to make it even harder for you since you’re not using their proprietary software. The documentation is cryptic, to say the least, and the support is yet to be found.

What helped me a lot was the WebTorrent for desktop repo, especially their packaging script, so, a very big thank you to the team there ❤️, your project saved my sanity, for real 🙏.

Following their great example I’ve been successfully using electron-packager and electron-osx-sign which are must-have packages to ship your product to the AppStore without XCode.

Certificates & stuffs

First of all, you’ll need 3 different certificates from your developer account.

  • Mac development, so you can test your signed packaged app before sending it to Apple.
  • Mac AppStore → Mac App Distribution, so you can sign your app and all executable inside it.
  • Mac AppStore → Mac Installer Distribution, so you can sign the package of your app, which is the format you’ll send to the AppStore.

Simply download them, double-click and they will be installed in your keychain. That's it, you won't have to deal with these anymore until they expire.

Then you’ll need to create an App ID for your app (one for each version, free and pro), and finally, two provisioning profiles each, one for development and one for distribution.

Now you’re ready to sign your app.

Entitlements.plist

Using plist.js you can create your two entitlement files needed, parent.plist and child.plist. I like doing it in the packaging script, so I don't end up with multiple files I'll never edit.

The parent will need com.apple.security.sand-box at true, because your app has to be sand-boxed before being submitted to the AppStore. And com.apple.application-identifier and com.apple.developer.team-identifier to identify your app.

Add any other needed entitlements depending on what your application does.

As an example, for Fenêtre I’m also using:

  • com.apple.security.network.client since we're connecting to the internet when displaying a website or any URL in Fenêtre.
  • com.apple.security.network.server for the browser extension, so it can send URLs to open. It's also used when encoding/decoding unsupported video formats.
  • com.apple.security.files.user-selected.read-write for the user to drag-n drop files into the app.

In the child.plist it's quite easier, you just need com.apple.security.sand-box and com.apple.security.inherit at true. That's it, that's all, output those file somewhere temporary, we'll use them later during the signature process.

Signature

Now to the big tricky part, the signing of the app. Fortunately for us electron-osx-sign has done most of the hard part. Here’s a snippet of my production signature script:

Signature script for production.

The only two arguments needed, appPath and pkgPath , are the .app's absolute path we've created with electron-packager and the absolute path of where we're outputting the .pkg.

Note the PARENT_PLIST_PATH and CHILD_PLIST_PATH that we also created earlier. And the two different identities we're using, one for the application itself, and another one for the .pkg we're generating. And the platform is mas for 'Mac AppStore'.

Now this package won’t be testable on your machine, not even the signed app. Instead, you’ll have to use another sign script for being able to test your sand-boxed application:

Signature script for development.

Note that we don’t need the generation of the .pkg anymore, since we won't test it. Also, the type changes to development, and the identity is now the Mac Developer one. As well as the DEV_PROVISIONING_PROFILE.

Debug your sandboxed Application

You now have the exact same app as the one that will be shipped to Apple. So you can test the sand-boxing, which is very important and very likely to crash.

Be sure that everything works in this state, or it will be rejected by Apple right away. You can use the very useful RB App Checker Lite as well, to test the entitlements and the signature of your app.

There’s still this ‘The profile does NOT match the application’s Team ID’ I can’t get rid of. But apparently, this is not a big deal ¯\_(ツ)_/¯.

If you need to see the output of your main process, get into the package contents of your generated .app and open the file located at MyApp.app/Contents/MacOS/MyApp, it will open a terminal window with the output of your main process.

To inspect the renderer process, simply spawn the web inspector from your BrowserWindow's options with the help of our global IS_PRODUCTION:

Now that you’re all set, you can use the Application Loader to upload your Application.pkg to your iTunes Connect account.

It’s hidden in XCode > Open Developer Tool > Application Loader. Just open it once, and pin it to your dock, so you don't have to launch XCode each time you need to upload your app, which will happen a lot.

Then from iTunes Connect you’ll be able to select your latest build for the next release.

Wait for the review to happen… update your app, and back to the start, until it's validated and pushed to the AppStore.

More by Yoann Moinet

Topics of interest

More Related Stories