Перевірити версію ОС у Swift?


191

Я намагаюся перевірити системну інформацію в Swift. Я зрозумів, що це можна досягти за допомогою коду:

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

У мене є дві проблеми з цим кодом:

  1. Яким має бути початкове значення sysData? Цей приклад дає -1 у retVal, ймовірно, тому, що sysData дорівнює нулю.
  2. Як я можу прочитати інформацію з sysData?

Відповіді:


388

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

var systemVersion = UIDevice.current.systemVersion

Для ОС 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, є набагато приємніший спосіб зробити це швидко. Викладено тут ... hackingwithswift.com/new-syntax-swift-2-available-checking
Fogmeister

2
Я можу побачити безпосередньо перевірку версії ОС (на відміну від перевірки конкретних можливостей) - збирати дані про розподіл версій ОС серед ваших користувачів, щоб визначити найнижчу ціль розгортання.
Nicolas Miari

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

EDIT: Просто знайшли інший спосіб досягти цього:

let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)

50

Я зробив допоміжні функції, які були передані з нижньої ланки в швидку:

Як ми можемо програмно виявити, на якій версії 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")

Швидкий 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
}

31

Швидкий 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/


17

Швидкий 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
}

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 {
    // 👎
}

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запиту.


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

Посилання

Операційна системаVersion

Рішення

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 
{
}  

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

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

2

Швидкий 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.


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

Мені шкода, що я не зміг усвідомити, що це XCTest з першого погляду.
DawnSong

1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)

0

Також якщо ви хочете перевірити WatchOS.

Швидкий

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

Ціль-С

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
}

Цей метод не поверне істину з пройденою версією "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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.