如何在OS X或iOS中运行OS版本(不使用Gestalt)?

问题描述 投票:64回答:13

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

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

在Cocoa应用程序中,可以使用哪些其他API在运行时检查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);
}
ios macos cocoa macos-carbon
13个回答
62
投票

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

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

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

- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version

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

在iOS上,这些方法实际上仅在iOS 8.0之后可用。


5
投票

uname(3)

qazxsw poi函数存储以null结尾的信息字符串,用于将当前系统标识为uname()引用的结构。

name结构在utsname头文件中定义,包含以下成员:

  • <sys/utsname.h> - 操作系统实现的名称。
  • sysname - 本机的网络名称。
  • nodename - 操作系统的发布级别。
  • release - 操作系统的版本级别。
  • version - 机器硬件平台。

5
投票

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

OS-X以多种方式在运行时提供其版本。每种方式都更适合特定的开发方案。我会试着总结一下,如果我忘记了什么,希望别人能完成我的答案。

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

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

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


3
投票

今天在MacOS上玩/System/Library/CoreServices/SystemVersion.plist的时候我偶然发现了sysctl,它确实包含了当前的操作系统版本。在运行Mojave的Mac上,我得到:

kern.osproductversion

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

$ 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内核代码库表明This commit是2018年中期出现的最新成员。我在10.14.3和10.13.6上成功测试了它。

总而言之,我认为最好的程序化,非Cocoa方法是检查osproductversion是否产生有效结果并回退到kern.osproductversionkern.osrelease中描述的手动映射。


0
投票

比赛结束,但我最终在这里寻找答案。对于它的价值,也许它可以用于其他人;

在过去,我使用命令行方法:

this answer

结果如下:

sw_vers

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

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

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


26
投票

在命令行上:

$ 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);

Darwin版本到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

24
投票

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

if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_7_2) {
    NSLog (@"We are not running on Mountain Lion");
}

18
投票

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

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

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

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

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

它不会被弃用。


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.")
}

11
投票

您可以使用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];

9
投票

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

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

我希望这可以帮助别人。


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.


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 Release Notes

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

© www.soinside.com 2019 - 2024. All rights reserved.