Ho un'app IOS con un back-end di Azure e vorrei registrare determinati eventi, come accessi e quali versioni degli utenti dell'app sono in esecuzione.
Come posso restituire la versione e il numero di build utilizzando Swift?
Ho un'app IOS con un back-end di Azure e vorrei registrare determinati eventi, come accessi e quali versioni degli utenti dell'app sono in esecuzione.
Come posso restituire la versione e il numero di build utilizzando Swift?
Risposte:
MODIFICARE
Aggiornato per Swift 4.2
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
MODIFICARE
Come sottolineato da @azdev sulla nuova versione di Xcode otterrai un errore di compilazione per provare la mia soluzione precedente, per risolverlo basta modificarlo come suggerito per scartare il dizionario del bundle usando un!
let nsObject: AnyObject? = Bundle.main.infoDictionary!["CFBundleShortVersionString"]
Fine modifica
Usa solo la stessa logica rispetto a Objective-C ma con alcune piccole modifiche
//First get the nsObject by defining as an optional anyObject
let nsObject: AnyObject? = NSBundle.mainBundle().infoDictionary["CFBundleShortVersionString"]
//Then just cast the object as a String, but be careful, you may want to double check for nil
let version = nsObject as! String
Spero che questo ti aiuti.
David
infoDictionary
dovrebbe essere scartato usando!
. Questo è quello che sto usando, inserito in un file Globals.swift:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
So che è già stata data una risposta, ma personalmente penso che sia un po 'più pulito:
Swift 3.0:
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
self.labelVersion.text = version
}
Swift <2.3
if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
self.labelVersion.text = version
}
In questo modo, la versione if let si occupa dell'elaborazione condizionale (impostando il testo dell'etichetta nel mio caso) e se infoDictionary o CFBundleShortVersionString sono nulli, lo scartamento opzionale provocherà il salto del codice.
self.labelVersion.text
è di tipo opzionale, quindi puoi assegnare direttamenteNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
let
, chiedendosi solo perché potrebbe essere necessario. Grazie!
Aggiornato per Swift 3.0
I NS
prefissi sono ora spariti in Swift 3.0 e diverse proprietà / metodi hanno cambiato i nomi per essere più Swifty. Ecco come appare ora:
extension Bundle {
var releaseVersionNumber: String? {
return infoDictionary?["CFBundleShortVersionString"] as? String
}
var buildVersionNumber: String? {
return infoDictionary?["CFBundleVersion"] as? String
}
}
Bundle.main.releaseVersionNumber
Bundle.main.buildVersionNumber
Vecchia risposta aggiornata
Ho lavorato molto con Frameworks dalla mia risposta originale, quindi volevo aggiornare la mia soluzione a qualcosa di più semplice e molto più utile in un ambiente multi-bundle:
extension NSBundle { var releaseVersionNumber: String? { return self.infoDictionary?["CFBundleShortVersionString"] as? String } var buildVersionNumber: String? { return self.infoDictionary?["CFBundleVersion"] as? String } }
Ora questa estensione sarà utile nelle app per identificare sia il bundle principale sia qualsiasi altro bundle incluso (come un framework condiviso per la programmazione di estensioni o terzi framework come AFNetworking), in questo modo:
NSBundle.mainBundle().releaseVersionNumber NSBundle.mainBundle().buildVersionNumber // or... NSBundle(URL: someURL)?.releaseVersionNumber NSBundle(URL: someURL)?.buildVersionNumber
Risposta originale
Volevo migliorare alcune delle risposte già pubblicate. Ho scritto un'estensione di classe che può essere aggiunta alla catena degli strumenti per gestirla in modo più logico.
extension NSBundle { class var applicationVersionNumber: String { if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]
come? String {return version} return "Numero versione non disponibile"}
class var applicationBuildNumber: String { if let build = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String { return build } return "Build Number Not Available" } }
Quindi ora puoi accedervi facilmente:
let versionNumber = NSBundle.applicationVersionNumber
So anche che è già stata data una risposta, ma ho racchiuso le risposte precedenti:
extension Bundle {
var releaseVersionNumber: String? {
return infoDictionary?["CFBundleShortVersionString"] as? String
}
var buildVersionNumber: String? {
return infoDictionary?["CFBundleVersion"] as? String
}
var releaseVersionNumberPretty: String {
return "v\(releaseVersionNumber ?? "1.0.0")"
}
}
Uso:
someLabel.text = Bundle.main.releaseVersionNumberPretty
Swift 3.1 :
class func getVersion() -> String {
guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
return "no version info"
}
return version
}
Per le versioni precedenti :
class func getVersion() -> String {
if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
return version
}
return "no version info"
}
Quindi, se si desidera impostare il testo dell'etichetta o si desidera utilizzare altrove;
self.labelVersion.text = getVersion()
Per Swift 4.0
let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"]!
let build = Bundle.main.infoDictionary!["CFBundleVersion"]!
Ho fatto un'estensione sul pacchetto
extension Bundle {
var appName: String {
return infoDictionary?["CFBundleName"] as! String
}
var bundleId: String {
return bundleIdentifier!
}
var versionNumber: String {
return infoDictionary?["CFBundleShortVersionString"] as! String
}
var buildNumber: String {
return infoDictionary?["CFBundleVersion"] as! String
}
}
e poi usalo
versionLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"
Per Swift 3.0 NSBundle non funziona, il codice seguente funziona perfettamente.
let versionNumberString =
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
as! String
e solo per il numero di build, è:
let buildNumberString =
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
as! String
Confusivamente 'CFBundleVersion' è il numero di build immesso in Xcode in Generale-> Identità.
Xcode 9.4.1 Swift 4.1
Nota l'uso di localizedInfoDictionary per selezionare la versione della lingua corretta del nome visualizzato del bundle.
var displayName: String?
var version: String?
var build: String?
override func viewDidLoad() {
super.viewDidLoad()
// Get display name, version and build
if let displayName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String {
self.displayName = displayName
}
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
self.version = version
}
if let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
self.build = build
}
}
Swift 4, utile estensione per bundle
import Foundation
public extension Bundle {
public var shortVersion: String {
if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
return result
} else {
assert(false)
return ""
}
}
public var buildVersion: String {
if let result = infoDictionary?["CFBundleVersion"] as? String {
return result
} else {
assert(false)
return ""
}
}
public var fullVersion: String {
return "\(shortVersion)(\(buildVersion))"
}
}
Bundle + Extensions.swift
import Foundation
extension Bundle {
var versionNumber: String? {
return infoDictionary?["CFBundleShortVersionString"] as? String
}
var buildNumber: String? {
return infoDictionary?["CFBundleVersion"] as? String
}
var bundleName: String? {
return infoDictionary?["CFBundleName"] as? String
}
}
Uso:
someLabel.text = Bundle.main.versionNumber
OP ha chiesto sia il numero di versione che il numero di build. Sfortunatamente la maggior parte delle risposte non fornisce entrambe queste opzioni. Inoltre, altri aggiungono metodi di estensione non necessari. Eccone uno piuttosto semplice e risolve il problema di OP:
// Example output: "1.0 (234)"
private func versionAndBuildNumber() -> String {
let versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
if let versionNumber = versionNumber, let buildNumber = buildNumber {
return "\(versionNumber) (\(buildNumber))"
} else if let versionNumber = versionNumber {
return versionNumber
} else if let buildNumber = buildNumber {
return buildNumber
} else {
return ""
}
}
La mia risposta (ad agosto 2015), dato che Swift continua a evolversi:
let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Ho creato un'estensione per UIApplication.
extension UIApplication {
static var appVersion: String {
let versionNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.versionNumber] as? String
let buildNumber = Bundle.main.infoDictionary?[IdentifierConstants.InfoPlist.buildNumber] as? String
let formattedBuildNumber = buildNumber.map {
return "(\($0))"
}
return [versionNumber,formattedBuildNumber].compactMap { $0 }.joined(separator: " ")
}
}
struct IdentifierConstants {
struct InfoPlist {
static let versionNumber = "CFBundleShortVersionString"
static let buildNumber = "CFBundleVersion"
}
}
Dopo aver esaminato la documentazione, credo che quanto segue sia più pulito:
let version =
NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")
as? String
Fonte : "L'uso di questo metodo è preferito rispetto ad altri metodi di accesso perché restituisce il valore localizzato di una chiave quando è disponibile."
Per Swift 1.2 è:
let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Swift 3:
Numero della versione
if let versionNumberString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { // do something }
Numero di build
if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }
Swift 4
func getAppVersion() -> String {
return "\(Bundle.main.infoDictionary!["CFBundleShortVersionString"] ?? "")"
}
Bundle.main.infoDictionary! [ "CFBundleShortVersionString"]
Vecchia sintassi rapida
let appVer: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]
extension UIApplication {
static var appVersion: String {
if let appVersion = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") {
return "\(appVersion)"
} else {
return ""
}
}
static var build: String {
if let buildVersion = NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey as String) {
return "\(buildVersion)"
} else {
return ""
}
}
static var versionBuild: String {
let version = UIApplication.appVersion
let build = UIApplication.build
var versionAndBuild = "v\(version)"
if version != build {
versionAndBuild = "v\(version)(\(build))"
}
return versionAndBuild
}
}
Attenzione: dovresti usarlo se lasciato qui nel caso in cui la versione o la build dell'app non sia impostata, il che provocherà un arresto anomalo se provi a utilizzare! da scartare.
Ecco una versione aggiornata per Swift 3.2:
extension UIApplication
{
static var appVersion:String
{
if let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
{
return "\(appVersion)"
}
return ""
}
static var buildNumber:String
{
if let buildNum = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String)
{
return "\(buildNum)"
}
return ""
}
static var versionString:String
{
return "\(appVersion).\(buildNumber)"
}
}
public var appVersionNumberString: String {
get {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
}
}
SWIFT 4
// Per prima cosa ottieni nsObject definendolo come AnyObject opzionale
let nsObject: AnyObject? = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as AnyObject
// Quindi esegui il cast dell'oggetto come stringa, ma fai attenzione, potresti voler ricontrollare per zero
let version = nsObject as! String
per chiunque sia interessato, c'è una libreria bella e ordinata chiamata SwifterSwift
disponibile su github e completamente documentata per ogni versione di swift (vedi swifterswift.com ).
usando questa libreria, leggere la versione dell'app e il numero di build sarebbe facile come questo:
import SwifterSwift
let buildNumber = SwifterSwift.appBuild
let version = SwifterSwift.appVersion
ecco una funzione che sto usando per decidere se mostrare o meno una pagina "l'app aggiornata". Restituisce il numero di build, che sto convertendo in un Int:
if let version: String = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
guard let intVersion = Int(version) else { return }
if UserDefaults.standard.integer(forKey: "lastVersion") < intVersion {
print("need to show popup")
} else {
print("Don't need to show popup")
}
UserDefaults.standard.set(intVersion, forKey: "lastVersion")
}
Se mai usato prima, restituirà 0 che è inferiore al numero di build corrente. Per non mostrare una schermata del genere ai nuovi utenti, è sufficiente aggiungere il numero di build dopo il primo accesso o al termine dell'onboarding.
Semplice funzione di utilità per restituire la versione dell'app come Int
func getAppVersion() -> Int {
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
let appVersionClean = appVersion.replacingOccurrences(of: ".", with: "", options: NSString.CompareOptions.literal, range:nil)
if let appVersionNum = Int(appVersionClean) {
return appVersionNum
}
}
return 0
}
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
self.lblAppVersionValue.text = version
}
Bundle + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Ho combinato idee da alcune risposte e ho esteso un po ':
Fondazione di importazione
pacchetto estensione {
public var appVersionShort: String? {
if let result = infoDictionary?["CFBundleShortVersionString"] as? String {
return result
} else {
return "⚠️"
}
}
public var appVersionLong: String? {
if let result = infoDictionary?["CFBundleVersion"] as? String {
return result
} else {
return "⚠️"
}
}
public var appName: String? {
if let result = infoDictionary?["CFBundleName"] as? String {
return result
} else {
return "⚠️"
}
}
}
Esempio di utilizzo di SwiftUI
VStack {
Text("Version: \(Bundle.main.appVersionShort!) (\(Bundle.main.appVersionLong!))")
.font(.subheadline)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
lblVersion.text = "Version \(version)"
}