前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >macOS 应用正确签名并公证后分发依然提示“无法验证开发者”

macOS 应用正确签名并公证后分发依然提示“无法验证开发者”

作者头像
我与梦想有个约会
发布2023-10-21 15:38:38
4720
发布2023-10-21 15:38:38
举报
文章被收录于专栏:jiajia_dengjiajia_deng

问题现象

应用使用正确的证书签名并使用 Apple 推荐的新公证手段公证后,将应用分发给其他人使用时,依然提示无法验证开发者,如下图所示:

问题结论

先说结论,各位看到文章可以先检查,如果你的情况并不是这种原因,在参考下面的排查思路。 原因是 CMake 工程使用 Unix Makefile 而未使用 Xcode generator 编译了依赖库导致运行时未能正确校验开发者信息。

排查思路

要验证问题是否解决需要先明确问题如何出现的(重现问题),应用在本地签名、公证后,如果你是通过类似 POPO 的软件内网传输给其他人,macOS 的检查机制是不会生效的,你需要将应用上传到某 Web 服务器后提供给用户下载时才会触发,这里是先要明确的一点。 根据 Apple 官方文档介绍,给出了几个明确的注意事项如使用正确的证书进行签名、启用强化运行时、启用时间戳选项等,参考官方文档。以下为逐一验证几个步骤的过程。

确认签名结果

CI 签名输出没有任何异常:

代码语言:javascript
复制
/Users/yunxin/builds/jFP7tNUz/0/yunxin-app/xkit-desktop/exports/bin/NetEaseMeeting.app: replacing existing signature
/Users/yunxin/builds/jFP7tNUz/0/yunxin-app/xkit-desktop/exports/bin/NetEaseMeeting.app: signed app bundle with Mach-O thin (arm64) [com.netease.nmc.Meeting]

确认公证结果

CI 公证结果没有任何异常

代码语言:javascript
复制
$ xcrun notarytool submit ${PACKAGE_NAME} --apple-id 2894220@qq.com --team-id 569GNZ5392 --password hjci-yfif-****-**** --wait
Conducting pre-submission checks for meeting-darwin-arm64-release-3-12-0-586-build-1934739.dmg and initiating connection to the Apple notary service...
Submission ID received
  id: 60e58388-1725-4958-8975-04e48b0d9e09
Successfully uploaded file
  id: 60e58388-1725-4958-8975-04e48b0d9e09
  path: /Users/yunxin/builds/1ns5YV66/0/yunxin-app/xkit-desktop/meeting-darwin-arm64-release-3-12-0-586-build-1934739.dmg
Waiting for processing to complete.
Current status: Accepted....................Processing complete
  id: 60e58388-1725-4958-8975-04e48b0d9e09
  status: Accepted
$ xcrun stapler staple ${PACKAGE_NAME}
Processing: /Users/yunxin/builds/1ns5YV66/0/yunxin-app/xkit-desktop/meeting-darwin-arm64-release-3-12-0-586-build-1934739.dmg
Processing: /Users/yunxin/builds/1ns5YV66/0/yunxin-app/xkit-desktop/meeting-darwin-arm64-release-3-12-0-586-build-1934739.dmg
The staple and validate action worked!
Job succeeded

检查签名

使用如下命令检查应用的签名信息:

代码语言:javascript
复制
codesign -vvv --deep --strict /Applications/网易会议.app

输出后结果一切正常,因为结果较多,仅贴一部分,因为不是重点:

