【问题标题】:Sign a Framework for OSX 10.9为 OSX 10.9 签署框架
【发布时间】:2013-11-07 08:42:56
【问题描述】:

在使用macdeployqt 后,我签署了我的应用程序以避免Gatekeeper 问题。

我可以在所有框架和捆绑包中的所有内容上使用codesign,但是当我签署捆绑包时出现错误:

$ codesign --force --verify --verbose --sign "Developer ID Application: My ID" MyApplication.app
MyApplication.app: bundle format unrecognized, invalid, or unsuitable
In subcomponent: /Users/username/Dev/Apps/MyApplication/MyApplication.app/Contents/Frameworks/QtConcurrent.framework

如果我检查签名:

$codesign -vvv MyApplication.app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent 
MyApplication.app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent: valid on disk
MyApplication.app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent: satisfies its Designated Requirement

根据http://furbo.org/2013/10/17/code-signing-and-mavericks/ 看来我应该像这样签署框架包

$ codesign --force --verify --verbose --sign "Developer ID Application: My ID" MyApplication.app/Contents/Frameworks/QtConcurrent.framework/Versions/5

但这会导致

MyApplication.app/Contents/Frameworks/QtConcurrent.framework/Versions/5: bundle format unrecognized, invalid, or unsuitable

【问题讨论】:

  • 你让它在 10.8 上工作?
  • 是的。 Mavericks 的代码签名已更改,现在您必须签署框架包。查看 furbo.org 的链接

标签: macos qt code-signing


【解决方案1】:

今天早上遇到了同样的错误。协同设计应用程序似乎在 OSX 10.9 上更加严格

问题是由于 macdeployqt 没有将 Qt 框架包的 info.plist 文件复制到应用包中。

您可以通过告诉您的脚本将文件手动复制到嵌入式框架的捆绑文件中来解决此问题。

例如

$ cp ~/Qt5.2.0/5.2.0-beta1/clang_64/lib/QtCore.framework/Contents/Info.plist MyApplication.app/Contents/Frameworks/QtCore.framework/Resources/

对您的应用使用的每个 qt 模块执行此操作,在调用 macdeployqt* 之后,但在调用 codesign 之前。 (* 或 mkdir 目标目录)

另外,在框架的文件夹上调用 codesign,而不是在版本子文件夹上。

$ codesign --force --verify --verbose --sign "Developer ID Application: My ID" MyApplication.app/Contents/Frameworks/QtConcurrent.framework

希望这会有所帮助。

【讨论】:

  • 谢谢,这行得通。你的 cp 命令有错误,应该是.../clang_64/lib/QtCore.framework/...
  • 错放的 plist 文件似乎不是导致此错误的唯一原因。我正在捆绑框架,当 plist 位于其各自的目标文件夹中时遇到此错误。我仍然收到神秘的“无法识别、无效或不合适的捆绑格式”错误。 Mac OS 10.9 下的 Xcode 5.0.2。
  • 这是关键一步。
  • 非常有用,谢谢。已将其链接到我在签署 Mac OS X 10.8 的帖子中:successfulsoftware.net/2012/08/30/…
  • 10.9.5 的代码设计再次更改;请参阅permalink.gmane.org/gmane.comp.lib.qt.devel/18480 上的精彩帖子,了解如何设置正确的 Qt 框架目录结构,尤其是参考developer.apple.com/library/mac/technotes/tn2206/_index.html#//…
【解决方案2】:

非常感谢!

您还必须签署应用程序使用的所有插件

$ codesign --force --verify --verbose --sign "Developer ID Application: My ID" MyApplication.app/Contents/PlugIns/imageformats/libqgif.dylib

最好的问候,

雷纳

【讨论】:

  • 问题是关于签署框架,而不是如何签署应用程序。
  • 这些插件是 Qt 框架的插件,也需要签名才能使框架工作。
  • @jdkoftinoff 是的,但问题是关于如何签署框架,没有报告签署插件的问题。
