81

最近提交后,我收到以下错误:

无效签名 - 嵌套应用程序包 (FooBar.app/Contents/Frameworks/GData.framework) 未签名、签名无效或未使用 Apple 提交证书签名。有关详细信息,请参阅代码签名和应用程序沙盒指南。

无效签名 - 嵌套应用程序包 (FooBar.app/Contents/Frameworks/Growl.framework) 未签名、签名无效或未使用 Apple 提交证书签名。有关详细信息,请参阅代码签名和应用程序沙盒指南。

签名无效 - 嵌套的应用程序包 libcurl (FooBar.app/Contents/Frameworks/libcurl.framework) 未签名、签名无效或未使用 Apple 提交证书签名。有关详细信息,请参阅代码签名和应用程序沙盒指南。

所以我根据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

技术说明 2206 说:

签名框架

将框架视为捆绑包,因此得出可以直接签署框架的结论似乎是合乎逻辑的。然而,这种情况并非如此。为避免在签署框架时出现问题,请确保签署特定版本而不是整个框架:

# 这是错误的方式:

codesign -s my-signing-identity ../FooBarBaz.framework

# 这是正确的方法:

codesign -s my-signing-identity ../FooBarBaz.framework/Versions/A

当我尝试验证结果时,它对我来说看起来不错:

% 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

为了好玩,我确实尝试直接签署框架包,但仍然被拒绝。但这正是文档所说的不应该做的事情。

任何猜测为什么会被认为是无效的?我使用的证书与我用于对我的应用程序进行代码签名的证书相同——过去曾使用过的证书。

我唯一的猜测是与现有的 plists (我需要拥有框架的 Info.plists 中的标识符吗?)或权利 - 有什么建议吗?

4

4 回答 4

48

根据 baptr 的回答,我开发了这个 shell 脚本,它对我的​​所有框架和其他二进制资源/辅助可执行文件(当前支持的类型:dylib、bundle 和登录项)进行了代码设计:

#!/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. 将其保存到项目中的文件中。我将副本保存Scripts在项目根目录的子目录中。
    • 我的叫codesign-frameworks.sh.
  2. 在“复制嵌入式框架”构建阶段之后添加一个“运行脚本”构建阶段。
    • 您可以将其称为“代码设计嵌入式框架”。
  3. ./codesign-frameworks.sh将(或您在上面调用的脚本)粘贴到脚本编辑器文本字段中。./Scripts/codesign-frameworks.sh如果将脚本存储在子目录中,请使用。
  4. 构建您的应用程序。所有捆绑的框架都将进行代码签名。

如果您仍然收到“<em>Identity: ambiguous (matches: ...”错误,请在下面发表评论。这不应该再发生了。

2012-11-14 更新:添加对名称中包含特殊字符(不包括单引号)的框架的支持到“codesign-frameworks.sh”。

2013 年 1 月 30 日更新:在“codesign-frameworks.sh”中添加对所有路径中的特殊字符(这应该包括单引号)的支持。

2013-10-29 更新:添加实验性 dylib 支持。

2013-11-28 更新:添加权利支持。改进实验性 dylib 支持。

2014-06-13 更新:修复包含(嵌套)框架的框架的代码设计问题。这是通过添加-depth选项来完成的find,这会导致find进行深度优先遍历。由于此处描述的问题,这已成为必要。简而言之:一个包含的包只有在它的嵌套包已经被签名时才能被签名。

2014-06-28 更新:添加实验性捆绑包支持。

2014-08-22 更新:改进代码并防止无法恢复 IFS。

2014-09-26 更新:添加对登录项的支持。

2014-10-26 更新:引用目录检查。这修复了包含特殊字符的路径的“第 31/42 行:参数太多”错误以及由此产生的“代码对象根本没有签名”错误。

2014 年 11 月 7 日更新:在 Xcode 中使用自动身份解析时解决模糊身份错误(如“Mac Developer: ambiguous ...”)。您不必再显式设置身份,只需使用“Mac Developer”即可!

2015-08-07 更新:改进语义。

欢迎改进!

于 2012-07-01T18:01:19.223 回答
11

您的评论显示您在捆绑包的版本目录中签署了对象。技术说明显示对目录本身进行签名。

以下内容与 Technote 更匹配:

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
于 2011-12-02T07:47:10.920 回答
4

这就是我修复它的方法;

  • 输入目标的构建设置
  • 找到“其他代码签名标志”行
  • 在 release 参数中输入--deep
  • 关闭 XCode
  • 进入Mac上的派生数据文件夹并删除旧的派生数据(默认路径为:/Users/YOUR_USER_NAME/Library/Developer/Xcode/DerivedData)
  • 打开 Xcode 并构建

构建存档并再次提交应用程序后...

于 2015-09-11T12:20:36.510 回答
0

我没有看到这里提到的一件事是您需要将 Info.plist 放在版本化框架目录中的 /Resources 中。否则,当您尝试对版本化目录进行签名时,您将收到“无法识别、无效或不合适的捆绑格式”错误。

我在这里提供了一个更详细的答案:How to Codesign Growl.framework for Sandboxed Mac App

于 2013-08-09T15:06:28.933 回答