代码语言:javascript
复制
--prepared:/Applications/网易会议.app/Contents/Frameworks/nem_hosting_module.framework/Versions/Current/.
--validated:/Applications/网易会议.app/Contents/Frameworks/nem_hosting_module.framework/Versions/Current/.
--prepared:/Applications/网易会议.app/Contents/Frameworks/NetEaseMeetingClient.app
--prepared:/Applications/网易会议.app/Contents/Frameworks/NetEaseMeetingClient.app/Contents/PlugIns/position/libqtposition_positionpoll.dylib
--validated:/Applications/网易会议.app/Contents/Frameworks/NetEaseMeetingClient.app/Contents/PlugIns/position/libqtposition_positionpoll.dylib
--prepared:/Applications/网易会议.app/Contents/Frameworks/NetEaseMeetingClient.app/Contents/PlugIns/position/libqtposition_cl.dylib
--validated:/Applications/网易会议.app/Contents/Frameworks/NetEaseMeetingClient.app/Contents/PlugIns/position/libqtposition_cl.dylib

官方文档:https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735

检查公证

使用如下命令检查应用是否已经在 Apple 进行公证,输出结果一切正常,accepted 表示已经公证:

代码语言:javascript
复制
➜  ~ spctl --assess --verbose /Applications/网易会议.app
/Applications/网易会议.app: accepted
source=Notarized Developer ID

检查强化运行时及时间戳

给应用签名时明确指定了强化运行时配置文件并启用了时间戳选项,这里排除:

代码语言:javascript
复制
COMMAND codesign --entitlements=${CMAKE_SOURCE_DIR}/meeting/bin/NetEaseMeeting.entitlements --timestamp --options=runtime -f -s "06C66D0DDF51A99C6A5C0F65BF9B2ABB5FD409B4" -v ${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}.app --deep

排除依赖库

经过以上步骤确认了签名、公证均没有异常。最后还是要对产物进行检查,因为历史版本相同的代码生成的应用是没有问题的,有差异的点只有工程组织方式,由原来的本地 QMake + CMake 全面修改为 CMake,并且依赖的三方库使用 conan 进行管理了。 为了排查差异,依次排除可能有异常的三方库,最后锁定到内部使用的一个名为 roomkit 的库上。当不拷贝该库文件到 App bundle 中时进行签名并公证,对端是可以正常显示是否打开应用的提示可以直接打开,如下所示:

当然 roomkit 是必须要依赖的模块,我们不可能直接移除掉该模块,接下来还是排查 roomkit 模块可能得影响点。

排除 Info.plist 差异

经过对比旧版与新版 Info.plist 文件有一些差异,将旧版 Info.plist 拷贝过来使用后依然有问题,该情况排除。

替换 framework 为 dylib

怀疑 framework 格式有问题导致无法验证开发者信息,随后将 roomkit 产物修改为 dylib 文件,修改后问题依然存在,该情况排除。

检查 CMake generator

新的工程管理方案将 roomkit 使用 conan 管理了,在生成 roomkit 时虽然使用 CMake 驱动,但 generator 使用的是 Unix Makefile。当切换 CMake generator 为 Xcode 后依然没有解决问题。

将工 roomkit 移动到主工程

不使用 conan 管理后,将源代码移动到主工程后该问题消失了,重新编译并签名公证后,对端是可以正常运行该程序的,不会提示无效的开发者。

于是对比基于同一工程和使用 conan 管理的两个打包后的产物,文件大小一致、代码一致、签名无误。当检查组件依赖时发现了端倪,有问题的包中包含很多 LC_RPATH 为本地 conan 缓存的目录,运行 otool -l libroomkit.dylib 后如下所示:

代码语言:javascript
复制
Load command 36
          cmd LC_RPATH
      cmdsize 144
         path /Users/jj.deng/.conan/data/ne_chromium_base/0.3.0-alpha.15/yunxin/testing/package/7912296e46b47bb505a62f9071f79fb8a6b1cef1/lib (offset 12)
Load command 37
          cmd LC_RPATH
      cmdsize 128
         path /Users/jj.deng/.conan/data/alog/1.1.3-alpha.56/yunxin/testing/package/2f2de4e3345f667bb03ed16a03f45c72c978d397/lib (offset 12)
Load command 38
          cmd LC_RPATH
      cmdsize 120
         path /Users/jj.deng/.conan/data/nim/9.10.0/yunxin/testing/package/c03875a8be5fc1f094417d3708316280c7dde200/lib (offset 12)
