75

位于 OS X 10.8 Mountain Lion 的 Gestalt() 函数CarbonCore/OSUtils.h已被弃用。

我经常使用这个函数在运行时测试 OS X 操作系统的版本(参见下面的玩具示例)。

还有哪些 API 可用于在 Cocoa 应用程序运行时检查 OS X 操作系统版本?

int main() {
    SInt32 versMaj, versMin, versBugFix;
    Gestalt(gestaltSystemVersionMajor, &versMaj);
    Gestalt(gestaltSystemVersionMinor, &versMin);
    Gestalt(gestaltSystemVersionBugFix, &versBugFix);

    printf("OS X Version: %d.%d.%d\n", versMaj, versMin, versBugFix);
}
4

16 回答 16

73

在 OS X 10.10(和 iOS 8.0)上,您可以使用[[NSProcessInfo processInfo] operatingSystemVersion]which 返回一个NSOperatingSystemVersion结构,定义为

typedef struct {
    NSInteger majorVersion;
    NSInteger minorVersion;
    NSInteger patchVersion;
} NSOperatingSystemVersion;

还有一种方法NSProcessInfo可以为您进行比较:

- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version

请注意,虽然记录在 OS X 10.10 及更高版本中可用,但两者都operatingSystemVersion存在isOperatingSystemAtLeastVersion:于 OS X 10.9(可能是 10.9.2)上并按预期工作。这意味着您不能测试是否NSProcessInfo响应这些选择器来检查您是否在 OS X 10.9 或 10.10 上运行。

在 iOS 上,这些方法仅在 iOS 8.0 之后有效。

于 2014-06-02T23:08:39.530 回答
28

在命令行上:

$ sysctl kern.osrelease
kern.osrelease: 12.0.0
$ sysctl kern.osversion
kern.osversion: 12A269

以编程方式:

#include <errno.h>
#include <sys/sysctl.h>

char str[256];
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);

达尔文版本到 OS X 版本:

17.x.x. macOS 10.13.x High Sierra
16.x.x  macOS 10.12.x Sierra
15.x.x  OS X  10.11.x El Capitan
14.x.x  OS X  10.10.x Yosemite
13.x.x  OS X  10.9.x  Mavericks
12.x.x  OS X  10.8.x  Mountain Lion
11.x.x  OS X  10.7.x  Lion
10.x.x  OS X  10.6.x  Snow Leopard
 9.x.x  OS X  10.5.x  Leopard
 8.x.x  OS X  10.4.x  Tiger
 7.x.x  OS X  10.3.x  Panther
 6.x.x  OS X  10.2.x  Jaguar
 5.x    OS X  10.1.x  Puma

获取和测试版本的示例:

#include <string.h>
#include <stdio.h>
#include <sys/sysctl.h>

/* kernel version as major minor component*/
struct kern {
    short int version[3];
};

/* return the kernel version */
void GetKernelVersion(struct kern *k) {
   static short int version_[3] = {0};
   if (!version_[0]) {
      // just in case it fails someday
      version_[0] = version_[1] = version_[2] = -1;
      char str[256] = {0};
      size_t size = sizeof(str);
      int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);
      if (ret == 0) sscanf(str, "%hd.%hd.%hd", &version_[0], &version_[1], &version_[2]);
    }
    memcpy(k->version, version_, sizeof(version_));
}

/* compare os version with a specific one
0 is equal
negative value if the installed version is less
positive value if the installed version is more
*/
int CompareKernelVersion(short int major, short int minor, short int component) {
    struct kern k;
    GetKernelVersion(&k);
    if ( k.version[0] !=  major) return major - k.version[0];
    if ( k.version[1] !=  minor) return minor - k.version[1];
    if ( k.version[2] !=  component) return component - k.version[2];
    return 0;
}

