This worked as of Feb 17 2025, on OSX Sonoma 14.7.2, using PyInstaller 6.12.0. And this packaged a very nontrivial app, which you can now download from https://cytoflow.readthedocs.io.
- Create a developer account with Apple
- https://developer.apple.com and shell out $99 for a developer account
- Wait a day or so for your developer account to be activated.
- Download and install XCode from the App Store.
- open XCode and install all of the command-line tools when it asks.
- Create a certificate signing request (CSR)
- Launch the "Keychain Access" utility
- Choose Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
- In the Certificate Assistant dialog, enter an email address in the User Email Address field.
- In the Common Name field, enter a name for the key.
- Leave the CA Email Address field empty.
- Choose “Saved to disk,” then click Continue. The file will be a
.csr
file.
- Create a "Developer ID Application" certificate.
- Browse to https://developer.apple.com/account
- Open the "Certificates" page
- Next to "Certificates", click the
+
icon - Choose "Developer ID Application" certificate type and click "Continue"
- Upload the CSR file you saved earlier and click "Continue"
- Download the resulting certificate. It will be a
.cer
file.
- Add the certificate to the
login
keychain- Return to the
Keychain Access
utility - Under the "File" menu, choose "Import Items..."
- Select the
.cer
file you just downloaded. - When asked which keychain to add it to, choose the "login" keychain.
- Return to the
- Verify that the certificate is available
- Open a Terminal
- Type
security find-identity -p basic -v
and ensure that the certificate you just added is present. Note the hexadecimal hash of the identity certificate. - If your certificate doesn't show up:
- go back to Keychain Access
- open the
login
keychain and choose "Certificates." - Right-click on your Developer ID Application certicate and choose "Evaluate"
- Leave "Generic" selected and click "Continue"
- If you get an error that the certificate is invalid, look to see why. My issue was that Xcode was supposed to install the intermediate certificates .... but didn't. If that's the case, you can get them from https://www.apple.com/certificateauthority/
- Make an app-specific password for notarytool
- Follow these instructions from Apple
- Save the app-specific password to a password manager or somewhere else safe.
- Store the app-specific password in the keyring so you don't have to type it in each time you run
notarytool
- In Terminal, run
xcrun notarytool store-credentials
. - When prompted, give the profile a memorable name
- When prompted, provide your Apple ID, the app-specific password, and your "development team" (which you can find at https://developer.apple.com/account under "Membership Details"
- If (when) you forget what this profile name is, you can find it in
Keychain Access
-- search forcom.apple.gke.notary.tool
.
- In Terminal, run
- Build your .app as usual (packaging
.app
bundles is beyond the scope of this gist). By default, PyInstaller signs it with an ad hoc key to satisfy Gatekeeper, but you can't distribute it like that. Make sure it opens when you run it withopen <myapp>.app
from the terminal. - Make sure that the
entitlements.plist
file attached to this gist is present in the build directory - Add the following to the
.spec
file:- to the
EXE()
call, addcodesign_identity='ABC123'
, replacingABC123
with the hexadecimal hash of the identity certificate from above. - to the
EXE()
call, addentitlements_file=entitlements.plist
, pointing to theentitlements.plist
file from this gist and adapting the path as necessary.
- to the
- Rebuild your .app using PyInstaller with the code signing and entitlements settings.
- In the Terminal, in the directory containing your
.app
bundle, typecodesign -vv --strict <myapp.app>
. Check thatcodesign
returns "valid on disk" and "satisfies its Designated Requirement." - If that's not the case, you can run
codesign -vvv --strict <myapp.app>
(note the extrav
) and look for errors.
- You can only submit
.pkg
,.dmg
and.zip
file for notarizing. And you can't usezip
to zip up the.app
bundle! Instead, we useditto
to maintain some necessary HFS metadata. - In Terminal, say
ditto -c -k --sequesterRsrc --keepParent <myapp.app> <myapp.zip>
- In Terminal, say
xcrun notarytool submit <myapp.zip> --keychain-profile <profile> --wait
. Use the profile name that you created above, surrounding it in quotes if necessary. - If this is your first submission, be prepared to wait, possibly several days. You can see past submissions with
xcrun notarytool history
, and you can usexcrun notarytool info <submission-id>
to check on a submission status if you need to turn off your computer or close the terminal thatnotarytool
is running in.- Apparently Apple builds some sort of profile the first time a developer submits something. Afterwards, notarization should only take seconds to minutes.
notarytool
should returnAccepted
if notarization succeeded. If it didn't, you can usenotarytool log <submission-id>
to get a clue to what went wrong.
- In Terminal, say
xcrun stapler staple <myapp.app>
. - Check that it returns
The staple and validate action worked!
- In Terminal, say
spctl -a -v <myapp.app>
- Double-check that Gatekeeper returns "accepted"
- If not, say
spctl -a -vvv <myapp.app>
and look for errors.