如何正确地将 MacOS 签名和公证添加到使用 Qt 构建的 .app
How properly add MacOS Signature & Notarization to .app built with Qt
我有一个应用程序(使用 Qt/QML 构建),我正尝试对其进行签名和公证,以便在 App Store 之外进行临时分发(供公司内部使用)。 Apple 确认我的软件已经过公证,然后我装订了我的 .app - 但 Gatekeeper 仍然从 运行 停止了该应用程序并提醒用户:
App Name can’t be opened because Apple cannot check it for malicious
software.
我做错了什么?.
以下是我正在执行的步骤:
运行 QMake/在 Qt Creator 中构建。
将生成的 Info.plist 文件中的 CFBundleIdentifier 键修改为 com.myCompanyName.appName而不是 Qt 生成的 com.yourcompany.appName。
cd
到我的构建目录。
运行 macdeployqt:
/Users/<user>/Qt/5.13.0/clang_64/bin/macdeployqt <appName>.app -qmldir=<project source code dir>
.
代号:
codesign --deep -f -s "Developer ID Application: <company name> (<team id>)" --options "runtime" "<appName>.app/"
(开发者 ID 应用程序是 KeychainAccess 中显示的名称)。
验证签名:
codesign -dv --verbose=4 <appName>.app
Returns:
`Executable=<build dir>/<app name>.app/Contents/MacOS/<app name>
Identifier=com.<company name>.<app name>
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=53750 flags=0x10000(runtime) hashes=1674+3 location=embedded
Library validation warning=OS X SDK version before 10.9 does not support Library Validation
VersionPlatform=1
VersionMin=658432
VersionSDK=0
Hash type=sha256 size=32
CandidateCDHash sha256=*************************************
CandidateCDHashFull sha256=*************************************
Hash choices=sha256
CMSDigest=*************************************
CMSDigestType=2
Page size=4096
CDHash=*************************************
Signature size=8990
Authority=Developer ID Application: <my company name> (<my team ID>)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=May 27, 2020 at 2:35:38 PM
Info.plist entries=10
TeamIdentifier=V7L2LD4Q9S
Sealed Resources version=2 rules=13 files=1198
Internal requirements count=1 size=184
或者如果我从应用程序包内的 Qt 框架中查看(随机选择的)可执行文件:
codesign -dv --verbose=4 <appName>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
Returns:
Executable=<build dir>/<app name>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
Identifier=org.qt-project.QtCore
Format=bundle with Mach-O thin (x86_64)
CodeDirectory v=20500 size=49057 flags=0x10000(runtime) hashes=1526+3 location=embedded
VersionPlatform=1
VersionMin=658432
VersionSDK=658944
Hash type=sha256 size=32
CandidateCDHash sha256=*************************************
CandidateCDHashFull sha256=*************************************
Hash choices=sha256
CMSDigest=*************************************
CMSDigestType=2
Page size=4096
CDHash=*************************************
Signature size=8990
Authority=Developer ID Application: <my company name> (<my team ID>)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=May 27, 2020 at 2:35:37 PM
Info.plist entries=8
TeamIdentifier=V7L2LD4Q9S
Runtime Version=10.14.0
Sealed Resources version=2 rules=13 files=1
Internal requirements count=1 size=184
zip: ditto -ck --rsrc --sequesterRsrc "<appName>.app" "<appName>.zip"
上传公证:
xcrun altool --notarize-app -t osx -f <appName>.zip --primary-bundle-id="com.<my company name>.<appName>" -u "<develpper ID @ company name> -p "<app specific password>"
收到一封电子邮件 "Your Mac software was successfully notarized."
主食:xcrun stapler staple "<appName>.app"
Returns: The staple and validate action worked!
分发:
- 创建一个空白的稀疏包磁盘映像。
- 将 appName.app 包复制到其中(连同 /Applications 的快捷方式)。
- 转换为只读。
- 分发给用户。
如果我查看 Console.app - 我可以在日志中看到该应用程序被拒绝打开:
default 15:10:56.549137-0400 runningboardd Invalidating assertion 294-139-3156 (target:executable<<appName>(501)>) from originator 139
default 15:11:01.061942-0400 runningboardd [executable<<appName>(501)>:4893] Death sentinel fired!
XprotectService
控制台中没有任何内容,如 this SO 答案所建议的那样。
如果我尝试使用 spctl 检查签名,它会失败:
spctl -v -a -t open --context context:primary-signature <appName>.app
Returns:
opal.app: rejected
source=Unnotarized Developer ID
spctl -a -t exec -vv <appName>.app produces
Returns:
<appName>.app: rejected
source=Unnotarized Developer ID
origin=Developer ID Application: <my company name> (<team ID>)
produces: invalid API object reference
但是,如果我使用订书机验证应用程序,它会通过:
stapler validate <appName>.app
Returns:
Processing: /<build dir>/<appName>.app
The validate action worked!
关于我的环境:
MacOS 10.15.3
Qt 5.13
Xcode11.4
问题在于,由于您使用 .dmg 进行分发,因此您还需要对 .dmg 进行公证。请按照以下步骤操作:
1) 将经过公证和装订的应用程序添加到 .dmg。
2) 公证您的 .dmg 文件。
3) 将公证装订到 .dmg 文件。
您可以使用我创建的以下 bash 脚本,它允许您创建公证请求、检查公证请求状态和主要公证:
#!/bin/bash
usage()
{
# Display Help
echo "*********************************************************************************************************************************************************"
echo " MacOS Application Notarization Script"
echo "*********************************************************************************************************************************************************"
echo
echo " Requirements"
echo " - XCode Installed"
echo " - Apple Id Account app-specific Password (https://support.apple.com/en-us/HT204397)"
echo " - Apple Developer ID Application Certificate created and installed in keychain (https://developer.apple.com/support/developer-id/)"
echo
echo " Instructions"
echo " 1. Run notarize option to code sign application and create notarization request"
echo " 2. Run check option with the request UUID of the previous step to check the notarization status"
echo " 3. Run staple option only if the notarization status was successful and package was approved"
echo " 4. You are now ready to distribute, if you want to create an installer you can use this option https://github.com/sindresorhus/create-dmg."
echo " Note that if you distribute your app in a .dmg, follow these steps:"
echo
echo " - Add your notarized and stapled app to the DMG."
echo " - Notarize your .dmg file."
echo " Example: sh [=10=] --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF)"
echo " - Staple the notarization to the .dmg file: xcrun stapler staple MyApp.dmg."
echo " Example: sh [=10=] --staple --file MyApp.dmg"
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Usage"
echo " [=10=] [-n|s|c] [ -a APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ] [ -k UUID ]"
echo
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Options:"
echo
notarizeHelp
checkHelp
stapleHelp
return
}
notarizeHelp()
{
echo " ======================================================================="
echo " -n | --notarize Notarize file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -n | --notarize ] [ -a | --file APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " [ -i ] - Apple Signing identity"
echo " [ -e ] - Application entitlements file"
echo " [ -b ] - Application Bundle identifier"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -v ] - Access Provider"
echo " Example:"
echo " .app sh [=10=] --notarize -a MyApp.app -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF -e App.entitlements -i \"Developer ID Application: COMPANY\""
echo " .zip sh [=10=] --notarize -a MyApp.app.zip -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo " .dmg sh [=10=] --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo
}
checkHelp()
{
echo " ======================================================================="
echo " -c | --check Check notarization status"
echo " ======================================================================="
echo " Syntax:"
echo " [ -c | --check ] [ -u USERNAME ] [ -p PASSWORD ] [ -k UUID ]"
echo " Parameters:"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -k ] - Notarization Request UUID"
echo " Example:"
echo " sh [=10=] --check -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -k ffff-ffffff-ffffff-ffffffffff"
echo
}
stapleHelp()
{
echo " ======================================================================="
echo " -s | --staple Staple file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -s | --staple ] [ -a | --file APP_NAME ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " Example:"
echo " sh [=10=] --staple --file MyApp.app"
echo
}
#Help Dictionary
helpFunction()
{
echo ""
usage
exit 1
}
# Transform long options to short ones
for arg in "$@"; do
shift
case "$arg" in
"--notarize") set -- "$@" "-n" ;;
"--staple") set -- "$@" "-s" ;;
"--check") set -- "$@" "-c" ;;
"--file") set -- "$@" "-a" ;;
*) set -- "$@" "$arg"
esac
done
while getopts "nsca:i:e:b:v:u:k:p:" option
do
case "${option}"
in
n) ACTION=NOTARIZE;;
s) ACTION=STAPLE;;
c) ACTION=CHECK;;
a) APP_NAME=${OPTARG};;
i) SIGNING_IDENTITY=${OPTARG};;
e) ENTITLEMENTS=${OPTARG};;
b) BUNDLE_ID=${OPTARG};;
p) PASSWORD=${OPTARG};;
v) PROVIDER=${OPTARG};;
u) USERNAME=${OPTARG};;
k) UUID=${OPTARG};;
?) helpFunction ;;
esac
done
do_check()
{
echo "$UUID"
if [ -z "${UUID}" ]; then
echo "[Error] Didn't specify notarization request UUID";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${UUID}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then
echo
checkHelp
exit 1
fi
echo "[INFO] Checking Notarization status for $UUID"
xcrun altool --notarization-info "$UUID" -u "$USERNAME" -p "$PASSWORD" --output-format xml
exit 1
}
sign()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${SIGNING_IDENTITY}" ]; then
echo "[Error] Didn't specify signing identity";
fi
if [ -z "${ENTITLEMENTS}" ]; then
echo "[Error] Didn't specify entitlements file";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ] || [ -z "${ENTITLEMENTS}" ] || [ -z "${SIGNING_IDENTITY}" ]; then
echo
notarizeHelp
exit 1
fi
echo "[INFO] Signing app contents"
find "$APP_NAME/Contents"|while read fname; do
if [[ -f $fname ]]; then
echo "[INFO] Signing $fname"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" $fname
fi
done
echo "[INFO] Signing app file"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME"
echo "[INFO] Verifying Code Sign"
codesign --verify --verbose "$APP_NAME"
echo "[INFO] Zipping $APP_NAME to ${APP_NAME}.zip"
ditto -c -k --rsrc --keepParent "$APP_NAME" "${APP_NAME}.zip"
#echo "[INFO] Uploading $APP_NAME for notarization"
#xcrun altool --notarize-app -t osx -f "${APP_NAME}.zip" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
notarizationUpload "${APP_NAME}.zip"
}
notarize()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${BUNDLE_ID}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ]; then
echo
notarizeHelp
exit 1
fi
case "$APP_NAME" in
*.app) sign;;
*.zip) notarizationUpload "$APP_NAME";;
*.dmg) notarizationUpload "$APP_NAME";;
esac
}
notarizationUpload()
{
echo "[INFO] Uploading $APP_NAME for notarization"
xcrun altool --notarize-app -t osx -f "" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
}
do_staple()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
echo
stapleHelp
exit 1
fi
echo "[INFO] Stapling $APP_NAME"
xcrun stapler staple "$APP_NAME"
echo "[INFO] Validating Staple for $APP_NAME"
xcrun stapler validate "$APP_NAME"
}
#Excute Action base on the option -s -n -c
case $ACTION in
STAPLE) do_staple;;
CHECK) do_check;;
NOTARIZE) notarize;;
*) helpFunction;
esac
unset APP_NAME ACTION SIGNING_IDENTITY BUNDLE_ID ENTITLEMENTS USERNAME PASSWORD PROVIDER UUID
我找到了这个教程,它详细解释了所有内容:
https://blog.pakkly.com/how-to-sign-qt-apps-on-mac-for-release/
它非常简短。
按照这个步骤,我能够创建一个经过公证的 DMG 文件。
更多提示:
- 使用的证书不能在不同的机器上使用,即使两者使用相同的apple ID帐户。
- 在使用 jenkins 作业构建 DMG 时,我因以下(显然众所周知的)消息而停止:
codesign --deep --timestamp --options runtime -s xxxx my.app
my.app: errSecInternalComponent
这可以通过在前面添加以下行轻松解决:
security unlock-keychain -p “<pwd>”
(在我的例子中,证书在登录部分)
- 另请注意这一点非常重要post:
Error when trying to obtain a certificate: The specified item could not be found in the keychain
我有一个应用程序(使用 Qt/QML 构建),我正尝试对其进行签名和公证,以便在 App Store 之外进行临时分发(供公司内部使用)。 Apple 确认我的软件已经过公证,然后我装订了我的 .app - 但 Gatekeeper 仍然从 运行 停止了该应用程序并提醒用户:
App Name can’t be opened because Apple cannot check it for malicious software.
我做错了什么?.
以下是我正在执行的步骤:
运行 QMake/在 Qt Creator 中构建。
将生成的 Info.plist 文件中的 CFBundleIdentifier 键修改为 com.myCompanyName.appName而不是 Qt 生成的 com.yourcompany.appName。
cd
到我的构建目录。运行 macdeployqt:
/Users/<user>/Qt/5.13.0/clang_64/bin/macdeployqt <appName>.app -qmldir=<project source code dir>
.代号:
codesign --deep -f -s "Developer ID Application: <company name> (<team id>)" --options "runtime" "<appName>.app/"
(开发者 ID 应用程序是 KeychainAccess 中显示的名称)。验证签名:
codesign -dv --verbose=4 <appName>.app
Returns:`Executable=<build dir>/<app name>.app/Contents/MacOS/<app name> Identifier=com.<company name>.<app name> Format=app bundle with Mach-O thin (x86_64) CodeDirectory v=20200 size=53750 flags=0x10000(runtime) hashes=1674+3 location=embedded Library validation warning=OS X SDK version before 10.9 does not support Library Validation VersionPlatform=1 VersionMin=658432 VersionSDK=0 Hash type=sha256 size=32 CandidateCDHash sha256=************************************* CandidateCDHashFull sha256=************************************* Hash choices=sha256 CMSDigest=************************************* CMSDigestType=2 Page size=4096 CDHash=************************************* Signature size=8990 Authority=Developer ID Application: <my company name> (<my team ID>) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=May 27, 2020 at 2:35:38 PM Info.plist entries=10 TeamIdentifier=V7L2LD4Q9S Sealed Resources version=2 rules=13 files=1198 Internal requirements count=1 size=184
或者如果我从应用程序包内的 Qt 框架中查看(随机选择的)可执行文件:
codesign -dv --verbose=4 <appName>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
Returns:Executable=<build dir>/<app name>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore Identifier=org.qt-project.QtCore Format=bundle with Mach-O thin (x86_64) CodeDirectory v=20500 size=49057 flags=0x10000(runtime) hashes=1526+3 location=embedded VersionPlatform=1 VersionMin=658432 VersionSDK=658944 Hash type=sha256 size=32 CandidateCDHash sha256=************************************* CandidateCDHashFull sha256=************************************* Hash choices=sha256 CMSDigest=************************************* CMSDigestType=2 Page size=4096 CDHash=************************************* Signature size=8990 Authority=Developer ID Application: <my company name> (<my team ID>) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=May 27, 2020 at 2:35:37 PM Info.plist entries=8 TeamIdentifier=V7L2LD4Q9S Runtime Version=10.14.0 Sealed Resources version=2 rules=13 files=1 Internal requirements count=1 size=184
zip:
ditto -ck --rsrc --sequesterRsrc "<appName>.app" "<appName>.zip"
上传公证:
xcrun altool --notarize-app -t osx -f <appName>.zip --primary-bundle-id="com.<my company name>.<appName>" -u "<develpper ID @ company name> -p "<app specific password>"
收到一封电子邮件 "Your Mac software was successfully notarized."
主食:
xcrun stapler staple "<appName>.app"
Returns:The staple and validate action worked!
分发:
- 创建一个空白的稀疏包磁盘映像。
- 将 appName.app 包复制到其中(连同 /Applications 的快捷方式)。
- 转换为只读。
- 分发给用户。
如果我查看 Console.app - 我可以在日志中看到该应用程序被拒绝打开:
default 15:10:56.549137-0400 runningboardd Invalidating assertion 294-139-3156 (target:executable<<appName>(501)>) from originator 139
default 15:11:01.061942-0400 runningboardd [executable<<appName>(501)>:4893] Death sentinel fired!
XprotectService
控制台中没有任何内容,如 this SO 答案所建议的那样。
如果我尝试使用 spctl 检查签名,它会失败:
spctl -v -a -t open --context context:primary-signature <appName>.app
Returns:
opal.app: rejected
source=Unnotarized Developer ID
spctl -a -t exec -vv <appName>.app produces
Returns:
<appName>.app: rejected
source=Unnotarized Developer ID
origin=Developer ID Application: <my company name> (<team ID>)
produces: invalid API object reference
但是,如果我使用订书机验证应用程序,它会通过:
stapler validate <appName>.app
Returns:
Processing: /<build dir>/<appName>.app
The validate action worked!
关于我的环境:
MacOS 10.15.3
Qt 5.13
Xcode11.4
问题在于,由于您使用 .dmg 进行分发,因此您还需要对 .dmg 进行公证。请按照以下步骤操作:
1) 将经过公证和装订的应用程序添加到 .dmg。
2) 公证您的 .dmg 文件。
3) 将公证装订到 .dmg 文件。
您可以使用我创建的以下 bash 脚本,它允许您创建公证请求、检查公证请求状态和主要公证:
#!/bin/bash
usage()
{
# Display Help
echo "*********************************************************************************************************************************************************"
echo " MacOS Application Notarization Script"
echo "*********************************************************************************************************************************************************"
echo
echo " Requirements"
echo " - XCode Installed"
echo " - Apple Id Account app-specific Password (https://support.apple.com/en-us/HT204397)"
echo " - Apple Developer ID Application Certificate created and installed in keychain (https://developer.apple.com/support/developer-id/)"
echo
echo " Instructions"
echo " 1. Run notarize option to code sign application and create notarization request"
echo " 2. Run check option with the request UUID of the previous step to check the notarization status"
echo " 3. Run staple option only if the notarization status was successful and package was approved"
echo " 4. You are now ready to distribute, if you want to create an installer you can use this option https://github.com/sindresorhus/create-dmg."
echo " Note that if you distribute your app in a .dmg, follow these steps:"
echo
echo " - Add your notarized and stapled app to the DMG."
echo " - Notarize your .dmg file."
echo " Example: sh [=10=] --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF)"
echo " - Staple the notarization to the .dmg file: xcrun stapler staple MyApp.dmg."
echo " Example: sh [=10=] --staple --file MyApp.dmg"
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Usage"
echo " [=10=] [-n|s|c] [ -a APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ] [ -k UUID ]"
echo
echo "________________________________________________________________________________________________________________________________________________________"
echo
echo " Options:"
echo
notarizeHelp
checkHelp
stapleHelp
return
}
notarizeHelp()
{
echo " ======================================================================="
echo " -n | --notarize Notarize file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -n | --notarize ] [ -a | --file APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ] [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " [ -i ] - Apple Signing identity"
echo " [ -e ] - Application entitlements file"
echo " [ -b ] - Application Bundle identifier"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -v ] - Access Provider"
echo " Example:"
echo " .app sh [=10=] --notarize -a MyApp.app -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF -e App.entitlements -i \"Developer ID Application: COMPANY\""
echo " .zip sh [=10=] --notarize -a MyApp.app.zip -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo " .dmg sh [=10=] --notarize -a MyApp.dmg -b com.company.myapp -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
echo
}
checkHelp()
{
echo " ======================================================================="
echo " -c | --check Check notarization status"
echo " ======================================================================="
echo " Syntax:"
echo " [ -c | --check ] [ -u USERNAME ] [ -p PASSWORD ] [ -k UUID ]"
echo " Parameters:"
echo " [ -u ] - Apple Developer ID Username"
echo " [ -p ] - Application Specific password"
echo " [ -k ] - Notarization Request UUID"
echo " Example:"
echo " sh [=10=] --check -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -k ffff-ffffff-ffffff-ffffffffff"
echo
}
stapleHelp()
{
echo " ======================================================================="
echo " -s | --staple Staple file"
echo " ======================================================================="
echo " Syntax:"
echo " [ -s | --staple ] [ -a | --file APP_NAME ]"
echo " Parameters:"
echo " [ -a | --file ] - File name"
echo " Example:"
echo " sh [=10=] --staple --file MyApp.app"
echo
}
#Help Dictionary
helpFunction()
{
echo ""
usage
exit 1
}
# Transform long options to short ones
for arg in "$@"; do
shift
case "$arg" in
"--notarize") set -- "$@" "-n" ;;
"--staple") set -- "$@" "-s" ;;
"--check") set -- "$@" "-c" ;;
"--file") set -- "$@" "-a" ;;
*) set -- "$@" "$arg"
esac
done
while getopts "nsca:i:e:b:v:u:k:p:" option
do
case "${option}"
in
n) ACTION=NOTARIZE;;
s) ACTION=STAPLE;;
c) ACTION=CHECK;;
a) APP_NAME=${OPTARG};;
i) SIGNING_IDENTITY=${OPTARG};;
e) ENTITLEMENTS=${OPTARG};;
b) BUNDLE_ID=${OPTARG};;
p) PASSWORD=${OPTARG};;
v) PROVIDER=${OPTARG};;
u) USERNAME=${OPTARG};;
k) UUID=${OPTARG};;
?) helpFunction ;;
esac
done
do_check()
{
echo "$UUID"
if [ -z "${UUID}" ]; then
echo "[Error] Didn't specify notarization request UUID";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${UUID}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then
echo
checkHelp
exit 1
fi
echo "[INFO] Checking Notarization status for $UUID"
xcrun altool --notarization-info "$UUID" -u "$USERNAME" -p "$PASSWORD" --output-format xml
exit 1
}
sign()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${SIGNING_IDENTITY}" ]; then
echo "[Error] Didn't specify signing identity";
fi
if [ -z "${ENTITLEMENTS}" ]; then
echo "[Error] Didn't specify entitlements file";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ] || [ -z "${ENTITLEMENTS}" ] || [ -z "${SIGNING_IDENTITY}" ]; then
echo
notarizeHelp
exit 1
fi
echo "[INFO] Signing app contents"
find "$APP_NAME/Contents"|while read fname; do
if [[ -f $fname ]]; then
echo "[INFO] Signing $fname"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" $fname
fi
done
echo "[INFO] Signing app file"
codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME"
echo "[INFO] Verifying Code Sign"
codesign --verify --verbose "$APP_NAME"
echo "[INFO] Zipping $APP_NAME to ${APP_NAME}.zip"
ditto -c -k --rsrc --keepParent "$APP_NAME" "${APP_NAME}.zip"
#echo "[INFO] Uploading $APP_NAME for notarization"
#xcrun altool --notarize-app -t osx -f "${APP_NAME}.zip" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
notarizationUpload "${APP_NAME}.zip"
}
notarize()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
fi
if [ -z "${BUNDLE_ID}" ]; then
echo "[Error] Didn't specify bundle identifier";
fi
if [ -z "${PROVIDER}" ]; then
echo "[Error] Didn't specify access provider";
fi
if [ -z "${USERNAME}" ]; then
echo "[Error] Apple ID username is required";
fi
if [ -z "${PASSWORD}" ]; then
echo "[Error] App Specific password is required";
fi
if [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${BUNDLE_ID}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ]; then
echo
notarizeHelp
exit 1
fi
case "$APP_NAME" in
*.app) sign;;
*.zip) notarizationUpload "$APP_NAME";;
*.dmg) notarizationUpload "$APP_NAME";;
esac
}
notarizationUpload()
{
echo "[INFO] Uploading $APP_NAME for notarization"
xcrun altool --notarize-app -t osx -f "" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER" --output-format xml
}
do_staple()
{
if [ -z "${APP_NAME}" ]; then
echo "[Error] Didn't specify a filename";
echo
stapleHelp
exit 1
fi
echo "[INFO] Stapling $APP_NAME"
xcrun stapler staple "$APP_NAME"
echo "[INFO] Validating Staple for $APP_NAME"
xcrun stapler validate "$APP_NAME"
}
#Excute Action base on the option -s -n -c
case $ACTION in
STAPLE) do_staple;;
CHECK) do_check;;
NOTARIZE) notarize;;
*) helpFunction;
esac
unset APP_NAME ACTION SIGNING_IDENTITY BUNDLE_ID ENTITLEMENTS USERNAME PASSWORD PROVIDER UUID
我找到了这个教程,它详细解释了所有内容: https://blog.pakkly.com/how-to-sign-qt-apps-on-mac-for-release/
它非常简短。 按照这个步骤,我能够创建一个经过公证的 DMG 文件。
更多提示:
- 使用的证书不能在不同的机器上使用,即使两者使用相同的apple ID帐户。
- 在使用 jenkins 作业构建 DMG 时,我因以下(显然众所周知的)消息而停止:
codesign --deep --timestamp --options runtime -s xxxx my.app
my.app: errSecInternalComponent
这可以通过在前面添加以下行轻松解决:
security unlock-keychain -p “<pwd>”
(在我的例子中,证书在登录部分)
- 另请注意这一点非常重要post: Error when trying to obtain a certificate: The specified item could not be found in the keychain