int main() {
   struct kern kern;
   GetKernelVersion(&kern);
   printf("%hd %hd %hd\n", kern.version[0], kern.version[1], kern.version[2]);

   printf("up: %d %d eq %d %d low %d %d\n",
        CompareKernelVersion(17, 0, 0), CompareKernelVersion(16, 3, 0),
        CompareKernelVersion(17, 3, 0), CompareKernelVersion(17,3,0),
        CompareKernelVersion(17,5,0), CompareKernelVersion(18,3,0));


}

我的机器上的结果 macOS High Sierra 10.13.2

17 3 0
up: -3 -1 eq 0 0 low 2 1
于 2012-07-28T01:02:31.250 回答
25

您可以使用 NSAppKitVersionNumber 值来检查 AppKit 的各种版本,尽管它们与操作系统版本不完全对应

if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_7_2) {
    NSLog (@"We are not running on Mountain Lion");
}
于 2012-07-28T00:45:49.220 回答
20

有一个可可 API。您可以从 NSProcessInfo 类中获取 os X 版本字符串。

获取操作系统版本字符串的代码如下..

NSString * operatingSystemVersionString = [[NSProcessInfo processInfo] operatingSystemVersionString];

NSLog(@"operatingSystemVersionString => %@" , operatingSystemVersionString);

// ===>> 版本 10.8.2 (Build 12C2034) 结果值

没有被弃用。

于 2013-06-05T08:44:08.767 回答
12

如果您只需要检查要支持的最低版本,也可以使用 kCFCoreFoundationVersionNumber。这样做的好处是它可以追溯到 10.1,并且可以在 C、C++ 和 Objective-C 中完成。

例如检查 10.10 或更高版本:

#include <CoreFoundation/CoreFoundation.h>
if (floor(kCFCoreFoundationVersionNumber) > kCFCoreFoundationVersionNumber10_9) {
    printf("On 10.10 or greater.");
}

您将需要链接到 CoreFoundation(或 Foundation)框架。

它也以完全相同的方式在 Swift 中工作。这是另一个例子:

import Foundation
if floor(kCFCoreFoundationVersionNumber) > kCFCoreFoundationVersionNumber10_8 {
    println("On 10.9 or greater.")
} else if floor(kCFCoreFoundationVersionNumber) > kCFCoreFoundationVersionNumber10_9 {
    println("On 10.10 or greater.")
}
于 2014-10-24T15:21:51.457 回答
12

您可以使用以下方法轻松获取操作系统的主要、次要、补丁版本NSOperatingSystemVersion

NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];

NSString* major = [NSString stringWithFormat:@"%d", version.majorVersion];


NSString* minor = [NSString stringWithFormat:@"%d", version.minorVersion];


NSString* patch = [NSString stringWithFormat:@"%d", version.patchVersion];
于 2015-07-27T15:52:35.440 回答
9

或者,更简单地说,这里是代码:

NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
NSString *productVersion = [version objectForKey:@"ProductVersion"];
NSLog (@"productVersion =========== %@", productVersion);

我希望这可以帮助别人。

于 2013-02-22T15:13:12.143 回答
8

如果您的应用需要在 10.10 以及之前的版本上运行,这里有一个解决方案:

typedef struct {
        NSInteger majorVersion;
        NSInteger minorVersion;
        NSInteger patchVersion;
} MyOperatingSystemVersion;

if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
    MyOperatingSystemVersion version = ((MyOperatingSystemVersion(*)(id, SEL))objc_msgSend_stret)([NSProcessInfo processInfo], @selector(operatingSystemVersion));
    // do whatever you want with the version struct here
}
else {
    UInt32 systemVersion = 0;
    OSStatus err = Gestalt(gestaltSystemVersion, (SInt32 *) &systemVersion);
    // do whatever you want with the systemVersion as before
}

请注意,即使 10.9 似乎也响应了 operatingSystemVersion 选择器,所以我认为它只是 10.9 中的一个私有 API(但仍然有效)。

这适用于所有版本的 OS X,并且不依赖于字符串解析或文件 I/O。

于 2014-08-12T13:32:45.170 回答
7

这实际上是上面答案的汇编,对有需要的开发人员有一些进一步的指导。

