Last active
February 16, 2023 22:43
-
-
Save petered/a80096cc93332411dc6cb5cd197670b8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Author: Peter O'Connor | |
# This script starts with a pyinstaller spec file, builds a macOS app, | |
# codesigns it, notarizes it, staples the notarization ticket, and zips it up. | |
# Full Guide at: https://sites.google.com/site/petesjunkyard/how-to-turn-your-python-program-into-a-working-macos-app | |
# | |
# Before using: | |
# 1) You should have a python app with a main script. | |
# 2) Become apple developer - See guide https://sites.google.com/site/petesjunkyard/how-to-turn-your-python-program-into-a-working-macos-app | |
# 3) Install pyinstaller with | |
# pip install pyinstaller | |
# 4) Install "command line tools for Xcode 14.2" (or newer) from https://developer.apple.com/download/all/ (this give you notarytool) | |
# 5) make the pyinstaller spec file with, e.g. | |
# pyi-makespec --windowed main.py # Should create a main.spec file | |
# 6) cd to the directory containing main.spec | |
# 7) Create a file called entitlements.plist - see https://sites.google.com/d/1gkIG2qmZi5e0qIeDGVoCT333ssUmGKLg/p/1eVkztBPP5nxSP5pnLN_B1N8TwgCBeGDP/edit for what to put in it. | |
# 8) Update the values below to match your app | |
# 9) You may also want to set your app-specific password (from https://appleid.apple.com) as an environment variable | |
# so that you don't have to enter it every time you run the script | |
# export APP_SPECIFIC_PASSWORD="your password" | |
# | |
# Now to do a fresh build, run this script with the spec file you created as the first argument | |
# ./publish_macos.sh main.spec | |
# | |
# And now you can distribute the resulting zip file, whiuch will look like YOUR_APP_NAME_osx-arm64.zip | |
APPLE_ID="[email protected]" # Your Apple ID - should be an email address, and registered as a developer with Apple | |
APP_NAME="EagleEyesScan" # Name of your app - should match the "name" argument to BUNDLE(...) in the spec file | |
TEAM_ID="3992QD63RK" # Your team ID - can be found in the Apple Developer Portal # From https://developer.apple.com/account | |
CERTIFICATE_NAME="Developer ID Application: Eagle Eyes Search Inc (3992QD63RK)" # From https://developer.apple.com/account/resources/certificates/list | |
# Assign first argument to variable SPEC_FILE, or if not specified, exit with error | |
SPEC_FILE=${1:?Please specify the path to the pyinstaller spec file as the first argument.} | |
# Get platform name as a variable from python platform.machine() | |
# or from the second argument if it is specified | |
PLATFORM=$(python -c "import platform; print(platform.machine())") | |
ARCH=${2:-$PLATFORM} | |
echo "Platform name: '$ARCH'" | |
# Set this file so that it fails immediately if any command fails | |
set -e | |
# Get the password as a variable from the environment or prompt user for it if it does not exist. | |
# Generate it at https://appleid.apple.com | |
if [ -z "$APP_SPECIFIC_PASSWORD" ]; then | |
read -s -p "Enter your app specific password: " APP_SPECIFIC_PASSWORD | |
echo | |
fi | |
# Delete the dist folder | |
rm -rf dist | |
# Create the dist folder with the app name | |
pyinstaller --noconfirm "$SPEC_FILE" | |
# Delete .DS_Score files which screw up the codesigning | |
find ./dist/$APP_NAME.app -name .DS_Store -delete | |
# Codes sign the Resources folder, which for some reason is not signed by default | |
codesign -s "$CERTIFICATE_NAME" -vvv --deep --timestamp --entitlements entitlements.plist dist/$APP_NAME.app/Contents/Resources/*.dylib --force | |
# Codesign the app | |
codesign -s "$CERTIFICATE_NAME" -v --deep --timestamp --entitlements entitlements.plist -o runtime "dist/$APP_NAME.app" --force | |
# Create a zip file | |
NOTARIZATION_ZIP_PATH=dist/"$APP_NAME"_"$ARCH"_SUBMISSION.zip | |
ditto -c -k --keepParent "dist/$APP_NAME.app" "$NOTARIZATION_ZIP_PATH" | |
# Submit the zip file to notarization | |
xcrun notarytool submit "$NOTARIZATION_ZIP_PATH" --apple-id $APPLE_ID --team-id $TEAM_ID --password "$APP_SPECIFIC_PASSWORD" --wait | |
# TODO: Check the status of the notarization and quit if invalid. Github Copilot has some ideas. | |
echo "Notarization complete...About to staple" | |
# Staple the notarization ticket to the app -- requires ID from previous command | |
xcrun stapler staple dist/$APP_NAME.app | |
rm "$NOTARIZATION_ZIP_PATH" | |
# Now with stapled ticket, create the final zip file (note - this still happens if we have failure in notarization) | |
FINAL_ZIP_PATH=dist/"$APP_NAME"_"$ARCH".zip | |
ditto -c -k --keepParent "dist/$APP_NAME.app" "$FINAL_ZIP_PATH" | |
echo "Final zip file created at $FINAL_ZIP_PATH. Spread it unto the world!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment