Проверить версию ОС в Swift?

191

Я пытаюсь проверить системную информацию в Swift. Я понял, что это может быть достигнуто с помощью кода:

var sysData:CMutablePointer<utsname> = nil
let retVal:CInt = uname(sysData)

У меня есть две проблемы с этим кодом:

  1. Каким должно быть начальное значение sysData? Этот пример дает -1 в retVal, вероятно, потому что sysData - ноль.
  2. Как я могу прочитать информацию из sysData?
Gergely
источник

Ответы:

388

Для iOS попробуйте:

var systemVersion = UIDevice.current.systemVersion

Для OS X попробуйте:

var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion

Если вы просто хотите проверить, работает ли у пользователей хотя бы определенная версия, вы также можете использовать следующую функцию Swift 2, которая работает на iOS и OS X:

if #available(iOS 9.0, *) {
    // use the feature only available in iOS 9
    // for ex. UIStackView
} else {
    // or use some work around
}

НО не рекомендуется проверять версию ОС. Лучше проверить, доступна ли функция, которую вы хотите использовать, на устройстве, чем сравнивать номера версий. Для iOS, как упоминалось выше, вы должны проверить, реагирует ли она на селектор; например.:

if (self.respondsToSelector(Selector("showViewController"))) {
    self.showViewController(vc, sender: self)
} else {
    // some work around
}
Михо
источник
Хотя это верно для цели c, есть более хороший способ сделать это быстро. Обрисовано в общих
чертах
2
Одно из применений, которое я вижу для прямой проверки версии ОС (в отличие от проверки конкретных возможностей), - это сбор данных о распределении версий ОС среди ваших пользователей, чтобы определить наименьшую цель развертывания.
Николас Миари
91

Обновление:
теперь вы должны использовать новую проверку доступности, представленную в Swift 2:
например, чтобы проверить iOS 9.0 или новее во время компиляции, используйте это:

if #available(iOS 9.0, *) {
    // use UIStackView
} else {
    // show sad face emoji
}

или может использоваться с целым методом или классом

@available(iOS 9.0, *)
func useStackView() {
    // use UIStackView
}

Для получения дополнительной информации см. Это .

Проверка времени выполнения:

если вам не нужна точная версия, но вы хотите проверить iOS 9,10 или 11, используя:

let floatVersion = (UIDevice.current.systemVersion as NSString).floatValue

РЕДАКТИРОВАТЬ: Просто нашел другой способ добиться этого:

let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)
Акс
источник
50

Я сделал вспомогательные функции, которые были перенесены из ссылки ниже в swift:

Как мы можем программно определить, на какой версии iOS работает устройство?

func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(version,
        options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
}

func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(version,
        options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
}

func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(version,
        options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
}

func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(version,
        options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
}

func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.currentDevice().systemVersion.compare(version,
        options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
}

Это можно использовать так:

SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO("7.0")

Swift 4.2

func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedSame
}

func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedDescending
}

func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) != .orderedAscending
}

func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == .orderedAscending
}

func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) != .orderedDescending
}
KVISH
источник
31

Swift 5

Нам не нужно создавать расширение, так как ProcessInfoдает нам информацию о версии. Вы можете увидеть пример кода для iOS, как показано ниже.

let os = ProcessInfo().operatingSystemVersion

switch (os.majorVersion, os.minorVersion, os.patchVersion) {
case (let x, _, _) where x < 8:
    print("iOS < 8.0.0"

case (8, 0, _):
    print("iOS >= 8.0.0, < 8.1.0")

case (8, _, _):
    print("iOS >= 8.1.0, < 9.0")

case (9, _, _):
    print("iOS >= 9.0.0")

default:
    print("iOS >= 10.0.0")
}

Ссылка: http://nshipster.com/swift-system-version-checking/

nahung89
источник
17

Swift 5

func run() {
    let version = OperatingSystemVersion(majorVersion: 13, minorVersion: 0, patchVersion: 0)
    if ProcessInfo.processInfo.isOperatingSystemAtLeast(version) {
        runNewCode()
    } else {
        runLegacyCode()
    }
}

func runNewCode() {
    guard #available(iOS 13.0, *) else {
        fatalError()
    }
    // do new stuff
}

func runLegacyCode() {
    // do old stuff
}
neoneye
источник
1
почему в runNewCode требуется #available (iOS 11.0, *)?
Илья Крит
1
@IllyaKrit #available(...)Блок останавливает отображение компилятором ошибок для кода, который не поддерживается в версиях, более старых, чем предусмотрено.
Адам будущего
15