OS-X 以多种方式在运行时提供其版本。每种方式都更适合特定的开发场景。我会尽力总结它们,如果我忘记了什么,希望其他人能完成我的回答。

首先,获取操作系统版本的方法的完整列表。

  1. uname命令行工具和功能提供了操作系统的 unix (darwin) 版本。虽然这不是 OS 的营销版本,但它与它独特地对齐,因此您可以从中推断出 OS-X 的营销版本。
  2. sysctl kern.osrelease命令行(或sysctlbyname("kern.osrelease", str, &size, NULL, 0)函数)将提供与 uname 相同的信息,但更容易解析。
  3. Gestalt(gestaltSystemVersionMajor)(其“ Minor”和BugFix“变体是最古老的(Carbon 之前的!)API,用于获取营销 OS 版本,仍然被长期弃用。在 CoreServices 框架的 C 中可用,但不推荐。
  4. NSAppKitVersionNumber是 AppKit 框架的浮点常量,它将提供 OS-X Appkit 版本(与 OS 版本一致),可用于链接到 AppKit 的所有应用程序。它还提供了所有可能版本的全面枚举(例如NSAppKitVersionNumber10_7_2
  5. kCFCoreFoundationVersionNumber是一个 CoreFoundation 框架浮点常量,与对应的 Appkit 相同,可用于与 CoreFoundation 链接的所有应用程序,包括 C、Obj-C 和 Swift。它也提供了对所有 OS X 发布版本的全面枚举(例如kCFCoreFoundationVersionNumber10_9
  6. [[NSProcessInfo processInfo] operatingSystemVersionString];是 Obj-C 中可用于 OS-X 和 iOS 应用程序的 Cocoa API。
  7. 有一个资源 .plist,/System/Library/CoreServices/SystemVersion.plist其中包含“ProductVersion”键中的操作系统版本。NSProcessInfo 从这个文件中读取它的信息,但是你可以直接使用你选择的 PList 读取 API 来做到这一点。

有关每个选项的更多详细信息 - 请参阅上面的答案。那里有很多信息!

于 2016-04-18T09:55:19.657 回答
6

uname(3)

uname()函数将标识当前系统的以 nul 结尾的信息字符串存储到由 引用的结构中name

utsname结构在<sys/utsname.h>头文件中定义,并包含以下成员:

  • sysname- 操作系统实现的名称。
  • nodename- 本机的网络名称。
  • release - 操作系统的发布级别。
  • version - 操作系统的版本级别。
  • machine - 机器硬件平台。
于 2012-06-17T16:24:56.637 回答
6

这就是我使用的:

NSInteger osxVersion;
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_6) {
    //10.6.x or earlier systems
    osxVersion = 106;
    NSLog(@"Mac OSX Snow Leopard");
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) {
    /* On a 10.7 - 10.7.x system */
    osxVersion = 107;
    NSLog(@"Mac OSX Lion");
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) {
    /* On a 10.8 - 10.8.x system */
    osxVersion = 108;
    NSLog(@"Mac OSX Moutain Lion");
} else {
    /* 10.9 or later system */
    osxVersion = 109;
    NSLog(@"Mac OSX: Mavericks or Later");
}

AppKit 发行说明中推荐

如果应用程序被沙盒化,则无法读取 /System/Library/CoreServices/SystemVersion.plist

于 2014-03-06T13:15:49.887 回答
5

今天在 macOS 上玩的时候,sysctl我偶然发现kern.osproductversion它确实包含当前的操作系统版本。在运行 Mojave 的 Mac 上,我得到:

$ sysctl kern.osproductversion
kern.osproductversion: 10.14.3

当然,也可以通过编程方式检索该值:

char str[256];
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osproductversion", str, &size, NULL, 0);

这个对 xnu 内核代码库的提交表明这osproductversion是 2018 年年中最近添加的。我在 10.14.3 和 10.13.6 上成功测试了它。

总而言之,在我看来,最好的程序化、非 Cocoa 方法是检查是否kern.osproductversion产生有效结果,否则回退到本答案kern.osrelease中描述的手动映射。

于 2019-02-01T19:54:34.727 回答
3

Gestalt()是一个纯 C API。接受的答案建议使用NSProcessInfo但这需要Objective-C代码,如果出于某种原因需要纯C,则不能使用。也是如此NSAppKitVersionNumber,自 10.13.4 以来 Apple 也不再更新。可以在 C 代码中使用该常量kCFCoreFoundationVersionNumber,但自 10.11.4 以来此常量不再更新。在 C 中可以读取kern.osreleaseusing sysctl,但需要映射表或依赖当前的内核版本控制方案,因此对于未来版本不可靠,因为内核版本方案可能会更改,并且映射表无法知道未来版本。

Apple 的官方和推荐方法是阅读/System/Library/CoreServices/SystemVersion.plist,因为这也是Gestalt()获取版本号的地方,这也是NSProcessInfo()获取版本号的地方,这也是命令行工具sw_vers获取版本号的地方,甚至是新@available(macOS 10.x, ...)的编译器功能从中获取版本号(我深入研究了系统以了解这一点)。#available(macOS 10.x, *)如果即使 Swift会从那里获得版本号,我也不会感到惊讶。

从那里读取版本号没有简单的 C 调用,所以我编写了以下纯 C 代码,它只需要CoreFoundation本身是纯 C 框架的框架:

static bool versionOK;
static unsigned versions[3];
static dispatch_once_t onceToken;

static
void initMacOSVersion ( void * unused ) {
    // `Gestalt()` actually gets the system version from this file.
    // Even `if (@available(macOS 10.x, *))` gets the version from there.
    CFURLRef url = CFURLCreateWithFileSystemPath(
        NULL, CFSTR("/System/Library/CoreServices/SystemVersion.plist"),
        kCFURLPOSIXPathStyle, false);
    if (!url) return;

    CFReadStreamRef readStr = CFReadStreamCreateWithFile(NULL, url);
    CFRelease(url);
    if (!readStr) return;

    if (!CFReadStreamOpen(readStr)) {
        CFRelease(readStr);
        return;
    }

    CFErrorRef outError = NULL;
    CFPropertyListRef propList = CFPropertyListCreateWithStream(
        NULL, readStr, 0, kCFPropertyListImmutable, NULL, &outError);
    CFRelease(readStr);
    if (!propList) {
        CFShow(outError);
        CFRelease(outError);
        return;
    }

    if (CFGetTypeID(propList) != CFDictionaryGetTypeID()) {
        CFRelease(propList);
        return;
    }

    CFDictionaryRef dict = propList;
    CFTypeRef ver = CFDictionaryGetValue(dict, CFSTR("ProductVersion"));
    if (ver) CFRetain(ver);
    CFRelease(dict);
    if (!ver) return;

    if (CFGetTypeID(ver) != CFStringGetTypeID()) {
        CFRelease(ver);
        return;
    }

    CFStringRef verStr = ver;
    // `1 +` for the terminating NUL (\0) character
    CFIndex size = 1 + CFStringGetMaximumSizeForEncoding(
        CFStringGetLength(verStr), kCFStringEncodingASCII);
    // `calloc` initializes the memory with all zero (all \0)
    char * cstr = calloc(1, size);
    if (!cstr) {
        CFRelease(verStr);
        return;
    }

    CFStringGetBytes(ver, CFRangeMake(0, CFStringGetLength(verStr)),
        kCFStringEncodingASCII, '?', false, (UInt8 *)cstr, size, NULL);
    CFRelease(verStr);

    printf("%s\n", cstr);

    int scans = sscanf(cstr, "%u.%u.%u",
        &versions[0], &versions[1], &versions[2]);
    free(cstr);
    // There may only be two values, but only one is definitely wrong.
    // As `version` is `static`, its zero initialized.
    versionOK = (scans >= 2);
}


static
bool macOSVersion (
    unsigned *_Nullable outMajor,
    unsigned *_Nullable outMinor,
    unsigned *_Nullable outBugfix
) {
    dispatch_once_f(&onceToken, NULL, &initMacOSVersion);
    if (versionOK) {
        if (outMajor) *outMajor = versions[0];
        if (outMinor) *outMinor = versions[1];
        if (outBugfix) *outBugfix = versions[2];
    }
    return versionOK;
}

使用 adispatch_once_f而不是的原因dispatch_once是块也不是纯 C。完全使用的原因dispatch_once是系统运行时版本号无法更改,因此没有理由在单个应用程序运行期间多次读取版本号。此外,阅读它并不能保证万无一失,而且每次您的应用可能需要它时重新阅读它的成本太高。

谈论不是故障安全,即使它不太可能,阅读它当然可能会失败,在这种情况下,函数会返回false并且总是会返回false。我让你在你的应用程序代码中以有意义的方式处理这种情况,因为我不知道知道版本号对你的应用程序有多重要。如果版本号不重要,也许您可​​以解决它,否则您应该以用户友好的方式使您的应用程序失败。

注意
如果您只需要版本号来执行取决于系统版本的替代代码,则可能有更好的替代方法来查询您自己的版本号。有关详细信息,请参阅此问题

于 2019-06-01T01:03:43.393 回答
0

比赛迟到了,但我最终也在这里寻找答案。对于它的价值,也许它对其他人有用;

过去我使用命令行方法:

sw_vers

结果是:

ProductName:    Mac OS X
ProductVersion: 10.13.6
BuildVersion:   17G65

可以单独询问每一行(注意驼峰符号):

sw_vers -productVersion
10.13.6

sw_vers -productName
Mac OS X

sw_vers -buildVersion
17G65

话虽如此,感谢此处列出的所有其他解决方案...

于 2018-08-14T17:27:00.490 回答
0

//我的 Swift 两分钱(多平台)

#if os(iOS)
import UIKit
#elseif os(OSX)
import Cocoa
#endif



func platform() -> String {
    var systemInfo = utsname()
    uname(&systemInfo)
    let size = Int(_SYS_NAMELEN) // is 32, but posix AND its init is 256....
    
    let s = withUnsafeMutablePointer(to: &systemInfo.machine) {p in
        //    let s = withUnsafeMutablePointer(to: &systemInfo.nodename) {p in
        
        p.withMemoryRebound(to: CChar.self, capacity: size, {p2 in
            return String(cString: p2)
        })
        
    }
    return s
}



func AppName()->String{
    let bund = Bundle.main
    if let displayName = bund.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
        if displayName.count>0{
            return displayName
        }
    }
    
    if let name = bund.object(forInfoDictionaryKey: "CFBundleName") as? String {
        return name
    }
    return "no AppName"
}


func buildVers()->String{
    
    let bund = Bundle.main
    let vers = bund.object(forInfoDictionaryKey: "CFBundleVersion") as! String
    return  vers
}


func AppleStoreVers()->String{
    
    if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
        return version
    }
    return "no.vers."
}



#if os(iOS)
func systemVersion()->String{
    let  v = UIDevice.current.systemVersion
    return v
}
#elseif os(OSX)
#endif
于 2020-08-22T17:43:09.183 回答
0

macOS Catalina 及更高版本的更新

20.x.x  macOS 11.X.X  BigSur
19.x.x  macOS 10.15.x Catalina
18.x.x  macOS 10.14.x Mojave
17.x.x  macOS 10.13.x High Sierra
16.x.x  macOS 10.12.x Sierra
15.x.x  OS X  10.11.x El Capitan
14.x.x  OS X  10.10.x Yosemite
13.x.x  OS X  10.9.x  Mavericks
12.x.x  OS X  10.8.x  Mountain Lion
11.x.x  OS X  10.7.x  Lion
10.x.x  OS X  10.6.x  Snow Leopard
 9.x.x  OS X  10.5.x  Leopard
 8.x.x  OS X  10.4.x  Tiger
 7.x.x  OS X  10.3.x  Panther
 6.x.x  OS X  10.2.x  Jaguar
 5.x    OS X  10.1.x  Puma
于 2020-12-06T08:28:28.680 回答