我开发了一个带有Qt5的Mac应用,所以在Xcode之外。我希望GateKeeper允许我的应用程序在客户端的计算机上运行,而不是发出“无法打开,因为无法确认开发人员的身份”警告。
我已成功对该应用程序进行了数字签名,但GateKeeper仍然附带此投诉。我有一个Apple开发人员证书(我是团队代理),我的钥匙串说它是有效的。我还安装了两个Apple根证书。
我使用命令行实用程序codesign
对app文件夹中的所有二进制文件进行数字签名,此外我还对app文件夹本身进行了数字签名。在所有情况下,协同设计的响应都是信息性的,并且没有显示错误。使用codesign我可以检查确实所有二进制文件都已签名,正在运行
$ codesign --verify --deep --verbose=2 MyApp.app
显示所有二进制文件都已验证。此外,它报告:
MyApp.app:在磁盘上有效 MyApp.app:满足其指定要求
运行:
$ codesign -v --verbose=4 --display MyApp.app
给
可执行= /用户/ XXX /中继/ YYY /部署/释放/ MyApp.app /内容/ MacOS的/ MyApp的 标识符= aaaa.MyApp 格式=与Mach-O薄的捆绑(x86_64) CodeDirectory v = 20200 size = 12461 flags = 0x0(none)hashes = 616 + 3 location = embedded 哈希类型= sha1大小= 20 CDHash = d1c12c783dac0e8d9a2b749fb896b11558cec8b6 签名尺寸= 8532 Authority =开发者ID应用程序:XXXXX Authority =开发者ID证书颁发机构 Authority = Apple Root CA. 时间戳= 29岁。 2015 12; 04:40 Info.plist条目= 8 TeamIdentifier = YYYYY 密封资源版本= 2规则= 12个文件= 10 内部要求计数= 1大小= 180
这似乎没问题。
运行
$ spctl -a -t exec -vv MyApp.app
在所有二进制文件上给出结果
MyApp.app:接受了 source =开发者ID origin =开发者ID申请:XXXX
这也似乎没问题
在应用程序或app文件夹内的二进制文件上运行XCode命令行工具检查签名:
$ ./check-signature /Users/xxx/trunk/yyy/release/MyApp.app
给出结果
(c)2014 Apple Inc.保留所有权利。 是
在所有情况下都是理想的结果。
但GateKeeper仍然不接受该应用程序,并抱怨开发人员无法确认。
[作者于2015年7月17日星期五]添加]
我想我已经找到了问题。我不知道它是一个功能还是一个OSX错误。 stackoverflow question 19551298给了我很多帮助。
每当从互联网上下载文件时,它都会获得与之关联的扩展文件属性com.apple.quarantine。在Finder中双击此下载的文件时,GateKeeper有两种可能:
在这两种情况下,MessageBox只有一个按钮,一个OK按钮。单击此按钮时,除了MessageBox关闭之外没有任何反应。
如果删除了扩展属性(xattr -d),则应用程序运行,签名或不签名。
通过在应用程序上的Finder中单击鼠标右键然后单击“打开”菜单操作启动应用程序时,行为会有所不同。再次显示了两个消息框中的一个,但现在有一个额外的按钮,允许用户打开应用程序。签名和未签名之间的唯一区别是“未识别”或“未确认”消息。我不希望我的客户能够分辨出差异。因此签署该应用程序是徒劳的。
在Apple Support Documentation的基础上,我预计当双击下载的应用程序时GateKeeper的另一个更好的行为(可能是文档已过时,或者我误读了它):
很抱歉回答我自己的问题,但我没有别的办法,因为编辑原始问题会导致意大利面条文字。
我终于解决了我的问题。首先是信用:(i)我的其他stackoverflow question的答案非常有用,(ii)我通过提交所谓的技术支持事件(TSI)得到了Apple官方开发人员的非常好(付费)的建议。
基于这一切,我现在能够在这里给出一个非常简洁的方法,说明如何通过GateKeeper成功处理您的Mac应用程序。详细说明食谱后,我将展示我原来的错误。
目标:在Xcode之外开发了一个Mac应用程序,让GateKeeper发出警告“从互联网下载...”,有三个按钮,其中一个是“打开”。
失败:当GateKeeper发出警告时,文本“.. unidentified developer ..”或文本“..未经证实的开发人员......” - 在两种情况下 - 带有一个OK按钮的消息框。
获取应用程序GateKeeper就绪包括三个步骤:
- 使您的应用程序独立,没有不可接受的外部依赖性。唯一可接受的外部依赖是系统库。应将所有其他依赖项复制到MyApp.app文件夹。 GateKeeper拒绝任何具有非系统外部依赖性的应用程序
- 二进制文件不应位于MyApp.app文件夹内的非法位置。库进入MyApp / Contents / Frameworks,可执行文件进入MyApp / Contents / MacOS
- MyApp中的所有二进制文件都应进行数字签名。然后应签署MyApp.app文件夹。对于此签名,Apple“Developer ID Application ...”证书是必需的
我们的食谱是自动的。所有工作都由一个脚本完成。在Qt Creator的情况下,我们使用qmake脚本,我们通过$$system
命令访问系统shell。当使用(Xcode)系统命令codesign
,spctl
或check-signature
中的任何一个时,我们假设您已将stderr重定向到stdout,如answer to question中所述。否则,在运行这些实用程序时,您将无法捕获系统响应。在下文中,我们不会明确显示此重定向。
这是我们的食谱
A.使应用程序独立:
- 将所有需要的二进制文件(带脚本)复制到MyApp.folder
- 运行(使用脚本)qazxsw poi和qazxsw poi,以便app中的所有依赖项都是相对类型
install_name_tool -change
或install_name_tool -id
- 在MyApp.app文件夹中的所有二进制文件上运行(使用脚本)
@executable_path/../MacOS..
并标记任何非法依赖,例如“@rpath ...”或绝对文件路径不是系统路径。请注意,@executable_path/../Frameworks
无法保证找到所有依赖项。插件往往超出otool -L
的视野。这就是你需要下一次检查的原因。- 在“MyApp.app/Contents/MacOS”位置启动终端。运行
otool -L
。然后在同一终端窗口otool
内运行。您的终端将填满数百个已加载的库。再次检查此列表是否有禁止的库(计算机上存在的库,但客户的计算机上没有)。- 布丁的证据就在吃。我们使用
export DYLD_PRINT_LIBRARIES=1
并检查我们的应用程序是否在那里运行。替代解决方案可能是不是开发人员的亲属的Mac。或者您也可以在自己的Mac上创建新用户(“测试”)并将应用程序复制到其下载(或桌面文件夹,或...)。在后一种情况下,您必须临时重命名IDE的根文件夹,否则用户“test”将在那里找到丢失的二进制文件。B签署应用程序
- 签名:使用我们的脚本,我们在应用程序中的所有二进制文件上运行
./MyApp
,然后在app文件夹本身上运行。在每种情况下都会捕获系统响应。它应该在每种情况下都包含字符串“signed Mach-O thin”。- 验证:在应用程序中的每个二进制文件和应用程序本身上运行(使用脚本)命令MacInCloud virtual machines并捕获系统响应。它应该在每种情况下包含字符串“在磁盘上有效”和“满足其指定要求”。
- GateKeeper检查:在每个二进制文件和app文件夹本身上运行(使用脚本)
codesign --force --verify --verbose --sign \"Developer ID Application: ....\" \"/path/to/binary\"
。捕获系统响应。它应该在所有情况下都包含字符串“accepted source”。- check-signature:在每个二进制文件和app文件夹本身上运行(使用脚本)
codesign --verify --verbose \"/path/to/binary\"
。捕获系统响应。在每种情况下,它应包含字符串“YES”。C外部检查
- 将您的应用压缩到一个zip文件中。上传到您的某个云服务器
- GateKeepers在其一般的守门员角色上保留了一长串的例外(通常是数百项)。如果要测试GateKeeper,您的应用必须不在该列表中。而不是编辑此列表更简单的技巧是在Mac上创建新用户。登录该用户并从Internet云服务器下载zip文件。 Finder会自动解压缩它。点击它。如果GateKeeper告诉您它可以打开应用程序,但它会在从Internet下载的同时向您发出警告,那么现在是时候抓一个(白色)啤酒了。
这里是所需的GateKeeper警告:spctl -a -t exec -vv /path/to/binary\"
我的错
我做了大量的安装和签名,没有明确检查每个二进制文件的结果。之后我会在一些二进制文件上使用check-signature \"/path/to/banary\"
但不是全部。我错过了从早期的Qt版本升级到Qt 5.5的事实,二进制获得了额外的依赖,即:otool -L
。我没有注意到它,但GateKeeper做到了。
Qt开发人员可能想知道为什么我们不只是使用libqminimal.dylib
在Mac上部署Qt应用程序。首先,我们不喜欢不使用记录不良的黑盒实用程序。在互联网论坛上,有很多人报道QtDBus
的问题。此外,在比较不同的Qt版本时,Qt库可以具有不同的安装位置(由macdeployqt
报告)。当我们有一个新的Qt版本时,我们的脚本将立即开始对禁止的依赖关系大喊大叫。通过这种方式,我们可以获得有关此新版本中已更改内容的信息。
adlag的问题和自我回答对于帮助我克服同样的问题非常宝贵。然而,和他的食谱一样好,有些陈述不太正确,所以我想提供一些额外的观点。
macdeployqt
和otool-L
检查和删除二进制文件和库中的嵌入路径otool -l $file | grep -A2 LC_RPATH
,以清楚解释为什么GateKeeper会抱怨二进制文件中的路径,以及如何在syslog中查看特定的投诉。install_name_tool -delete_rpath $path $file
。install_name_tool
。您将收到有关资源信封的错误。这是预期的,而不是问题。spctl -a -t exec -vv /path/to/binary
删除Qt安装的绝对路径。然后我使用macdeployqt
创建捆绑包,签署捆绑包并创建DMG文件。我的两位:
install_name_tool
如果您的应用程序已正确签名,您应该会看到一个带有“打开”按钮的系统对话框。
我通过查看从互联网上下载的另一个.app找到了隔离属性的值。我不知道这个价值意味着什么。
我真的不明白为什么spctl命令说“已接受”,即使Gatekeeper服务拒绝打开应用程序。经过多次尝试后想出了问题。
在我的情况下:Pop消息 - 损坏的应用程序是由于库缺失。我使用QT创建了.app文件。要生成dmg,我使用的是deploymacqt命令工具。 deploymacqt工具在.app中创建动态库,所以基本上如果我们在创建dmg之前进行协同编码,这个alter会操纵代码符号。所以正确的解决方法是。
macdeployqt
您需要使用可执行文件的命令行APP_PATH="Any.app"
xattr -w com.apple.quarantine '0081;5a37dc6a;Google Chrome;F15F7E1C-F894-4B7D-91B4-E110D11C4858' "$APP_PATH"
xattr -l "$APP_PATH" # You should see the quarantine attribute here
open "$APP_PATH"
和您的Frameworks验证所有rpath。如果你的可执行文件中有一个本地rpath(例如:/ user / name / Qt /),则将其删除(使用此命令# Create dmg using
deploymacqt <yourapp.app> -dmg
# Open resulted dmg file, copy <yourapp.app> to different folder(let's say /Documents/<yourapp.app>)
# Codesign the /Documents/<yourapp.app> using
codesign --deep --force --verify --verbose --sign "Developer ID Application: <developerid>" <yourapp.app>
# Verify using
codesign --verify --verbose=4 <yourapp.app>
* you should see something like this
<yourapp.app>: valid on disk
<yourapp.app>: satisfies its Designated Requirement
# Now create again the dmg file using dropdmg(https://c-command.com/dropdmg/) application, download, install dropdmg. set the cofiguration preferences with your developer id certificate in signing option.
# drag and drop <yourapp.app> to dropdmg app, wait for creation of dmg to complete. voila you have now successfully created dmg with proper developer id certification.
# verify resulted dmg again using
codesign --verify --verbose=4 <yourapp.dmg>
# you can also verify with gatekeeper
spctl -a -t exec -vv <yourapp.dmg>
)。