Apple requires that all distributed binaries are signed and notarized using a paid Apple Developer account. This can be done using commandline tools for binaries created with tools such as PyInstaller, or compiled using gcc.
If you already have a developer account with Developer ID Application
and Developer ID Installer
certificates configured in XCode, skip this step
- Create a developer account with Apple
- https://developer.apple.com and shell out $99 for a developer account. Theives
- Download and install X-Code from the Apple App Store
- https://developer.apple.com/download/all/?q=Xcode (this requires a sign in, or can be downloaded from the App Store)
- Open and run X-Code app and install whatever extras it requires
- Open the preferences pane (cmd+,) and choose Accounts(
- click the
+
in the lower left corner - choose
Apple ID
- enter your apple ID and password
- Previously created keys can be downloaded and installed from https://developer.apple.com
- click the
- Select the developer account you wish to use
- Choose Manage Certificates...
- Click the
+
in the lower left corner and choose Developer ID Application - Click the
+
in the lower left corner and choose Developer ID Installer
- Instructions from Apple
- Open
KeyChain Access
- Create a "New Password Item"
- Keychain Item Name: Developer-altool
- Account Name: your developer account email
- Password: the application-specific password you just created
NB! Additional args such as --add-data
may be needed to build a functional binary
- Create a onefile binary
pyinstaller --onefile myapp.py
-
Add the entitements.plist to the directory (see below)
-
List the available keys and locate a Developer ID Application certificate:
security find-identity -p basic -v
1) ABC123 "Apple Development: [email protected] ()" 2) XYZ234 "Developer ID Installer: Aaron Ciuffo ()" 3) QRS333 "Developer ID Application: Aaron Ciuffo ()" 4) LMN343 "Developer ID Application: Aaron Ciuffo ()" 5) ZPQ234 "Apple Development: [email protected] ()" 6) ASD234 "Developer ID Application: Aaron Ciuffo ()" 7) 01010A "Developer ID Application: Aaron Ciuffo ()" 7 valid identities found
-
codesign --deep --force --options=runtime --entitlements ./entitlements.plist --sign "HASH_OF_DEVELOPER_ID APPLICATION" --timestamp ./dist/foo.app
-
Create a temp directory to build the package:
mkdir /tmp/myapp
-
Use ditto to build the pkg installer structure
ditto /path/to/myapp /tmp/myapp/path/to/install/location
- to install application "WhizBang" into
/Applications/
on the target use:ditto ~/src/whiz_bang/dist/whizBang /tmp/whiz_bang/Applications/
- to install application "WhizBang" into
- repeat for all files that should be packaged
-
build the package
-
productbuild --identifier "com.your.pkgname.pkg" --sign "HASH_OF_INSTALLER_ID" --timestamp --root /tmp/myapp / myapp.pkg
-
NB! the format for the
--root
option is as follows:--root
<ditto path>
<relative path on target system to install from>
<signed .pkg file>
xcrun altool --notarize-app --primary-bundle-id "com.foobar.fooapp" --username="[email protected]" --password "@keychain:Developer-altool" --file ./myapp.pkg
- Check email for successful notarization
- Alternatively check status using:
xcrun altool --notarization-history 0 -u "developer@***" -p "@keychain:Developer-altool"
- Alternatively check status using:
- If notarization fails use the following to review a detailed log:
xcrun altool --notarization-info "Your-Request-UUID" \
--username "[email protected]" \
--password "@keychain:Developer-altool"
- add the notariztaion to the pkg
xcrun stapler staple ghostscript64.pkg
- Norarize a Commandline utility
- This blog details setting up:
- a developer profile & certificates
- one time passwords
- creating keychain entries to allow the
-p "@keychain:Key"
switch to work - Signing and Notarizing
- Satpling
- This blog details setting up:
- Adding an
entitlements.plist
to the signing process- ensure that embedded python libraries can be access appropriately
- Signing and Notarizing tools compiled outside of XCode
- covers:
- signing
- packaging
- notarizing
- stapling
- covers:
-
Only ".app" bundles appear to work using this procedure
pyinstaller --windowed --onefile foo.py
- edit the spec file
app = BUNDLE
section to include a bundle_identifier
app = BUNDLE(exe, name='helloworld.app', icon=None, bundle_identifier='com.txoof.helloworld' )
-
NOTE! Appbundles will not execute properly -- they must be run by execuing the
bundle.app/Contents/MacOS/myapp
NB! This may not work for single file executables -- use the PKG method above
- Create a
.dmg
:- clean any uneeded files out of
./dist
; only the .app should remain hdiutil create ./myapp.dmg -ov -volname "MyApp" -fs HFS+ -srcfolder "./dist"
- clean any uneeded files out of
- Shrink and make read-only:
$hdiutil convert ./myapp.dmg -format UDZO -o myapp.dmg