Я сделал этот Singleton для простого использования, создал IOSVersion.swiftфайл и добавил этот код:

import UIKit

public class IOSVersion {
    class func SYSTEM_VERSION_EQUAL_TO(version: NSString) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
    }

    class func SYSTEM_VERSION_GREATER_THAN(version: NSString) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version as String,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
    }

    class func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: NSString) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version as String,
            options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
    }

    class func SYSTEM_VERSION_LESS_THAN(version: NSString) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version as String,
            options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
    }

    class func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: NSString) -> Bool {
        return UIDevice.currentDevice().systemVersion.compare(version as String,
            options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
    }
}

ИСПОЛЬЗОВАНИЕ:

IOSVersion.SYSTEM_VERSION_EQUAL_TO("8.0")
IOSVersion.SYSTEM_VERSION_LESS_THAN("8.0")

Спасибо @KVISH

Редактировать Swift 2:

if #available(iOS 9.0, *) {
    // 👍 
} else {
    // 👎
}
YannSteph
источник
4
Это синглтон? или просто класс функций на IOSVersion? не было бы static let shared = IOSVersion
одиночки
9

Если вы используете Swift 2 и хотите проверить версию ОС, чтобы использовать определенный API, вы можете использовать новую функцию доступности:

if #available(iOS 8, *) {
    //iOS 8+ code here.
}
else {
    //Code for iOS 7 and older versions.
    //An important note: if you use #availability, Xcode will also 
    //check that you don't use anything that was introduced in iOS 8+
    //inside this `else` block. So, if you try to use UIAlertController
    //here, for instance, it won't compile. And it's great.
}

Я написал этот ответ, потому что это первый вопрос в Google для swift 2 check system versionзапроса.

FreeNickname
источник
7

Обновление для Swift 3.0+

func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedSame
}

func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedDescending
}

func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedAscending
}

func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) == ComparisonResult.orderedAscending
}

func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedDescending
}
Меллонг Лау
источник
1
Можно пропустить, ComparisonResultчтобы сделать его короче.
Джон Пан
Кроме того, учет UIDevice.current.systemVersion.compare(version, options: .numeric)в funcможет помочь чтению кода.
Джон Пан
5

подробности

  • Xcode 10.2.1 (10E1001), Swift 5

связи

OperatingSystemVersion

Решение

extension OperatingSystemVersion {
    func getFullVersion(separator: String = ".") -> String {
        return "\(majorVersion)\(separator)\(minorVersion)\(separator)\(patchVersion)"
    }
}

let os = ProcessInfo().operatingSystemVersion
print(os.majorVersion)          // 12
print(os.minorVersion)          // 2
print(os.patchVersion)          // 0
print(os.getFullVersion())      // 12.2.0
Василий Боднарчук
источник
1
Нет ли проблем с округлением при использовании Doubleномера версии, например 10.0999вместо 10.1?
mschmidt
Нет var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999, это напечатает10.0999
Василий Боднарчук
4
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue

let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8

и проверить как

if(iOS8)
{

}
else 
{
}  
poojathorat
источник
4

Самый простой и простой способ проверить версию системы (и многих других версий) в Swift 2 и выше:

if #available(iOS 9.0, *) { // check for iOS 9.0 and later

}

Кроме того, #availableвы можете проверить версии этих:

iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
Tengai
источник
2

Мэтт Томпсон делится очень удобным способом

switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) {
case .OrderedSame, .OrderedDescending:
    println("iOS >= 8.0")
case .OrderedAscending:
    println("iOS < 8.0")
}
dVaffection
источник
2

Swift 4.x

func iOS_VERSION_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedSame
}

func iOS_VERSION_GREATER_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending
}

func iOS_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) != ComparisonResult.orderedAscending
}

func iOS_VERSION_LESS_THAN(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedAscending
}

func iOS_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
    return UIDevice.current.systemVersion.compare(version, options: NSString.CompareOptions.numeric) != ComparisonResult.orderedDescending
}

Использование:

if iOS_VERSION_GREATER_THAN_OR_EQUAL_TO(version: "11.0") {
    //Do something!
}

PS KVISH ответ переведен на Swift 4.x с переименованием функций, так как я специально использую этот фрагмент для приложения iOS.

Hemang
источник
1

Примечание. Доступно в iOS 8.0 и более поздних версиях. OS X v10.10 и позже

var majorVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.majorVersion }
var minorVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.minorVersion }
var patchVersion: Int    { return NSProcessInfo.processInfo().operatingSystemVersion.patchVersion }
var myOSVersion:  String { return NSProcessInfo.processInfo().operatingSystemVersionString        }
Лео Дабус
источник
1

Основываясь на ответе Мэтта Томпсона, вот метод с соответствующими модульными тестами, который работает с Swift и Objective-c на iOS 7 и выше (включая iOS 9, которая больше не позволяет проверять NSFoundationNumber ):

+ (BOOL) isAtLeastOSVersion:(NSString *)osVersion
{
    switch ([[UIDevice currentDevice].systemVersion compare:osVersion options:NSNumericSearch]) {
        case NSOrderedSame:
        case NSOrderedDescending:
            return YES;
        default:
            return NO;
    }
}  

,

@interface ANFakeCurrDevice : NSObject
@property (nonatomic, strong) NSString *systemVersion;
@end
@implementation ANFakeCurrDevice
@end


@implementation MyHelperClassUnitTests

- (void)setUp {
    [super setUp];
}

- (void)tearDown {
    [super tearDown];
}

- (void)test_isAtLeastOSVersion
{
    id deviceMock = [OCMockObject niceMockForClass:[UIDevice class]];
    ANFakeCurrDevice *fakeCurrDevice = [ANFakeCurrDevice new];
    fakeCurrDevice.systemVersion = @"99.9.9";
    [[[deviceMock stub] andReturn:fakeCurrDevice] currentDevice];
    XCTAssertTrue([[UIDevice currentDevice].systemVersion isEqualToString:@"99.9.9"]);

    fakeCurrDevice.systemVersion = @"1.0.1";
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1"]);
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1.0"]);
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"1.0.1"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"1.0.2"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"1.1.0"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0.0"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.0.1"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"2.1.0"]);


    fakeCurrDevice.systemVersion = @"8.4.0";
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"7.0.1"]);
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8"]);
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"8.4.1"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"8.4.2"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0.1"]);
    XCTAssertFalse([ANConstants isAtLeastOSVersion:@"9.0.2"]);
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"] && ![ANConstants isAtLeastOSVersion:@"9.0"]);

    fakeCurrDevice.systemVersion = @"8.4.1";
    XCTAssertTrue([ANConstants isAtLeastOSVersion:@"8.4"] && ![ANConstants isAtLeastOSVersion:@"9.0"]);
}


@end
n8tr
источник
Вы понимаете, что метод очень короткий и компактный, и я просто добавил код модульного теста для иллюстрации и доказательства того, что он работает, верно?
n8tr
Мне жаль, что я не понял, что это XCTest с первого взгляда.
DawnSong
1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
Matjan
источник
0

Также, если вы хотите проверить WatchOS.

стриж

let watchOSVersion = WKInterfaceDevice.currentDevice().systemVersion
print("WatchOS version: \(watchOSVersion)")

Objective-C

NSString *watchOSVersion = [[WKInterfaceDevice currentDevice] systemVersion];
NSLog(@"WatchOS version: %@", watchOSVersion);
Эдисон
источник
0

Получить текущую версию системы и разделить ее. Таким образом, вы можете получить мажорную и минорную версию.

let sys_version = UIDevice.current.systemVersion
let all_version = sys_version.components(separatedBy: ".")
print("Major version : \(all_version[0])")
print("Minor version : \(all_version[1])")
Мили Шах
источник
0

Большинство примеров кода, написанных здесь, получат неожиданный результат с ненулевыми версиями. Например,

func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
return UIDevice.current.systemVersion.compare(version, options: .numeric) != ComparisonResult.orderedAscending
}

Этот метод не вернет true с переданной версией "10.3.0" в iOS "10.3". Этот вид результата не имеет смысла, и они должны рассматриваться как одна и та же версия. Чтобы получить точный результат сравнения, мы должны рассмотреть сравнение всех числовых компонентов в строке версии. Кроме того, предоставление глобальных методов всеми заглавными буквами не является хорошим способом. Поскольку тип версии, который мы используем в нашем SDK, является String, имеет смысл расширять функции сравнения в String.

Чтобы сравнить версию системы, все следующие примеры должны работать.

XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThan: "99.0.0"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(equalTo: UIDevice.current.systemVersion))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThan: "3.5.99"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(lessThanOrEqualTo: "10.3.0.0.0.0.0.0"))
XCTAssertTrue(UIDevice.current.systemVersion.isVersion(greaterThanOrEqualTo: "10.3"))

Вы можете проверить это в моем хранилище здесь https://github.com/DragonCherry/VersionCompare

DragonCherry
источник