How do you codesign framework bundles for the Mac App Store?

感情迁移 提交于 2019-11-28 15:14:32

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
  1. 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.
  2. Add a “Run Script” build phase right after your “Copy Embedded Frameworks” build phase.
    • You can call it “Codesign Embedded Frameworks”.
  3. 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.
  4. 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
  • Fing 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...

Ross Bencina

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!