【解决方案3】:

我根据 Benoît 的回答编写了一个脚本,用于修补 .app: https://gist.github.com/kainjow/8059407

代码:

#!/usr/bin/env ruby

# Copies missing Info.plist files for a .app's Qt frameworks installed
# from macdeployqt. Without the plists, 'codesign' fails on 10.9 with
# "bundle format unrecognized, invalid, or unsuitable".
#
# Example usage:
# ruby macdeployqt_fix_frameworks.rb /Users/me/Qt5.2.0/5.2.0/clang_64/ MyProgram.app
#
# Links:
# https://bugreports.qt-project.org/browse/QTBUG-23268
# http://stackoverflow.com/questions/19637131/sign-a-framework-for-osx-10-9
# http://qt-project.org/forums/viewthread/35312

require 'fileutils'

qtdir = ARGV.shift
dotapp = ARGV.shift

abort "Missing args." if !qtdir || !dotapp
abort "\"#{qtdir}\" invalid" if !File.exists?(qtdir) || !File.directory?(qtdir)
abort "\"#{dotapp}\" invalid" if !File.exists?(dotapp) || !File.directory?(dotapp)

frameworksDir = File.join(dotapp, 'Contents', 'Frameworks')
Dir.foreach(frameworksDir) do |framework|
next if !framework.match(/^Qt.*.framework$/)
fullPath = File.join(frameworksDir, framework)
destPlist = File.join(fullPath, 'Resources', 'Info.plist')
next if File.exists?(destPlist)
srcPlist = File.join(qtdir, 'lib', framework, 'Contents', 'Info.plist')
abort "Source plist not found: \"#{srcPlist}\"" if !File.exists?(srcPlist)
FileUtils.cp(srcPlist, destPlist)
end 

