Sprawdź wersję systemu operacyjnego w Swift?

191

Próbuję sprawdzić informacje o systemie w Swift. Doszedłem do wniosku, że można to osiągnąć za pomocą kodu:

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

Mam dwa problemy z tym kodem:

  1. Jaka powinna być początkowa wartość sysData? Ten przykład podaje -1 w retVal prawdopodobnie dlatego, że sysData ma wartość zero.
  2. Jak mogę odczytać informacje z sysData?
Gergely
źródło

Odpowiedzi:

388

W systemie iOS spróbuj:

var systemVersion = UIDevice.current.systemVersion

W przypadku systemu OS X spróbuj:

var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion

Jeśli chcesz tylko sprawdzić, czy użytkownicy mają uruchomioną co najmniej określoną wersję, możesz również skorzystać z następującej funkcji Swift 2, która działa na iOS i OS X:

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

ALE nie jest zalecane sprawdzanie wersji systemu operacyjnego. Lepiej sprawdzić, czy funkcja, której chcesz użyć, jest dostępna na urządzeniu, niż porównywać numery wersji. W przypadku systemu iOS, jak wspomniano powyżej, należy sprawdzić, czy odpowiada na selektor; na przykład.:

if (self.respondsToSelector(Selector("showViewController"))) {
    self.showViewController(vc, sender: self)
} else {
    // some work around
}
miho
źródło
Chociaż jest to poprawne w przypadku celu c, istnieje o wiele ładniejszy sposób, aby to zrobić szybko. Przedstawiono tutaj ... hackingwithswift.com/new-syntax-swift-2-availability-checking
Fogmeister
2
Jednym ze sposobów, w jaki mogę bezpośrednio sprawdzić wersję systemu operacyjnego (w przeciwieństwie do sprawdzania określonych możliwości), jest zebranie danych o dystrybucji wersji systemu operacyjnego wśród użytkowników w celu ustalenia najniższego docelowego poziomu wdrożenia.
Nicolas Miari,
91

Aktualizacja:
Teraz powinieneś użyć nowego sprawdzania dostępności wprowadzonego w Swift 2:
np. Aby sprawdzić w systemie iOS 9.0 lub nowszym w czasie kompilacji, użyj tego:

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

lub może być użyty z całą metodą lub klasą

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

Aby uzyskać więcej informacji, zobacz to .

Kontrola czasu pracy:

jeśli nie chcesz dokładnej wersji, ale chcesz sprawdzić iOS 9,10 lub 11 przy użyciu, jeśli:

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

EDYCJA: Właśnie znalazłem inny sposób na osiągnięcie tego:

let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)
Aks
źródło
50

Zrobiłem funkcje pomocnicze, które zostały przeniesione z poniższego linku do szybkiego:

Jak możemy programowo wykryć, na której wersji iOS działa urządzenie?

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
}

Można go używać w następujący sposób:

SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO("7.0")

Szybki 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
źródło
31

Szybki 5

Nie musimy tworzyć rozszerzenia, ponieważ ProcessInfodaje nam informacje o wersji. Możesz zobaczyć przykładowy kod dla iOS jak poniżej.

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

Odniesienie: http://nshipster.com/swift-system-version-checking/

nahung89
źródło
17

Szybki 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
źródło
1
dlaczego w runNewCode jest potrzebny #available (iOS 11.0, *)?
Illya Krit,
1
@IllyaKrit #available(...)Blok zatrzymuje kompilatorowi wyświetlanie błędów dla kodu, który nie jest obsługiwany w wersjach starszych niż podane.
future-adam
15

Zrobiłem ten Singleton do prostego użytku, utworzyłem IOSVersion.swiftplik i dodałem ten kod:

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

POSŁUGIWAĆ SIĘ :

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

Dzięki @KVISH

Edytuj Swift 2:

if #available(iOS 9.0, *) {
    // 👍 
} else {
    // 👎
}
YannSteph
źródło
4
Czy to singleton? czy po prostu funkcje klasowe w IOSVersion? nie byłby singlem static let shared = IOSVersion
Charlton Provatas
9

