Verifique a versão do sistema operacional no Swift?

190

Estou tentando verificar as informações do sistema no Swift. Eu descobri que isso poderia ser alcançado por código:

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

Eu tenho dois problemas com este código:

  1. Qual deve ser o valor inicial do sysData? Este exemplo fornece -1 em retVal provavelmente porque sysData é nulo.
  2. Como posso ler informações de sysData?
Gergely
fonte

Respostas:

387

Para iOS, tente:

var systemVersion = UIDevice.current.systemVersion

Para o OS X, tente:

var systemVersion = NSProcessInfo.processInfo().operatingSystemVersion

Se você quiser apenas verificar se os usuários estão executando pelo menos uma versão específica, também pode usar o seguinte recurso Swift 2, que funciona no iOS e no OS X:

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

MAS não é recomendável verificar a versão do sistema operacional. É melhor verificar se o recurso que você deseja usar está disponível no dispositivo do que comparar os números de versão. Para o iOS, como mencionado acima, você deve verificar se ele responde a um seletor; por exemplo.:

if (self.respondsToSelector(Selector("showViewController"))) {
    self.showViewController(vc, sender: self)
} else {
    // some work around
}
miho
fonte
Embora isso esteja correto para o objetivo c, há uma maneira muito mais agradável de fazê-lo rapidamente. Esboçado aqui ... hackingwithswift.com/new-syntax-swift-2-availability-checking
Fogmeister
2
Um uso que posso verificar para verificar a versão do sistema operacional diretamente (em vez de verificar recursos específicos) é coletar dados sobre a distribuição da versão do sistema operacional entre seus usuários, para determinar o seu destino de implantação mais baixo.
Nicolas Miari
90

Atualização:
Agora você deve usar a nova verificação de disponibilidade introduzida no Swift 2:
por exemplo, para verificar o iOS 9.0 ou posterior em tempo de compilação, use o seguinte:

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

ou pode ser usado com todo o método ou classe

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

Para mais informações, consulte isso .

Verificações de tempo de execução:

se você não deseja a versão exata, mas deseja verificar o iOS 9,10 ou 11 usando:

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

EDIT: Acabei de encontrar outra maneira de conseguir isso:

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

Criei funções auxiliares que foram transferidas do link abaixo para swift:

Como podemos detectar programaticamente em qual versão do iOS o dispositivo está sendo executado?

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
}

Pode ser usado assim:

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

Swift 5

Não precisamos criar extensão, pois ProcessInfonos fornece as informações da versão. Você pode ver o código de exemplo para iOS como abaixo.

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

Referência: http://nshipster.com/swift-system-version-checking/

nahung89
fonte
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
fonte
1
por que, no runNewCode, é # disponível (iOS 11.0, *) necessário?
Illya Krit #
1
@IllyaKrit O #available(...)bloco impede o compilador de exibir erros para o código que não é suportado em versões anteriores às fornecidas.
future-adam
15

Eu criei este Singleton para uso simples, criei um IOSVersion.swiftarquivo e adicionei 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
    }
}

USAR :

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

Obrigado @KVISH

Editar Swift 2:

if #available(iOS 9.0, *) {
    // 👍 
} else {
    // 👎
}
YannSteph
fonte
4
Isso é singleton? ou apenas funções de classe no IOSVersion? não seria um singleton static let shared = IOSVersion
Charlton Provatas
9

Se você estiver usando o Swift 2 e quiser verificar a versão do sistema operacional para usar uma determinada API, poderá usar o novo recurso de disponibilidade:

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

Eu escrevi esta resposta porque é a primeira pergunta no Google para a swift 2 check system versionconsulta.

FreeNickname
fonte
7

Atualização 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
fonte
1
Pode pular ComparisonResultpara torná-lo mais curto.
John Pang
Além disso, fatorar UIDevice.current.systemVersion.compare(version, options: .numeric)em um funcpode ajudar a ler o código.
John Pang
5

Detalhes

  • Xcode 10.2.1 (10E1001), Swift 5

Ligações

OperatingSystemVersion

Solução

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
fonte
1
Não há problemas de arredondamento em potencial ao usar Doublepara um número de versão, por exemplo, em 10.0999vez de 10.1?
30917 mschmidt
Não var stringVersion = "10.0999"; print(stringVersion.toDouble!) // print 10.0999, ele será impresso #10.0999
Vasily Bodnarchuk 30/10
4
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue

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

e verifique como

if(iOS8)
{

}
else 
{
}  
poojathorat
fonte
4

A maneira mais fácil e simples de verificar a versão do sistema (e muitas outras versões) no Swift 2 e superior é:

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

}

Além disso, #availablevocê pode verificar versões destes:

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

Mattt Thompson compartilha uma maneira muito ú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")
}
dAfeição
fonte
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!
}

Resposta do PS KVISH traduzida para o Swift 4.x com renomeação das funções, pois estou usando especificamente esse snippet para o aplicativo iOS.

Hemang
fonte
1

Nota: Disponível no iOS 8.0 e posterior. OS X v10.10 e 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
fonte
1

Com base na resposta de Matt Thompson, aqui está um método com os respectivos testes de unidade que funcionam com Swift e Objective-c no iOS 7 e superior (incluindo o iOS 9, que não permite mais que você verifique o 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
fonte
você percebe que o método atual é muito curto e compacto e que acabei de adicionar o código do teste de unidade para ilustração e prova de que funciona, certo?
N8tr 6/11/2015
Lamento não ter percebido que é o XCTest de relance.
DawnSong
1
let osVersion = NSProcessInfo.processInfo().operatingSystemVersion
let versionString = osVersion.majorVersion.description + "." + osVersion.minorVersion.description + "." + osVersion.patchVersion.description
print(versionString)
Matjan
fonte
0

Além disso, se você quiser verificar o WatchOS.

Rápido

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

Objetivo-C

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

Obtenha a versão atual do sistema e divida-a. Então você pode obter a versão principal e secundária.

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

A maioria dos códigos de amostra escritos aqui obterá resultados inesperados com versões extra-zero. Por exemplo,

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

Este método não retornará verdadeiro com a versão passada "10.3.0" no iOS "10.3". Esse tipo de resultado não faz sentido e deve ser considerado como a mesma versão. Para obter resultados precisos de comparação, devemos considerar a comparação de todos os componentes numéricos na string de versão. Além disso, fornecer métodos globais em letras maiúsculas não é um bom caminho. Como o tipo de versão que usamos em nosso SDK é uma String, faz sentido estender a funcionalidade de comparação na String.

Para comparar a versão do sistema, todos os exemplos a seguir devem 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"))

Você pode conferir no meu repositório aqui https://github.com/DragonCherry/VersionCompare

DragonCherry
fonte