-
Notifications
You must be signed in to change notification settings - Fork 1
macOS Signing Workflow
In xCode add the Hardened runtime and Sandbox entitlements (file is also below) https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app#Perform-additional-configuration-steps
We assume building individual repositories (i.e., not the dev bundle) and working and configured CMake build
run in the build folder generated by CMAKE (the folder containing the with xcode project file, e.g., mv-main.xcodeproj
for the ManiVault Core)
xcodebuild -scheme ALL_BUILD -configuration Release build
https://developer.apple.com/library/archive/technotes/tn2339/_index.html
This will install into the regular folder structure (license, Plugins, and app bundle will be copied in the packaging into a dmg inside a folder with the app name, the other ones can optionally be added in this script. note all executables need to be signed, so if e.g., the libraries folder is added the dylib in there needs to be signed, too):
Release
|
------------------------ ...
| | |
license Plugins ManiVault Studio.app
After building, if not done automatically, collect all plugins in the above folder structure under Plugins
For adding signing certificates etc. to the Github runner see Github documentation: https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development
If you do not already have those (e.g., in your local keychain on your Mac, create the certificates first:
- create app id (currently we use com.biovault.mv, I wonder if we want to change this to studio.manivault) I think a wild card will work but for testing i created the explicit id in my account https://developer.apple.com/help/account/manage-identifiers/register-an-app-id
- create developer id certificate https://developer.apple.com/help/account/create-certificates/create-developer-id-certificates
- along this process you will need to create a certificate signing request (it is also linked in the description) https://developer.apple.com/help/account/create-certificates/create-a-certificate-signing-request
- there are some things not fully correct in the build. See Open Issues below and manually fix them before signing.
all following steps are run in the MV_INSTALL/Release folder as indicated above
FIRSTNAME LASTNAME
: Name in the Developer account (I assume this is usually Firstname Lastname, but doublecheck)
TEAM_ID
: 10 digit alphanumeric team id, see your apple developer welcome mail
APPLE_ID
: apple id used for the developer account (possibly any that is added to that account under appstore connect is also possible, many of the certificate steps above list a required role in the description, that role can be assigned to team members)
PASSWORD
: the password for that apple id (use an app password if two factor is enabled on the apple id)
SUBMISSION_ID
: created by submitting the app for notarization\
-
Deep signing the app
codesign --verbose --force --timestamp --verify --deep --sign "Developer ID Application: FIRSTNAME LASTNAME (TEAM_ID)" --entitlements ManiVault\ Studio.app/Contents/Resources/ManiVault\ Studio.entitlements --options runtime ManiVault\ Studio.app
-
Webengine (see below for entitlements file), this is one line! the entitlements file is expected to be in the same folder in this command
codesign --verbose --force --timestamp --verify --sign "Developer ID Application: FIRSTNAME LASTNAME (TEAM_ID)" --entitlements webengine.entitlements --options runtime ManiVault\ Studio.app/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess
-
Resign the app executable
codesign --verbose --force --timestamp --verify --sign "Developer ID Application: FIRSTNAME LASTNAME (TEAM_ID)" --entitlements ManiVault\ Studio.app/Contents/Resources/ManiVault\ Studio.entitlements --options runtime ManiVault\ Studio.app/Contents/MacOS/ManiVault\ Studio
-
Sign all plugins in one batch
codesign --verbose --force --deep --timestamp -o runtime --sign "Developer ID Application: FIRSTNAME LASTNAME (TEAM_ID)" Plugins/*
Package as dmg with package.command
script. Run from within the Release folder (next to the app bundle)
Background.png
needs to be in the same folder while running currently, script should be adjusted to the CI/CD environment (changing the ending to .sh
should also create a regular bash script, it is currently .command
for convenience when run manually)
-
submit
xcrun notarytool submit --apple-id APPLE_ID --password PASSWORD --team-id TEAM_ID ManiVault\ Studio.1.0.0.dmg
This will print thje SUBMISSION_ID to the command line -
check status
xcrun notarytool info --apple-id APPLE_ID --password PASSWORD --team-id TEAM_ID SUBMISSION_ID
-
Once status shows "Accepted": Staple
xcrun stapler staple ManiVault\ Studio.1.0.0.dmg
-
The embedded libquazip is missing a .0 at the end of the version
mv ManiVault\ Studio.app/Contents/Frameworks/libquazip1-qt6.1.4.dylib ManiVault\ Studio.app/Contents/Frameworks/libquazip1-qt6.1.4.0.dylib
-
Not all Qt frameworks are embedded, needs decision what to do, support part of Qt only or embedd all or external solution (if that is even possible. General solution for plugins with dynamically linked libraries might be needed,too). Temporary solution for a fixed set of plugins is to rerun macdeploy with the plugins copied into the app bundle:
cp -R Plugins ManiVault\ Studio.app/Contents/Frameworks/MVPlugins
macdeployqt ManiVault\ Studio.app
rm -rf ManiVault\ Studio.app/Contents/Frameworks/MVPlugins
-
Some plugins need other plugins but cannot find them. Before Signing add the plugin folder to their
rpath
cd Plugins
ls | xargs -n1 install_name_tool -add_rpath @loader_path
MV_Application.entitlements (should be added to the app bundle as under Contents/Resources/ManiVault Studio.entitlements
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
this needs to be available next to the app bundle during step 2 of signing
(we can probably just reuse the above entitlements file, as it includes the page protection, but this should be cleaner)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
</dict>
</plist>
#!/bin/bash
# by Andy Maloney
# http://asmaloney.com/2013/07/howto/packaging-a-mac-os-x-application-using-a-dmg/
# make sure we are in the correct dir when we double-click a .command file
dir=${0%/*}
if [ -d "$dir" ]; then
cd "$dir"
fi
# set up your app name, version number, and background image file name
APP_NAME="ManiVault Studio"
VERSION="1.0.0"
DMG_BACKGROUND_IMG="Background.png"
# you should not need to change these
APP_EXE="${APP_NAME}.app/Contents/MacOS/${APP_NAME}"
VOL_NAME="${APP_NAME}.${VERSION}" # volume name will be "ManiVault Studio 1.0.0"
DMG_TMP="${VOL_NAME}-temp.dmg"
DMG_FINAL="${VOL_NAME}.dmg" # final DMG name will be "ManiVault Studio.x.x.x.dmg"
STAGING_DIR="./Install" # we temporarily copy all our stuff into this dir
# Check the background image DPI and convert it if it isn't 72x72
_BACKGROUND_IMAGE_DPI_H=`sips -g dpiHeight ${DMG_BACKGROUND_IMG} | grep -Eo '[0-9]+\.[0-9]+'`
_BACKGROUND_IMAGE_DPI_W=`sips -g dpiWidth ${DMG_BACKGROUND_IMG} | grep -Eo '[0-9]+\.[0-9]+'`
if [ $(echo " $_BACKGROUND_IMAGE_DPI_H != 72.0 " | bc) -eq 1 -o $(echo " $_BACKGROUND_IMAGE_DPI_W != 72.0 " | bc) -eq 1 ]; then
echo "WARNING: The background image's DPI is not 72. This will result in distorted backgrounds on Mac OS X 10.7+."
echo " I will convert it to 72 DPI for you."
_DMG_BACKGROUND_TMP="${DMG_BACKGROUND_IMG%.*}"_dpifix."${DMG_BACKGROUND_IMG##*.}"
sips -s dpiWidth 72 -s dpiHeight 72 ${DMG_BACKGROUND_IMG} --out ${_DMG_BACKGROUND_TMP}
DMG_BACKGROUND_IMG="${_DMG_BACKGROUND_TMP}"
fi
# clear out any old data
rm -rf "${STAGING_DIR}" "${DMG_TMP}" "${DMG_FINAL}"
# copy over the stuff we want in the final disk image to our staging dir
mkdir -p "${STAGING_DIR}"
mkdir -p "${STAGING_DIR}/${APP_NAME}"
cp -Rpf "${APP_NAME}.app" "${STAGING_DIR}/${APP_NAME}"
cp -Rpf "Plugins" "${STAGING_DIR}/${APP_NAME}"
cp -Rpf "license" "${STAGING_DIR}/${APP_NAME}"
# ... cp anything else you want in the DMG - documentation, etc.
# figure out how big our DMG needs to be
# assumes our contents are at least 1M!
SIZE=`du -sh "${STAGING_DIR}" | sed 's/\([0-9\.]*\)M\(.*\)/\1/'`
SIZE=`echo "${SIZE} + 5.0" | bc | awk '{print int($1+0.5)}'`
if [ $? -ne 0 ]; then
echo "Error: Cannot compute size of staging dir"
exit
fi
# create the temp DMG file
hdiutil create -srcfolder "${STAGING_DIR}" -volname "${VOL_NAME}" -fs HFS+ \
-fsargs "-c c=64,a=16,e=16" -format UDRW -size ${SIZE}M "${DMG_TMP}"
echo "Created DMG: ${DMG_TMP}"
# mount it and save the device
DEVICE=$(hdiutil attach -readwrite -noverify "${DMG_TMP}" | \
egrep '^/dev/' | sed 1q | awk '{print $1}')
sleep 2
# add a link to the Applications dir
echo "Add link to /Applications\n"
pushd /Volumes/"${VOL_NAME}"
ln -s /Applications
popd
# add a background image
mkdir /Volumes/"${VOL_NAME}"/.background
cp "${DMG_BACKGROUND_IMG}" /Volumes/"${VOL_NAME}"/.background/
# tell the Finder to resize the window, set the background,
# change the icon size, place the icons in the right position, etc.
echo '
tell application "Finder"
tell disk "'${VOL_NAME}'"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {300, 300, 825, 760}
set viewOptions to the icon view options of container window
set arrangement of viewOptions to not arranged
set icon size of viewOptions to 72
set background picture of viewOptions to file ".background:'${DMG_BACKGROUND_IMG}'"
set position of item "'${APP_NAME}'" of container window to {160, 205}
set position of item "Applications" of container window to {360, 205}
close
open
update without registering applications
delay 2
end tell
end tell
' | osascript
sync
# unmount it
hdiutil detach "${DEVICE}"
# now make the final image a compressed disk image
echo "Creating compressed image\n"
hdiutil convert "${DMG_TMP}" -format UDZO -imagekey zlib-level=9 -o "${DMG_FINAL}"
# clean up
rm -rf "${DMG_TMP}"
rm -rf "${STAGING_DIR}"
echo 'Signing.\n'
codesign -s "Developer ID Application: INSERT DEVELOPER ID HERE" "${DMG_FINAL}"
echo 'Done.'
exit