Tod*_*orf 67 macos cocoa macos-carbon ios
CarbonCore/OSUtils.h自OS X 10.8 Mountain Lion 起,位于的Gestalt()函数已被弃用.
我经常使用此函数在运行时测试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);
}
Run Code Online (Sandbox Code Playgroud)
0xc*_*ced 64
在OS X 10.10(和iOS 8.0)上,您可以使用[[NSProcessInfo processInfo] operatingSystemVersion]返回NSOperatingSystemVersion结构,定义为
typedef struct {
NSInteger majorVersion;
NSInteger minorVersion;
NSInteger patchVersion;
} NSOperatingSystemVersion;
Run Code Online (Sandbox Code Playgroud)
NSProcessInfo中还有一个方法可以为您进行比较:
- (BOOL)isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion)version
Run Code Online (Sandbox Code Playgroud)
当心,虽然记载了OS X 10.10可用后来,双方operatingSystemVersion并isOperatingSystemAtLeastVersion:在OS X 10.9(存在可能10.9.2如预期)和工作.这意味着您不能测试是否NSProcessInfo响应这些选择器以检查您是否在OS X 10.9或10.10上运行.
在iOS上,这些方法实际上仅在iOS 8.0之后可用.
Var*_*der 27
在命令行上:
$ sysctl kern.osrelease
kern.osrelease: 12.0.0
$ sysctl kern.osversion
kern.osversion: 12A269
Run Code Online (Sandbox Code Playgroud)
编程方式:
#include <errno.h>
#include <sys/sysctl.h>
char str[256];
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osrelease", str, &size, NULL, 0);
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
获取和测试版本的示例:
#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));
}
Run Code Online (Sandbox Code Playgroud)
结果我的机器macOs High Sierra 10.13.2
17 3 0
up: -3 -1 eq 0 0 low 2 1
Run Code Online (Sandbox Code Playgroud)
iai*_*ain 24
有NSAppKitVersionNumber值可用于检查各种版本的AppKit,尽管它们与操作系统版本不完全对应
if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_7_2) {
NSLog (@"We are not running on Mountain Lion");
}
Run Code Online (Sandbox Code Playgroud)
小智 19
有一个cocoa API.您可以从NSProcessInfo类获取os X版本字符串.
获取操作系统版本字符串的代码如下:
NSString * operatingSystemVersionString = [[NSProcessInfo processInfo] operatingSystemVersionString];
NSLog(@"operatingSystemVersionString => %@" , operatingSystemVersionString);
Run Code Online (Sandbox Code Playgroud)
// === >>版本10.8.2(Build 12C2034)结果值
它不会被弃用.
kai*_*jow 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.");
}
Run Code Online (Sandbox Code Playgroud)
您需要链接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.")
}
Run Code Online (Sandbox Code Playgroud)
Vik*_*sal 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];
Run Code Online (Sandbox Code Playgroud)
或者,更简单地说,这是代码:
NSDictionary *version = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
NSString *productVersion = [version objectForKey:@"ProductVersion"];
NSLog (@"productVersion =========== %@", productVersion);
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮助别人.
Gestalt()是一个纯C API。接受的答案建议使用NSProcessInfo,但这需要 Objective-C 代码,如果出于某种原因需要纯 C,则不能使用。对于 也是如此NSAppKitVersionNumber,自 10.13.4 以来,Apple 也不再更新它。在 C 代码中可以使用该常量kCFCoreFoundationVersionNumber,但自 10.11.4 以来该常量已不再更新。在 C 中可以进行读取kern.osrelease使用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;
}
Run Code Online (Sandbox Code Playgroud)
dispatch_once_f使用 a代替的原因dispatch_once是块也不是纯 C 语言。使用at的原因dispatch_once是版本号在系统运行时无法更改,因此没有理由在单个应用程序运行期间多次读取版本号。此外,读取它并不能保证万无一失,并且每次您的应用程序可能需要它时重新读取它都太昂贵。
谈论不安全,即使不太可能,读取它当然可能会失败,在这种情况下,函数返回false并且总是会返回false。我让您在应用程序代码中以有意义的方式处理这种情况,因为我不知道了解版本号对您的应用程序有多重要。如果版本号并不重要,也许您可以解决它,否则您应该以用户友好的方式让您的应用程序失败。
注意
如果您只需要版本号来根据系统版本执行替代代码,那么可能有更好的替代方法来自行查询版本号。有关详细信息,请参阅此问题。
如果您的应用程序需要在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
}
Run Code Online (Sandbox Code Playgroud)
请注意,即使10.9似乎响应了operatingSystemVersion选择器,所以我认为它只是10.9中的私有API(但仍然有效).
这适用于所有版本的OS X,不依赖于字符串解析或文件I/O.
这是我使用的:
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");
}
Run Code Online (Sandbox Code Playgroud)
如果应用程序是沙盒,则无法读取/System/Library/CoreServices/SystemVersion.plist
这实际上是上面答案的汇编,有一些进一步指导有需要的开发人员.
OS-X以多种方式在运行时提供其版本.每种方式都更适合特定的开发方案.我会试着总结一下,如果我忘记了什么,希望别人能完成我的答案.
首先,获取操作系统版本的综合方法列表.
uname命令行工具和功能提供OS的UNIX(达尔文)版本.虽然这不是操作系统的营销版本,但它与其唯一对齐,因此您可以从中推断出OS-X营销版本.sysctl kern.osrelease命令行(或sysctlbyname("kern.osrelease", str, &size, NULL, 0)函数)将提供与uname相同的信息,稍微容易解析.Gestalt(gestaltSystemVersionMajor)(其" Minor"和BugFix"变体是最古老的(pre-Carbon!)API获取营销操作系统版本,仍然受到长期弃用的支持.可从CoreServices框架获得C,但不推荐.NSAppKitVersionNumber是AppKit框架的浮点常量,它将提供OS-X Appkit版本(与操作系统版本一致),可用于链接AppKit的所有应用程序.它还提供了所有可能版本的全面列举(例如NSAppKitVersionNumber10_7_2)kCFCoreFoundationVersionNumber是一个CoreFoundation框架浮点常量,与Appkit对应相同,可用于所有与CoreFoundation链接的应用程序,包括C,Obj-C和Swift.它也提供了所有OS X发布版本的全面枚举(例如kCFCoreFoundationVersionNumber10_9)[[NSProcessInfo processInfo] operatingSystemVersionString]; 是Obj-C中可用于OS-X和iOS应用程序的Cocoa API./System/Library/CoreServices/SystemVersion.plist其中包含"ProductVersion"键中的操作系统版本.NSProcessInfo从此文件中读取其信息,但您可以使用您选择的PList-reading API直接执行此操作.有关每个选项的更多详细信息 - 请参阅上面的答案.那里有很多信息!
有uname(3):
该
uname()函数存储以nul结尾的信息字符串,用于将当前系统标识为引用的结构name.该
utsname结构在定义<sys/utsname.h>头文件中,并包含下列成员:
sysname- 操作系统实现的名称.nodename- 本机的网络名称.release- 释放操作系统级别.version- 操作系统的版本级别.machine- 机器硬件平台.
sysctl今天在 macOS 上玩弄时,我偶然发现kern.osproductversion其中确实包含当前的操作系统版本。在运行 Mojave 的 Mac 上,我得到:
$ sysctl kern.osproductversion
kern.osproductversion: 10.14.3
Run Code Online (Sandbox Code Playgroud)
当然,也可以通过编程方式检索该值:
char str[256];
size_t size = sizeof(str);
int ret = sysctlbyname("kern.osproductversion", str, &size, NULL, 0);
Run Code Online (Sandbox Code Playgroud)
对 xnu 内核代码库的提交表明这osproductversion是 2018 年中期的最新添加。我在 10.14.3 和 10.13.6 上成功测试了它。
总而言之,在我看来,最好的程序化、非 Cocoa 方法是检查是否kern.osproductversion产生有效的结果,否则返回到本答案中kern.osrelease所述的手动映射。
| 归档时间: |
|
| 查看次数: |
50050 次 |
| 最近记录: |