Gradle构建的Java应用在macOS Monterey启动失败问题求助
根因说明
该错误底层返回NSPOSIXErrorDomain Code=2 "No such file or directory",核心原因是macOS Monterey收紧了App Bundle的结构校验规则:
- 系统启动应用时会严格校验
Info.plist中声明的主可执行文件路径、内置运行时路径的合法性,不存在路径错放、软链接断链、大小写不匹配的容错空间,早于Monterey的系统版本会自动容错这类配置错误 - 旧版Gradle Java打包插件(包括2.5.0以下版本的badass-runtime/jlink插件、JDK14以下自带的jpackage)生成的App Bundle结构不符合Monterey的校验规则,会触发该启动错误
- 常规权限放开、隔离属性清除、随机顺序签名操作未生效,本质是没有解决最核心的Bundle结构错误,且签名顺序不符合Monterey的代码签名校验逻辑
分步修复方案
第一步:校验App Bundle主可执行文件路径合法性
打开终端依次执行以下命令,检查配置声明的可执行文件是否真实存在:# 进入应用包Contents目录 cd /Applications/MyApp.app/Contents # 读取Info.plist中声明的主可执行文件名 EXEC_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" Info.plist) # 检查MacOS目录下是否存在对应可执行文件 ls -l MacOS/$EXEC_NAME如果最后一条命令返回
No such file or directory,说明打包时可执行文件被错放到其他目录(常见错放路径为Contents/Resources、Contents/Java),将对应文件移动到Contents/MacOS/目录下,保证文件名和CFBundleExecutable声明值完全大小写一致即可。第二步:校验内置Java运行时路径合法性
检查App Bundle内的JRE路径是否完整:# 检查默认打包生成的JRE路径是否存在 ls -ld /Applications/MyApp.app/Contents/runtime/Contents/Home/bin/java如果路径不存在,说明打包时JRE未被正确置入App Bundle,或者启动脚本里写死了Bundle外部的JRE路径(Monterey禁止未授权应用引用包外的可执行文件启动),将对应JRE目录移动到上述路径,或者修改
Contents/MacOS/下的启动脚本,将JAVA_HOME变量改为Bundle内的相对路径../runtime/Contents/Home。第三步:按Monterey要求的顺序重新签名
错误的签名顺序会导致系统判定签名无效,Monterey要求必须从最内层的嵌套资源开始签名,最后签名外层App本体,ad-hoc签名需要额外指定runtime参数:# 先签名内置JRE运行时 sudo codesign --force --deep --sign - /Applications/MyApp.app/Contents/runtime # 再签名所有内置Java依赖、动态库 sudo codesign --force --deep --sign - /Applications/MyApp.app/Contents/Java/* sudo codesign --force --deep --sign - /Applications/MyApp.app/Contents/MacOS/* # 最后签名App本体,添加runtime授权 sudo codesign --force --deep --sign - --options=runtime /Applications/MyApp.app # 校验签名有效性 codesign -vvv /Applications/MyApp.app校验命令返回
valid on disk、satisfies its Designated Requirement即为签名成功。第四步:清除系统启动缓存
之前的失败启动记录会被Launch Services缓存,改完配置后需要重置缓存避免加载旧错误记录:# 清除应用的隔离属性 sudo xattr -r -d com.apple.quarantine /Applications/MyApp.app # 重置该应用的Launch Services注册记录 /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f /Applications/MyApp.app
永久修复方案
如果不想每次打包后手动修改,直接升级项目中使用的Gradle打包插件到最新版本:使用jpackage打包的话升级JDK版本到17及以上;使用badass系列插件的话升级插件版本到2.5.0及以上,新版本插件已经适配Monterey的App Bundle校验规则,打包生成的安装包可以直接正常启动。
调试技巧
如果上述操作后仍无法启动,不要直接双击应用图标,直接在终端执行App Bundle内的主可执行文件:
/Applications/MyApp.app/Contents/MacOS/$EXEC_NAME
终端会直接输出启动过程中的具体报错(比如缺哪个依赖文件、哪个路径找不到),可以直接定位到具体问题点。
内容的提问来源于stack exchange,提问作者Denis

