Comprobar la versión del sistema operativo en Swift?

191

Estoy tratando de verificar la información del sistema en Swift. Me di cuenta de que se podía lograr por código:

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

Tengo dos problemas con este código:

  1. ¿Cuál debería ser el valor inicial de sysData? Este ejemplo da -1 en retVal probablemente porque sysData es nulo.
  2. ¿Cómo puedo leer información de sysData?
Gergely
fuente

Respuestas:

388

Para iOS, intente:

var systemVersion = UIDevice.current.systemVersion

Para OS X, intente:

var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion

Si solo desea verificar si los usuarios están ejecutando al menos una versión específica, también puede usar la siguiente función Swift 2 que funciona en iOS y OS X:

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

PERO no se recomienda verificar la versión del sistema operativo. Es mejor verificar si la función que desea usar está disponible en el dispositivo que comparar los números de versión. Para iOS, como se mencionó anteriormente, debe verificar si responde a un selector; p.ej.:

if (self.respondsToSelector(Selector("showViewController"))) {
    self.showViewController(vc, sender: self)
} else {
    // some work around
}
miho
fuente
Si bien esto es correcto para el objetivo c, hay una manera mucho mejor de hacerlo rápidamente. Esbozado
Fogmeister
2
Un uso que puedo ver para verificar la versión del sistema operativo directamente (en lugar de verificar las capacidades específicas) es recopilar datos sobre la distribución de la versión del sistema operativo entre sus usuarios, para determinar su objetivo de implementación más bajo.
Nicolas Miari
91

Actualización:
ahora debe usar la nueva verificación de disponibilidad introducida con Swift 2:
por ejemplo, para verificar iOS 9.0 o posterior en tiempo de compilación, use esto:

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

o se puede usar con todo el método o clase

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

Para más información mira esto .

Verificaciones de tiempo de ejecución:

si no quieres la versión exacta pero quieres verificar iOS 9,10 u 11 usando if:

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

EDITAR: Acabo de encontrar otra forma de lograr esto:

let iOS8 = floor(NSFoundationVersionNumber) > floor(NSFoundationVersionNumber_iOS_7_1)
let iOS7 = floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_7_1)
Aks
fuente
50

Realicé funciones de ayuda que se transfirieron desde el siguiente enlace a swift:

¿Cómo podemos detectar mediante programación en qué versión de iOS se está ejecutando el dispositivo?

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
}

Se puede usar así:

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
fuente
31

Swift 5

No necesitamos crear una extensión ya ProcessInfoque nos da la información de la versión. Puede ver el código de muestra para iOS como se muestra a continuación.

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

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

nahung89
fuente
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
fuente
1
¿Por qué en runNewCode se necesita #available (iOS 11.0, *)?
Illya Krit
1
@IllyaKrit El #available(...)bloque impide que el compilador muestre errores para el código que no se admite en versiones anteriores a las proporcionadas.
future-adam
15

Hice este Singleton para un uso simple, creé un IOSVersion.swiftarchivo y agregué este código:

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

UTILIZAR :

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

Gracias @KVISH

Editar Swift 2:

if #available(iOS 9.0, *) {
    // 👍 
} else {
    // 👎
}
YannSteph
fuente
44
¿Es ese singleton? o simplemente funciones de clase en IOSVersion? no sería un singleton static let shared = IOSVersion
Charlton Provatas
9

Si está utilizando Swift 2 y desea verificar la versión del sistema operativo para usar una determinada API, puede usar la nueva función de disponibilidad:

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

Escribí esta respuesta porque es la primera pregunta en Google para la swift 2 check system versionconsulta.

FreeNickname
fuente
7

Actualización para 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
fuente
1
Puede saltar ComparisonResultpara hacerlo más corto.
John Pang
Además, factorizar UIDevice.current.systemVersion.compare(version, options: .numeric)en un funcpuede ayudar a la lectura del código.
John Pang
5

Detalles

  • Xcode 10.2.1 (10E1001), Swift 5

Enlaces

OperatingSystemVersion

Solución

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
fuente
1
¿No hay problemas potenciales de redondeo cuando se usa Doublepara un número de versión, por ejemplo, en 10.0999lugar de 10.1?
mschmidt
No. var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999, se imprimirá10.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

y verifica como

if(iOS8)
{

}
else 
{
}  
poojathorat
fuente
4

La forma más fácil y sencilla de verificar la versión del sistema (y muchas otras versiones) en Swift 2 y superior es:

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

}

Además, con #availableusted puede verificar versiones de estos:

iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
Tengai
fuente
2

Mattt Thompson comparte una manera muy útil

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

Uso:

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

La respuesta de PS KVISH se tradujo a Swift 4.x con el cambio de nombre de las funciones, ya que específicamente estoy usando este fragmento para la aplicación iOS.

Hemang
fuente
1

Nota: Disponible en iOS 8.0 y posterior. OS X v10.10 y posterior

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
fuente
1

Basado en la respuesta de Matt Thompson, aquí hay un método con pruebas de unidad respectivas que funciona con Swift y Objective-c en iOS 7 y superior (incluido iOS 9 que ya no le permite verificar el 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
fuente
te das cuenta de que el método real es muy corto y compacto y que acabo de agregar el código de prueba de la unidad para ilustración y prueba de que funciona, ¿verdad?
n8tr
Lamento no haberme dado cuenta de que es XCTest de un vistazo.
DawnSong
1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
Matjan
fuente
0

También si quieres consultar WatchOS.

Rápido

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

C objetivo

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

Obtenga la versión actual del sistema y divídalo. Para que pueda obtener la versión mayor y menor.

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
fuente
0

La mayoría de los códigos de muestra escritos aquí obtendrán resultados inesperados con versiones extra-cero. Por ejemplo,

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

Este método no devolverá verdadero con la versión aprobada "10.3.0" en iOS "10.3". Este tipo de resultado no tiene sentido y deben considerarse como la misma versión. Para obtener un resultado de comparación exacto, debemos considerar comparar todos los componentes numéricos en la cadena de versión. Además, proporcionar métodos globales en mayúsculas no es un buen camino a seguir. Como el tipo de versión que utilizamos en nuestro SDK es un String, tiene sentido ampliar la funcionalidad de comparación en String.

Para comparar la versión del sistema, todos los siguientes ejemplos deberían funcionar.

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

Puede consultarlo en mi repositorio aquí https://github.com/DragonCherry/VersionCompare

DragonCherry
fuente