17

使用后,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
4

6 回答 6

19

今天早上遇到同样的错误。协同设计应用程序在 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/

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

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

IE

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

希望这可以帮助。

于 2013-10-28T16:14:01.170 回答
7

概括

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

细节

解决此问题的最简单方法是使用 --deep codesign 选项。这个选项(我相信是 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 选项再次签名,指定应用程序级别的要求。结果将是主应用程序将使用应用程序要求进行签名,而所有子二进制文件将使用框架/插件要求进行签名。

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

于 2014-04-16T17:27:32.747 回答
2

非常感谢!

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

IE

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

此致,

雷纳

于 2013-11-02T17:29:41.697 回答
0

我根据 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 
于 2013-12-20T18:55:43.803 回答
0

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

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

于 2013-12-25T01:26:04.087 回答
0

在进行代码设计之前,我使用此脚本来更正 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
于 2014-12-21T23:25:20.480 回答