Load command 39
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/libevent/2.1.12/_/_/package/98268102ce1d6461fd77de96dbfe521aa4569a60/lib (offset 12)
Load command 40
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/sqlcipher/4.5.0/_/_/package/05d14d2fa2a4ecf20bb6d2fc8daa0c4823efd82d/lib (offset 12)
Load command 41
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/libcurl/7.88.1/_/_/package/d699a8117ee89877a5435732a284bd66e73e8db3/lib (offset 12)
Load command 42
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/jsoncpp/1.9.4/_/_/package/2f2de4e3345f667bb03ed16a03f45c72c978d397/lib (offset 12)
Load command 43
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/gtest/1.11.0/_/_/package/fb16a498e820fb09d04ff9374a782b5b21da0601/lib (offset 12)
Load command 44
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/libuv/1.41.1/_/_/package/240c2182163325b213ca6886a7614c8ed2bf1738/lib (offset 12)
Load command 45
          cmd LC_RPATH
      cmdsize 136
         path /Users/jj.deng/.conan/data/tinyNET/0.1.0-21-g1e1d3f15/yunxin/testing/package/7580092a53c9c8b599007449ce80de252bf43516/lib (offset 12)
Load command 46
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/openssl/1.1.1n/_/_/package/240c2182163325b213ca6886a7614c8ed2bf1738/lib (offset 12)
Load command 47
          cmd LC_RPATH
      cmdsize 112
         path /Users/jj.deng/.conan/data/zlib/1.2.13/_/_/package/240c2182163325b213ca6886a7614c8ed2bf1738/lib (offset 12)
Load command 48
          cmd LC_RPATH
      cmdsize 136
         path /Users/jj.deng/.conan/data/tinySAK/0.1.0-13-g07d29b61/yunxin/testing/package/2f2de4e3345f667bb03ed16a03f45c72c978d397/lib (offset 12)
Load command 49
          cmd LC_RPATH
      cmdsize 120
         path /Users/jj.deng/.conan/data/nertc/5.3.3/yunxin/testing/package/9aa227859c38818147bd790129a73a89bce37027 (offset 12)

而正常可以运行的包是没有这样的问题的,本质的区别在于,当 roomkit 在主工程编译时,会执行 cmake install 流程,install 以后 LC_RPATH 的信息会被清理,而使用 conan 管理的 roomkit 仅仅进行了编译,并没有执行 cmake install。重新修改 conanfile.py 的导出包流程,使用 cmake install 后的产物作为依赖后,该问题消失。修改代码对比:

修改前,我们仅仅进行了 build,并且使用 conan 提供的 package 函数,将 cmake 缓存目录下的文件直接拷贝到了产物输出目录。而修改后,直接在 package 函数中执行cmake.install()这样 cmake 会自动拷贝产物到 package 目录并且删除了原产物的 LC_RPATH。conan 在调用 cmake 初始化包的时候,会自动设置 CMAKE_INSTALL_PREFIX 为 conan 包输出目录,所以这里你不用关心会 install 的目录设置问题。参考 conan 官方文档:https://docs.conan.io/1/howtos/cmake_install.html

总结

至此该问题水落石出,最终还是 Gatekeeper 机制让我们再次踩了个坑,在解决完问题后,我尝试在 Google 中搜索(这个时候 ChatGPT 基本上是一本正经的胡说八道)类似问题,果然找到了与我问题贴近的帖子:https://developer.apple.com/forums/thread/128038

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题现象
  • 问题结论
  • 排查思路
    • 确认签名结果
      • 确认公证结果
        • 检查签名
          • 检查公证
            • 检查强化运行时及时间戳
              • 排除依赖库
                • 排除 Info.plist 差异
                • 替换 framework 为 dylib
                • 检查 CMake generator
                • 将工 roomkit 移动到主工程
            • 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档