Jeśli używasz Swift 2 i chcesz sprawdzić wersję systemu operacyjnego, aby użyć określonego interfejsu API, możesz użyć nowej funkcji dostępności:

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

Napisałem tę odpowiedź, ponieważ jest to pierwsze pytanie w Google dla tego swift 2 check system versionzapytania.

FreeNickname
źródło
7

Aktualizacja dla 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
}
Mellong Lau
źródło
1
Można pominąć, ComparisonResultaby go skrócić.
John Pang,
Uwzględnienie faktów UIDevice.current.systemVersion.compare(version, options: .numeric)w funcpomocy może pomóc w odczytaniu kodu.
John Pang,
5

Detale

  • Xcode 10.2.1 (10E1001), Swift 5

Spinki do mankietów

OperatingSystemVersion

Rozwiązanie

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
Wasilij Bodnarchuk
źródło
1
Czy nie występują potencjalne problemy z zaokrąglaniem przy użyciu Doublenumeru wersji, np. 10.0999Zamiast 10.1?
mschmidt
Nie var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999. Wydrukuje10.0999
Wasilij Bodnarchuk
4
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue

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

i sprawdź jako

if(iOS8)
{

}
else 
{
}  
poojathorat
źródło
4

Najłatwiejszym i najprostszym sposobem sprawdzenia wersji systemu (i wielu innych wersji) w Swift 2 i wyższych jest:

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

}

Ponadto #availablemożesz sprawdzić wersje tych:

iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
Tengai
źródło
2

Mattt Thompson udostępnia bardzo przydatny sposób

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
źródło
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
}

Stosowanie:

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

Odpowiedź PS KVISH przetłumaczona na Swift 4.x ze zmianą nazw funkcji, ponieważ specjalnie używam tego fragmentu kodu dla aplikacji na iOS.

Hemang
źródło
1

Uwaga: Dostępne w iOS 8.0 i nowszych. OS X 10.10 i nowszy

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        }
Leo Dabus
źródło
1

Na podstawie odpowiedzi Matta Thompsona, oto metoda z odpowiednimi testami jednostkowymi, która działa z Swift i Objective-c na iOS 7 i nowszych (w tym iOS 9, które nie pozwalają już sprawdzać 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
źródło
zdajesz sobie sprawę, że faktyczna metoda jest bardzo krótka i zwarta oraz że właśnie dodałem kod testu jednostkowego w celu zilustrowania i udowodnienia, że ​​działa, prawda?
n8tr,
Przepraszam, że nie zdawałem sobie sprawy, że to XCTest na pierwszy rzut oka.
DawnSong
1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
Matjan
źródło
0

Również jeśli chcesz sprawdzić WatchOS.

Szybki

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

Cel C

NSString *watchOSVersion = [[WKInterfaceDevice currentDevice] systemVersion];
NSLog(@"WatchOS version: %@", watchOSVersion);
Edison
źródło
0

Pobierz aktualną wersję systemu i podziel ją. Możesz uzyskać wersję główną i mniejszą.

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])")
Mili Shah
źródło
0

Większość zapisanych tutaj przykładowych kodów uzyska nieoczekiwany wynik w wersjach z dodatkowymi zerami. Na przykład,

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

Ta metoda nie zwróci wartości true w przypadku przekazanej wersji „10.3.0” w systemie iOS „10.3”. Tego rodzaju wynik nie ma sensu i należy je traktować jako tę samą wersję. Aby uzyskać dokładny wynik porównania, musimy rozważyć porównanie wszystkich składników liczb w ciągu wersji. Ponadto podanie globalnych metod wielkimi literami nie jest dobrym rozwiązaniem. Ponieważ typ wersji, której używamy w naszym zestawie SDK, jest ciągiem, sensowne jest rozszerzenie funkcji porównywania w łańcuchu.

Aby porównać wersję systemu, wszystkie poniższe przykłady powinny działać.

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

Możesz to sprawdzić w moim repozytorium tutaj https://github.com/DragonCherry/VersionCompare

DragonCherry
źródło