【讨论】:

    【解决方案4】:

    根据Apple docs,您需要签署版本文件夹,而不是框架本身。我已经尝试过了,遇到了两个问题。首先,Qt 框架的一些 Info.plist 文件的可执行文件名不正确(一个 _debug 后缀)。修复后,我设法以“Apple 方式”签署了所有框架。但是,在这样做之后,我无法签署主应用程序,并且收到关于我刚刚签署的 Qt 框架的错误。

    所以奇怪但有效的解决方案是签署框架文件夹。即使 Info.plist 文件中的可执行文件名称不正确,这也适用。

    【讨论】:

      【解决方案5】:

      总结

      1. 通过将 Info.plist 移动到框架中当前版本级别的 Resources 文件夹来修复格式错误的 Qt 框架。
      2. 使用 codesign --deep 选项一次对包中的所有二进制文件进行签名,包括框架和插件。

      详情

      解决此问题的最简单方法是使用 --deep 协同设计选项。这个选项(我相信是 Mavericks 引入的)将对目标包中的所有二进制文件进行签名,包括主应用程序二进制文件及其框架和插件。

      但是,在使用此选项(或任何其他建议的签名技术)之前,您必须按照此线程上的其他帖子修复 Qt 框架。出于某种奇怪的原因,所构建的 Qt 框架不符合 Apple 的框架规范,并且会混淆代码设计工具。这反过来会导致不良行为,例如用签名框架二进制文件的附加副本替换框架的顶级符号链接。

      要修复 Qt 框架,您应该将 Info.plist 复制到框架特定版本的 Resources 文件夹中,而不是复制到框架的顶层(如之前建议的那样)。此外,您可能希望丢弃应用程序包框架中 Info.plist 的原始副本,因为它基本上位于错误的位置。

      具体来说,您应该根据需要执行以下操作来修复每个框架:

      mkdir -p MyKillerApp.app/Contents/Frameworks/QtCore.framework/Versions/Current/Resources
      cp lib/QtCore.framework/Contents/Info.plist MyKillerApp.app/Contents/Frameworks/QtCore.framework/Versions/Current/Resources
      rm -rf MyKillerApp.app/Contents/Frameworks/QtCore.framework/Contents
      

      以上假设框架中有一个“版本/当前”符号链接。我认为所有构建的 Qt 库都是这种情况。但如果您的构建不是这种情况,那么您可以使用特定版本的文件夹名称(如“4”)而不是“当前”符号链接。

      标准化框架后,您可以使用 --deep 选项对应用程序包中的所有二进制文件进行签名:

      codesign --deep --force --verify --sign "Developer ID Application: My ID" MyKillerApp.app
      

      或者,如果您在项目级别启用了代码签名以进行部署后处理,则只需在“其他代码签名标志”中传递 --deep 选项:

      OTHER_CODE_SIGN_FLAGS = --deep
      

      如果您对主应用程序的代码设计要求与对框架或插件的不同,您可以使用一个小技巧。首先,您使用框架/插件要求使用 --deep 选项进行签名。然后,您可以使用 --force 选项但不使用 --deep 选项再次签名,指定应用程序级别的要求。结果将是主应用程序将使用应用程序要求进行签名,而所有子二进制文件将使用框架/插件要求进行签名。

      这种方法可能被认为有点懒惰和浪费,因为您要对主应用程序进行两次签名。但它比从主应用程序二进制文件中单独查找和签署所有子二进制文件的替代方案更简单。

      【讨论】:

      • 这是否适用于使用spctl -a -t exec -vv Myapp.app 验证捆绑包是否适合新的网守格式?我总是得到一个“拒绝”的结果。
      • 你是在小牛队或以上签约吗? Mavericks 10.9.5 和 Yosemite 的新 Gatekeeper 需要 v2 签名。如果您使用 Mavericks 签名(甚至是当前的发布版本),它将创建所需的 v2 签名。
      【解决方案6】:

      在进行代码设计之前,我使用此脚本来更正 QT 4.8 框架。希望这可以帮助。我和一位同事花了大约 3-4 天的时间才弄清楚这一点(这是在 QT 发表博客之前)。

      # we need to massage qt frameworks so they get codesigned by the new codesign
      # more information about this $#@$!@# piece of $@#$@$!
      # http://blog.qt.digia.com/blog/2014/10/29/an-update-on-os-x-code-signing/
      
      QT_LIB_DIR=$(qmake -query QT_INSTALL_LIBS)
      for i in $(find "$APP/Contents/Frameworks/" -name Qt\*.framework); do
         FW_NAME=$(basename "$i")
         FW_SHORTNAME=$(basename -s ".framework" "$i")
         mv "$i/Resources" "$i/Versions/4"
         ln -s Versions/Current/Resources "$i/"
         ln -s Versions/Current/${FW_SHORTNAME} "$i/${FW_SHORTNAME}"
         ln -s 4 "$i/Versions/Current"
         cp "${QT_LIB_DIR}/${FW_NAME}/Contents/Info.plist" "$i/Resources"
         chmod u+w "$i/Resources/Info.plist"
         # now comes the real magic, we have to add CFBundleIdentifier and CFBundleVersion to the Info.plist
         awk "/<\/dict>/{print \"<key>CFBundleIdentifier</key>\n<string>org.qt-project.${FW_SHORTNAME}</string>\"}1" "$i/Resources/Info.plist" > "$i/Resources/Info.plist.tmp"
         mv "$i/Resources/Info.plist.tmp" "$i/Resources/Info.plist"
         awk '/<\/dict>/{print "<key>CFBundleVersion</key>\n<string>4.8</string>"}1' "$i/Resources/Info.plist" > "$i/Resources/Info.plist.tmp"
         mv "$i/Resources/Info.plist.tmp" "$i/Resources/Info.plist"
      done
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-02
        • 2016-10-27
        • 2013-11-07
        • 1970-01-01
        • 2014-05-28
        • 1970-01-01
        • 1970-01-01
        • 2014-08-23
        相关资源
        最近更新 更多