How do you codesign framework bundles for the Mac App Store?
After a recent submission I have gotten the following error:
Invalid Signature - the nested app bundle (FooBar.app/Contents/Frameworks/GData.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
Invalid Signature - the nested app bundle (FooBar.app/Contents/Frameworks/Growl.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
Invalid Signature - the nested app bundle libcurl (FooBar.app/Contents/Frameworks/libcurl.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
So I signed all the framework bundles per Technote 2206:
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libcurl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libssh2.1.dylib
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A/Growl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A/GData
Technote 2206 says:
Signing Frameworks
Seeing as frameworks are bundles it would seem logical to conclude that you can sign a framework directly. However, this is not the case. To avoid problems when signing frameworks make sure that you sign a specific version as opposed to the whole framework:
# This is the wrong way:
codesign -s my-signing-identity ../FooBarBaz.framework
# This is the right way:
codesign -s my-signing-identity ../FooBarBaz.framework/Versions/A
And when I try to verify the results, it looks good to me:
% codesign -vvv FooBar.app/Contents/Frameworks/libcurl.framework
FooBar.app/Contents/Frameworks/libcurl.framework: valid on disk
FooBar.app/Contents/Frameworks/libcurl.framework: satisfies its Designated Requirement
% codesign -vvv FooBar.app/Contents/Frameworks/Growl.framework
FooBar.app/Contents/Frameworks/Growl.framework: valid on disk
FooBar.app/Contents/Frameworks/Growl.framework: satisfies its Designated Requirement
For fun, I did try signing the framework bundle directly and it was still rejected. But that is exactly what the documentation sa开发者_C百科id not to do.
Any guesses why that would be considered invalid? I am using the same cert that I use to code sign my app -- the one that has worked in the past.
My only guess would be something to do with the existing plists (do I need to own the identifiers in the framework's Info.plists?) or entitlements -- any suggestions?
Based on baptr’s answer, I have developed this shell script that codesigns all my frameworks and other binary resources/auxiliary executables (currently supported types: dylib, bundle, and login items):
#!/bin/sh
# WARNING: You may have to run Clean in Xcode after changing CODE_SIGN_IDENTITY!
# Verify that $CODE_SIGN_IDENTITY is set
if [ -z "${CODE_SIGN_IDENTITY}" ] ; then
echo "CODE_SIGN_IDENTITY needs to be set for framework code-signing!"
if [ "${CONFIGURATION}" = "Release" ] ; then
exit 1
else
# Code-signing is optional for non-release builds.
exit 0
fi
fi
if [ -z "${CODE_SIGN_ENTITLEMENTS}" ] ; then
echo "CODE_SIGN_ENTITLEMENTS needs to be set for framework code-signing!"
if [ "${CONFIGURATION}" = "Release" ] ; then
exit 1
else
# Code-signing is optional for non-release builds.
exit 0
fi
fi
ITEMS=""
FRAMEWORKS_DIR="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -d "$FRAMEWORKS_DIR" ] ; then
FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -name "*.dylib" -or -name "*.bundle" | sed -e "s/\(.*framework\)/\1\/Versions\/A\//")
RESULT=$?
if [[ $RESULT != 0 ]] ; then
exit 1
fi
ITEMS="${FRAMEWORKS}"
fi
LOGINITEMS_DIR="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/"
if [ -d "$LOGINITEMS_DIR" ] ; then
LOGINITEMS=$(find "${LOGINITEMS_DIR}" -depth -type d -name "*.app")
RESULT=$?
if [[ $RESULT != 0 ]] ; then
exit 1
fi
ITEMS="${ITEMS}"$'\n'"${LOGINITEMS}"
fi
# Prefer the expanded name, if available.
CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then
# Fall back to old behavior.
CODE_SIGN_IDENTITY_FOR_ITEMS="${CODE_SIGN_IDENTITY}"
fi
echo "Identity:"
echo "${CODE_SIGN_IDENTITY_FOR_ITEMS}"
echo "Entitlements:"
echo "${CODE_SIGN_ENTITLEMENTS}"
echo "Found:"
echo "${ITEMS}"
# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below.
SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")
# Loop through all items.
for ITEM in $ITEMS;
do
echo "Signing '${ITEM}'"
codesign --force --verbose --sign "${CODE_SIGN_IDENTITY_FOR_ITEMS}" --entitlements "${CODE_SIGN_ENTITLEMENTS}" "${ITEM}"
RESULT=$?
if [[ $RESULT != 0 ]] ; then
echo "Failed to sign '${ITEM}'."
IFS=$SAVED_IFS
exit 1
fi
done
# Restore $IFS.
IFS=$SAVED_IFS
- Save it to a file in your project. I keep my copy in a
Scripts
subdirectory in my project’s root.- Mine is called
codesign-frameworks.sh
.
- Mine is called
- Add a “Run Script” build phase right after your “Copy Embedded Frameworks” build phase.
- You can call it “Codesign Embedded Frameworks”.
- Paste
./codesign-frameworks.sh
(or whatever you called your script above) into the script editor text field. Use./Scripts/codesign-frameworks.sh
if you store the script in a subdirectory. - Build your app. All bundled frameworks will be codesigned.
Should you still get an “Identity: ambiguous (matches: …” error, please comment below. This should not happen anymore.
Updated 2012-11-14: Adding support for frameworks with special characters in their name (this does not include single quotes) to “codesign-frameworks.sh”.
Updated 2013-01-30: Adding support for special characters in all paths (this should include single quotes) to “codesign-frameworks.sh”.
Updated 2013-10-29: Adding experimental dylib support.
Updated 2013-11-28: Adding entitlements support. Improving experimental dylib support.
Updated 2014-06-13: Fixing codesigning issues with frameworks containing (nested) frameworks. This was done by adding -depth
option to find
, which causes find
to do a depth-first traversal. This has become necessary, because of the issue described here. In short: a containing bundle can only be signed if its nested bundles are signed already.
Updated 2014-06-28: Adding experimental bundle support.
Updated 2014-08-22: Improving code and preventing failure to restore IFS.
Updated 2014-09-26: Adding support for login items.
Updated 2014-10-26: Quoting directory checks. This fixes the “line 31/42: too many arguments” errors and the resulting “ code object is not signed at all” error for paths including special characters.
Updated 2014-11-07: Resolving the ambiguous identity error (like “Mac Developer: ambiguous …”) when using automatic identity resolution in Xcode. You don’t have to explicitly set the identity anymore and can just use “Mac Developer”!
Updated 2015-08-07: Improving semantics.
Improvements welcome!
Your comment shows you signed the objects within the bundle's version directory. The Technote shows to sign the directory itself.
The following matches the Technote better:
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A
This is how I fixed it;
- Enter to the build settings of your target
- Find the line "Other Code Signing Flags"
- Enter --deep value to the release parameter
- Close Xcode
- Enter to the derived data folder on your Mac and delete the old derived data (default path is: /Users/YOUR_USER_NAME/Library/Developer/Xcode/DerivedData)
- Open Xcode and build
After the build archive and submit the app again...
One thing I don't see mentioned here is that you need to have your Info.plist inside /Resources inside the versioned framework directory. Otherwise you'll get the "bundle format unrecognized, invalid, or unsuitable" error when you try to sign the versioned directory.
I provided a more extended answer here: How to Codesign Growl.framework for Sandboxed Mac App
精彩评论