旧SDK编译的x86_64应用如何在Apple Silicon Mac获取真实macOS版本
问题背景
- 采用macOS 10.15 SDK编译的x86_64架构应用,通过Rosetta 2运行在Apple Silicon芯片的macOS 11+设备上时,所有常规系统版本获取API、
sysctlbyname("kern.osproductversion", ...)均会返回伪装的兼容版本号10.16,无法获取真实系统版本。
解决方案
方案1:直接读取系统版本属性列表(推荐)
系统真实版本号明文存储在/System/Library/CoreServices/SystemVersion.plist文件中,该文件不受SDK兼容层、Rosetta转译环境的版本伪装逻辑影响,所有用户(包括沙盒应用)均有读取权限,解析即可拿到真实版本:
// Objective-C 示例代码 NSString *versionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist"; NSDictionary *systemVersionInfo = [NSDictionary dictionaryWithContentsOfFile:versionPlistPath]; NSString *realOSVersion = systemVersionInfo[@"ProductVersion"];
注意:不要尝试读取同目录下的
ServerVersion.plist,该文件仅在安装了macOS Server组件的设备上存在,普通消费级系统无此文件。
如果是纯C实现,可以用CoreFoundation的API解析该plist,同样不需要依赖Foundation框架。
方案2:内核版本映射法(无Foundation/CoreFoundation依赖场景适用)
Rosetta兼容层不会伪装kern.osrelease字段返回的内核版本号,可通过该值映射得到真实macOS版本:
- 调用
sysctlbyname("kern.osrelease", ...)获取内核版本字符串 - 提取字符串第一段的主版本号,按对应关系映射即可:
- 内核主版本20 → macOS 11.x (Big Sur)
- 内核主版本21 → macOS 12.x (Monterey)
- 内核主版本22 → macOS 13.x (Ventura)
- 内核主版本23 → macOS 14.x (Sonoma)
- 内核主版本24 → macOS 15.x (Sequoia)
// C 示例代码 size_t bufSize = 0; sysctlbyname("kern.osrelease", NULL, &bufSize, NULL, 0); char *kernelVersion = malloc(bufSize); sysctlbyname("kern.osrelease", kernelVersion, &bufSize, NULL, 0); // 解析kernelVersion字符串,取第一个'.'前的数字即为主版本号,按映射关系匹配系统版本 free(kernelVersion);
该方案无需读取文件系统,但需要随macOS版本更新维护映射关系,适合纯C、无系统框架依赖的开发场景。
旧方案失效原因
Apple为了保证未适配macOS 11新SDK的旧应用能正常运行,对所有链接macOS 11.0之前SDK的应用做了版本兼容伪装:无论实际运行的系统版本是多少,上层版本API、kern.osproductversion sysctl节点都会返回10.16,避免旧应用中硬编码的版本判断逻辑(例如判断系统版本>=11时走新分支但未做兼容)触发崩溃或异常。上述两个方案均绕过了该兼容伪装层,直接读取未被篡改的原始系统信息,因此可以拿到准确结果。
内容的提问来源于stack exchange,提问作者Bri Bri
相关产品推荐
相关产品推荐

