I know this is long so here's a real brief summary:
I am trying to build an application and copy other pre-built scripts or files into the
.app/Contents/MacOS
directory.I can get something that works and still prompts the user for mic access but it won't pass notarization (saying the signature is bad). I can't tell if I'm building the DMG and/or PKG in an improper way or maybe copying files into the install destination hoses the signature?
If I copy the pre-built files in place and then re-sign my app after archiving I can pass Apple's notarization but then the mic access fails crashing with a privacy violation (as if I never specified entitlements).
Here's the longer version with much detail:
I have an application myApp that uses the microphone that I build as an archive from the command line with xcodebuild -scheme myApp archive -archivePath myApp.archive
.
The app works if I were to stop here. I have the proper entitlements, code hardening enabled and the NSMicrophoneUsageDescription
in my plist.
However, I have various other resources that I must include with my app. I want to put them in the myApp.app/Contents/MacOS
dir. These resources include a shell script for debugging, a secondary Swift tool, etc.
I am finding it impossible to build this app with the proper signature and entitlements for mic access in conjunction with passing Apple's notarization.
I am copying these secondary apps into the destination dir by specifying a pre-action and post-action script in Xcode for the Archive action in my scheme.
Pre-Action Archive Script
The pre-action script is signing all the secondary objects with my Developer ID Application certificate:
APP_SIGN_ID="Developer ID Application: MyCompany Inc. (XXXXXXXXXX)"
LOG="/tmp/archive.log"
rm -f $LOG
echo "Pre-action for archive" > $LOG
function sign_and_verify() {
echo "signing $1" >> $LOG
codesign --force --options runtime --verify --verbose --sign "$APP_SIGN_ID" "$1"
if [ $? -ne 0 ]; then
echo "failed signature" >> $LOG
exit 1
fi
}
# sign these things as a pre-action to archive and copy them to the Contents/MacOS in the post-action
sign_and_verify "${HOME}/src/bin/mydebugtool"
sign_and_verify "${HOME}/src/bin/myscript.sh"
Post-Action Archive Script
The post-action script for the archive in my scheme is copying these signed assets into place (the copy has to be done as a post-action b/c the archive destination dir doesn't exist in the pre-action phase):
LOG="/tmp/archive.log"
TARGETDIR="${ARCHIVE_PRODUCTS_PATH}/Applications/myApp.app/Contents/MacOS/"
function my_copy() {
echo "copying $1 to $2" >> $LOG
cp "$1" "$2"
if [ $? -eq 0 ]; then
echo "copy success" >> $LOG
else
echo "copy failure" >> $LOG
fi
}
my_copy "${HOME}/src/bin/mydebugtool" "${TARGETDIR}"
my_copy "${HOME}/src/bin/myscript.sh" "${TARGETDIR}"
I then build this archive. If I run open <path-to-archive>/myApp.app
it opens properly and prompts for mic access. The other tools are correctly in the archive.
Notarization Output
However, when I bundle the archive contents into a DMG or PKG it fails notarization with:
{
"logFormatVersion": 1,
"jobId": "5a225fdb-d85d-41fa-8bde-1026xx92331a",
"status": "Invalid",
"statusSummary": "Archive contains critical validation errors",
"statusCode": 4000,
"archiveFilename": "myApp.dmg",
"uploadDate": "2019-08-20T20:22:08Z",
"sha256": "d93da550d2617246aead790a13afc6360ff5198764cfb779b785e06d463d4e32",
"ticketContents": null,
"issues": [
{
"severity": "error",
"code": null,
"path": "myApp.dmg/myApp.app/Contents/MacOS/myApp",
"message": "The signature of the binary is invalid.",
"docUrl": null,
"architecture": "x86_64"
}
]
}
It's a shame it fails because it runs great on Mojave. It'll just never run on Catalina without passing notarization.
So I can't tell if it's failing because of the way I'm building the DMG or PKG or if it's failing because I'm putting things into the Contents/MacOS directory (even though they are signed?).
How I build a DMG
For the sake of clarity, here's the little script I use to assemble the DMG I'm trying to get notarized:
BASE_DIR=`pwd`"/myapp.archive.xcarchive/Products/Applications"
function create_dmg() {
echo "creating DMG"
rm -f temp.dmg
rm -f myApp.dmg
title=myApp
size=240
umount /Volumes/myApp
hdiutil create -srcfolder "${BASE_DIR}" -volname "${title}" -fs HFS+ \
-fsargs "-c c=64,a=16,e=16" -format UDRW -size ${size}m temp.dmg
device=$(hdiutil attach -readwrite -noverify -noautoopen temp.dmg | \
egrep '^/dev/' | sed 1q | awk '{print $1}')
mkdir /Volumes/"${title}"/.background
cp background.png /Volumes/"${title}"/.background/background.png
ln -s /Applications /Volumes/"${title}"/"Applications"
rm -rf /Volumes/"${title}"/.fseventsd
sleep 2
echo '
tell application "Finder"
tell disk "'${title}'"
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 {400, 100, 950, 500}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 150
set background picture of theViewOptions to file ".background:'background.png'"
set position of item "myApp" of container window to {120, 150}
set position of item "Applications" of container window to {430, 150}
set position of item ".background" of container window to {120, 525}
set position of item ".Trashes" of container window to {220, 525}
set position of item ".DS_Store" of container window to {320, 525}
set position of item ".fseventsd" of container window to {430, 525}
update without registering applications
delay 5
end tell
end tell
' | osascript
sync
sync
How I build a PKG
I also am building a PKG which also fails notarization. Here's my script for building the PKG:
PKG_SIGN_ID="Developer ID Installer: My Company Inc. (XXXXXXXXX)"
BASE_DIR=`pwd`"/myapp.archive.xcarchive/Products/Applications"
function create_pkg() {
echo "creating pkg"
rm -f myApp.pkg
# generate plists
cd $BASE_DIR
pkgbuild --analyze --root ./myApp.app myApp.plist
# pkgbuild myApp
pkgbuild --scripts /tmp/installer-scripts --root "./myApp.app" --component-plist "./myApp.plist" --identifier "com.mycompany.myapp.myApp" --version "$VERSION" --install-location "/Applications/myApp.app" ./myApp.pkg
if [ $? -ne 0 ]; then
echo "failed pkgbuild for myApp.pkg"
rm -f myApp.pkg
exit 1
fi
# copy the installer resources
cp -r ../../res ./
# --synthesize will generate the Distribution.xml file
productbuild --synthesize --resources ./res --package myApp.pkg Distribution.xml
if [ $? -ne 0 ]; then
echo "failed productbuild synthesize for Distribution.xml"
rm -f myApp.pkg
exit 1
fi
# add our title to the Distribution.xml that was generated
# I can't believe I have to splice this in after the synthesize but I couldn't find another way
cat Distribution.xml | sed $'3i\\\n<title>MyApp</title>\n' > mod.xml
mv mod.xml Distribution.xml
cat Distribution.xml | sed $'3i\\\n<welcome file="welcome.html"/>\n' > mod.xml
mv mod.xml Distribution.xml
cat Distribution.xml | sed $'3i\\\n<background file="background.png" mime-type="image/png" scaling="tofit"/>\n' > mod.xml
mv mod.xml Distribution.xml
cat Distribution.xml | sed $'3i\\\n<background-darkAqua file="background.png" mime-type="image/png" scaling="tofit"/>\n' > mod.xml
mv mod.xml Distribution.xml
productbuild --resources ./res --sign "$PKG_SIGN_ID" --distribution Distribution.xml myApp.$VERSION.pkg
if [ $? -ne 0 ]; then
echo "failed signature"
rm -f myApp.pkg
exit 1
else
echo "Successfully built and signed myApp.$VERSION.pkg"
mv myApp.$VERSION.pkg ../../../
# remove the unsigned package so we don't accidentally distribute that
rm -f myApp.pkg
fi
}
I hope this isn't so long that someone who can help has stopped reading. I tried to be brief yet also include as much detail as I think appropriate.
UPDATE: to verify whether I'm improperly building a DMG I commented out the post-action archive script, built the app and the DMG and got it notarized. So something about me putting files into the Contents/MacOS dir as part of the archive post-action is breaking the signature.
**