Vérifier la version du système d'exploitation dans Swift?

203

J'essaye de vérifier les informations système dans Swift. J'ai compris que cela pouvait être réalisé par code:

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

J'ai deux problèmes avec ce code:

  1. Quelle devrait être la valeur initiale de sysData? Cet exemple donne -1 dans retVal probablement parce que sysData est nul.
  2. Comment puis-je lire les informations de sysData?
Gergely
la source

Réponses:

409

Pour iOS, essayez:

var systemVersion = UIDevice.current.systemVersion

Pour OS X, essayez:

var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion

Si vous souhaitez simplement vérifier si les utilisateurs exécutent au moins une version spécifique, vous pouvez également utiliser la fonctionnalité Swift 2 suivante qui fonctionne sur iOS et OS X:

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

MAIS il n'est pas recommandé de vérifier la version du système d'exploitation. Il est préférable de vérifier si la fonctionnalité que vous souhaitez utiliser est disponible sur l'appareil plutôt que de comparer les numéros de version. Pour iOS, comme mentionné ci-dessus, vous devez vérifier s'il répond à un sélecteur; par exemple.:

if (self.respondsToSelector(Selector("showViewController"))) {
    self.showViewController(vc, sender: self)
} else {
    // some work around
}
Miho
la source
Bien que cela soit correct pour l'objectif c, il existe une manière beaucoup plus agréable de le faire rapidement. Décrit ici ... hackingwithswift.com/new-syntax-swift-2-availability-checking
Fogmeister
2
Une utilisation que je peux voir pour vérifier directement la version du système d'exploitation (par opposition à la vérification de capacités spécifiques) est de collecter des données sur la distribution de la version du système d'exploitation parmi vos utilisateurs, afin de déterminer votre cible de déploiement la plus basse.
Nicolas Miari
97

Mise à jour:
Vous devez maintenant utiliser la nouvelle vérification de disponibilité introduite avec Swift 2:
par exemple, pour vérifier iOS 9.0 ou une version ultérieure au moment de la compilation , utilisez ceci:

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

ou peut être utilisé avec toute la méthode ou la classe

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

Pour plus d'informations, consultez ceci .

Vérifications du temps d'exécution:

si vous ne voulez pas de version exacte mais que vous voulez vérifier iOS 9, 10 ou 11 en utilisant si:

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

EDIT: Je viens de trouver un autre moyen d'y parvenir:

let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)
Aks
la source
51

J'ai créé des fonctions d'assistance qui ont été transférées du lien ci-dessous vers swift:

Comment pouvons-nous détecter par programme sur quelle version iOS l'appareil fonctionne?

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
}

Il peut être utilisé comme ceci:

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
la source
35

Swift 5

Nous n'avons pas besoin de créer une extension car ProcessInfonous donne les informations de version. Vous pouvez voir un exemple de code pour iOS comme ci-dessous.

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

Référence: http://nshipster.com/swift-system-version-checking/

nahung89
la source
18

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
la source
1
pourquoi dans runNewCode est #available (iOS 11.0, *) nécessaire?
Illya Krit
1
@IllyaKrit Le #available(...)bloc empêche le compilateur d'afficher des erreurs pour le code qui n'est pas pris en charge dans les versions antérieures à celles fournies.
future-adam
15

J'ai fait ce Singleton pour une utilisation simple, créé un IOSVersion.swiftfichier et ajouté ce code:

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

UTILISATION :

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

Merci @KVISH

Modifier Swift 2:

if #available(iOS 9.0, *) {
    // 👍 
} else {
    // 👎
}
YannSteph
la source
4
Est-ce singleton? ou simplement des fonctions de classe sur IOSVersion? ne serait pas un singleton static let shared = IOSVersion
Charlton Provatas
9

Si vous utilisez Swift 2 et que vous souhaitez vérifier la version du système d'exploitation pour utiliser une certaine API, vous pouvez utiliser la nouvelle fonctionnalité de disponibilité:

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

J'ai écrit cette réponse car c'est la première question dans Google pour la swift 2 check system versionrequête.

FreeNickname
la source
7

Mise à jour pour 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
la source
1
Peut sauter ComparisonResultpour le raccourcir.
John Pang
En outre, la prise en compte UIDevice.current.systemVersion.compare(version, options: .numeric)dans un funcpeut aider à la lecture du code.
John Pang
6

Détails

  • Xcode 10.2.1 (10E1001), Swift 5

Liens

OperatingSystemVersion

Solution

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
Vasily Bodnarchuk
la source
1
N'y a-t-il pas des problèmes d'arrondi potentiels lors de l'utilisation Doubled'un numéro de version, par exemple 10.0999au lieu de 10.1?
mschmidt
Non var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999, il imprimera10.0999
Vasily Bodnarchuk
4
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue

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

et vérifiez comme

if(iOS8)
{

}
else 
{
}  
poojathorat
la source
4

Le moyen le plus simple et le plus simple de vérifier la version du système (et de nombreuses autres versions) dans Swift 2 et versions ultérieures est:

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

}

En outre, #availablevous pouvez vérifier les versions de ceux-ci:

iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
Tengai
la source
2

Mattt Thompson partage un moyen très pratique

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

Usage:

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

Réponse PS KVISH traduite en Swift 4.x en renommant les fonctions car j'utilise spécifiquement cet extrait de code pour l'application iOS.

Hemang
la source
1

Remarque: disponible dans iOS 8.0 et versions ultérieures. OS X v10.10 et versions ultérieures

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
la source
1

Sur la base de la réponse de Matt Thompson, voici une méthode avec des tests unitaires respectifs qui fonctionne avec Swift et Objective-c sur iOS 7 et supérieur (y compris iOS 9 qui ne vous permet plus de vérifier le 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
la source
vous réalisez que la méthode actuelle est très courte et compacte et que je viens d'ajouter le code de test unitaire pour l'illustration et la preuve que cela fonctionne, non?
n8tr
Je suis désolé de ne pas avoir réalisé que c'est XCTest en un coup d'œil.
DawnSong
1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
Matjan
la source
0

Aussi si vous souhaitez vérifier WatchOS.

Rapide

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

Objectif c

NSString *watchOSVersion = [[WKInterfaceDevice currentDevice] systemVersion];
NSLog(@"WatchOS version: %@", watchOSVersion);
Edison
la source
0

Obtenez la version actuelle du système et divisez-la. Ainsi, vous pouvez obtenir une version majeure et mineure.

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
la source
0

La plupart des exemples de codes écrits ici obtiendront des résultats inattendus avec des versions extra-nulles. Par exemple,

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

Cette méthode ne retournera pas vrai avec la version "10.3.0" passée dans iOS "10.3". Ce type de résultat n'a pas de sens et doit être considéré comme la même version. Pour obtenir un résultat de comparaison précis, nous devons envisager de comparer tous les composants numériques dans la chaîne de version. De plus, fournir des méthodes globales dans toutes les lettres majuscules n'est pas une bonne solution. Comme le type de version que nous utilisons dans notre SDK est une chaîne, il est logique d'étendre la fonctionnalité de comparaison dans String.

Pour comparer la version du système, tous les exemples suivants devraient fonctionner.

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

Vous pouvez le vérifier dans mon référentiel ici https://github.com/DragonCherry/VersionCompare

DragonCerise
la source