Xcode为Unity3D构建向后兼容macOS的Bundle时@available检查失效问题
我需要开发一款在Xcode中构建的Unity3D插件,该插件需调用苹果全新的GameController API,而该API的部分功能仅支持macOS 11及以上版本。
我将插件Bundle的Deployment Target设置为10.15以兼容macOS 10.15环境的构建版本,同时使用Objective-C的@available判断对调用GameController信息查询的代码进行包裹:
if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) { ... }
当Deployment Target为10.15时,即便运行该插件的Unity项目处于macOS 11平台环境下,@available判断始终返回false;若将Deployment Target调整为11,@available判断可正常执行,但在macOS 10.15系统下Unity无法导入该Bundle。
核心疑问:构建这类向后兼容的Bundle的正确方式是什么?我知晓@available是版本运行时检查机制,但不确定该机制是否仍适用于Bundle场景。
- 开发全新的原生Objective-C应用,将该应用和上述Bundle的Deployment Target均设置为10.15,在macOS 11 Beta(Big Sur)系统下运行该应用,通过苹果动态库导入机制运行时加载Bundle并调用其函数时,
@available判断可正确识别系统版本为11 - 保持同一Bundle不变,将其导入运行在相同系统下的Unity项目,通过带有
DllImport特性的C# extern方法调用对应函数时,Bundle内的@available判断却出现失效
出现跨进程版本判断失效的核心逻辑是:@available宏在编译阶段会生成对应版本检查的代码,但这些代码在链接时,会优先复用宿主进程内已存在的同名系统版本判定函数,不会在动态库内部生成独立的判定实现。
Unity 主程序自身的编译部署目标远早于macOS 11,其内置的版本判定函数没有适配macOS 11及以上的版本枚举值,直接劫持了动态库的版本检查逻辑,导致无论实际运行系统版本如何,判断结果都会返回false。
而在原生独立应用的测试场景下,进程内不存在适配老版本的全局判定函数,动态库会使用自身编译时生成的完整判定逻辑,因此版本检查可正常生效。
- 优先改用独立版本判断逻辑替代默认
@available宏:通过NSProcessInfo的operatingSystemVersion接口获取当前运行系统的主、次、修订版本号,自行实现版本比对逻辑。该方式不依赖编译期生成的全局判定符号,不会被宿主进程的逻辑劫持,在Unity环境下可稳定工作。 - 若需使用系统原生的版本检查能力,需调整动态库的链接配置,强制动态库生成独立的版本判定逻辑:
- 在Xcode Build Settings中开启
Dead Code Stripping - 为
Other Linker Flags添加配置,将版本判定相关的内部符号标记为动态库私有符号,避免全局链接复用宿主进程的实现
- 在Xcode Build Settings中开启
- 若插件涉及Swift代码,需开启静态Swift运行时链接选项,避免Swift运行时的版本判定逻辑和Unity主程序的运行时环境冲突。
内容的提问来源于stack exchange,提问作者user15273246

