Wie erhalte ich mit Swift die App-Version und die Build-Nummer?
387
Ich habe eine IOS-App mit einem Azure-Back-End und möchte bestimmte Ereignisse protokollieren, z. B. Anmeldungen und welche Versionen der App-Benutzer ausgeführt werden.
Wie kann ich die Version und die Build-Nummer mit Swift zurückgeben?
Verwechseln Sie CFBundleVersion& CFBundleShortVersionString` nicht. Die erste ist Ihre Build- Version. Die andere ist die Versionsnummer . Siehe hier für weitere Informationen
Honey
1
@ ØyvindVik Die meisten Leute gehen davon aus, dass Sie eine Objective-C-Lösung ohne Händchenhalten in Swift übersetzen können.
Gnasher729
Antworten:
424
BEARBEITEN
Aktualisiert für Swift 4.2
let appVersion =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String
BEARBEITEN
Wie von @azdev in der neuen Version von Xcode hervorgehoben, wird beim Kompilieren meiner vorherigen Lösung ein Kompilierungsfehler angezeigt. Um dies zu lösen, bearbeiten Sie es einfach wie vorgeschlagen, um das Bundle-Wörterbuch mit einem!
let nsObject:AnyObject?=Bundle.main.infoDictionary!["CFBundleShortVersionString"]
Bearbeiten beenden
Verwenden Sie einfach dieselbe Logik wie in Objective-C, jedoch mit einigen kleinen Änderungen
//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
Wenn ich dies benutze, erhalte ich einen Compilerfehler "[NSObject: AnyObject]? Hat kein Mitglied namens 'tiefgestellt'"
andreas
Sie können versuchen, das AnyObject zu ersetzen? von AnyObject! Ohne genau zu wissen, welchen Code Sie verwenden, ist es sehr schwierig zu erraten, was falsch ist. Denken Sie auch daran, dass Swift von einer Xcode-Version zu einer anderen wechseln kann. Daher ist es auch wichtig, Ihre Xcode-Version zu kennen.
David
18
@andreas infoDictionarysollte mit ausgepackt werden !. Dies ist, was ich benutze, in eine Globals.swift-Datei gelegt:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
Azdev
1
Ich musste noch ein "!" nach "as". let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Josei
3
Sie sollten vermeiden, ein erzwungenes Auspacken "!" da sie dazu führen, dass Ihre App abstürzt, wenn einer dieser Werte Null ist
Julius
278
Ich weiß, dass dies bereits beantwortet wurde, aber ich persönlich denke, dass dies ein wenig sauberer ist:
Swift 3.0:
iflet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version
}
Schnell <2.3
iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version
}
Auf diese Weise kümmert sich die if let-Version um die bedingte Verarbeitung (in meinem Fall das Festlegen des Beschriftungstextes), und wenn infoDictionary oder CFBundleShortVersionString gleich Null sind, wird der Code beim optionalen Entpacken übersprungen.
self.labelVersion.textist optionaler Typ, so dass Sie direkt zuweisen könnenNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
Jonauz
8
Gibt es einen Grund, warum der Wert nicht festgelegt wird? Ich bin mir leteinig, dass es definitiv vorsichtiger ist und frage mich nur, warum es nötig sein könnte. Vielen Dank!
Crashalot
@Crashalot trotz Ihres Namens;) Sie möchten nicht, dass Ihre App abstürzt, wenn Sie beispielsweise einen Tippfehler machen, sondern die Versionsnummer lautet "etwas ist schief gelaufen".
Daniel Springer
OP: Sie können das ersetzen? mit! und entfernen Sie "als Zeichenfolge". Wenn es Null ist, wird es sowieso nicht abstürzen
Daniel Springer
245
Aktualisiert für Swift 3.0
Die NSPräfixe sind jetzt in Swift 3.0 verschwunden und einige Eigenschaften / Methoden haben den Namen geändert, um schneller zu sein. So sieht das jetzt aus:
Ich habe seit meiner ursprünglichen Antwort viel mit Frameworks gearbeitet, daher wollte ich meine Lösung auf etwas aktualisieren, das in einer Umgebung mit mehreren Bundles sowohl einfacher als auch viel nützlicher ist:
Jetzt ist diese Erweiterung in Apps nützlich, um sowohl das Hauptpaket als auch alle anderen enthaltenen Pakete (z. B. ein gemeinsames Framework für die Erweiterungsprogrammierung oder dritte Frameworks wie AFNetworking) zu identifizieren:
Ich wollte einige der bereits veröffentlichten Antworten verbessern. Ich habe eine Klassenerweiterung geschrieben, die zu Ihrer Werkzeugkette hinzugefügt werden kann, um dies logischer zu handhaben.
extensionNSBundle{classvar applicationVersionNumber:String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]
wie? String {return version} return "Versionsnummer nicht verfügbar"}
classvar applicationBuildNumber:String{iflet build =NSBundle.mainBundle().infoDictionary?["CFBundleVersion"]as?String{return build
}return"Build Number Not Available"}}
Jetzt können Sie einfach darauf zugreifen, indem Sie:
let versionNumber =NSBundle.applicationVersionNumber
classfunc getVersion()->String{guardlet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?Stringelse{return"no version info"}return version
}
Für ältere Versionen :
classfunc getVersion()->String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{return version
}return"no version info"}
Wenn Sie also Beschriftungstext festlegen oder woanders verwenden möchten;
oder: class func getVersion () -> String {return NSBundle.mainBundle (). infoDictionary? ["CFBundleShortVersionString"] as? String ?? "no version info"}
tapmonkey
Ich denke, das Kopieren anderer Antworten macht keinen Sinn. Wenn Ihre Antwort nicht mehr gültig ist, haben Sie immer die Möglichkeit, sie zu löschen und Platz für die anderen Antworten zu schaffen :)
carmen_munich
1
@carmen_munich Da du hier verleumdest, muss ich dir antworten. Zunächst wird diese Antwort im März 2015 und Ihre Antwort im Februar 2017 veröffentlicht. Daher muss Ihre Inspiration von den früheren Antworten stammen. Zweitens habe ich Ihre Antwort überhaupt nicht gesehen. Ich habe meine Antwort aktualisiert, weil ich sie heutzutage so verwende. Die Verwendung einer Erweiterung ist wohl nicht nur für jemanden in der iOS-Community möglich. Bitte versuchen Sie wirklich, reif zu sein und andere Entwickler zu respektieren. Ich bekomme hier nichts zu posten. Ich möchte Menschen helfen, das ist es. Bitte versuchen Sie nicht, Leute zu entmutigen, die versuchen, auf SO zu helfen.
Gunhan
Ich habe viele Rückmeldungen von Neulingen gehört, dass sie eine Antwort posten und sehen möchten, dass jemand auf "up" klickt, was wirklich schön zu sehen ist und die Leute motiviert. Aber wenn jemand Antworten in seine veraltete Antwort kopiert, wird derjenige, der sich die Mühe gemacht hat, sie zu veröffentlichen, nicht die Motivation bekommen, dass jemand dafür gestimmt hat. Die Neulinge sind also wirklich enttäuscht und haben das Gefühl, dass sie der Community keinen Wert bringen und aufhören zu posten. Und versteh es nicht falsch, ich meine das im Allgemeinen. Ich hoffe, Sie fühlen sich nicht beleidigt und verstehen jetzt besser, warum ich diesen Vorschlag gemacht habe.
carmen_munich
@carmen_munich Wenn Sie die Antworten auf diese Frage chronologisch sortieren, werden Sie feststellen, dass jemand anderes bereits die gleiche Antwort gegeben hat wie Sie vor Ihnen! Sie beschuldigen mich also, etwas getan zu haben, das Sie selbst getan haben. Da ich einen Verlauf für diese Frage habe, habe ich meine neuen Nutzungseinstellungen in einem Update geteilt. Das ist alles.
Gunhan
32
Für Swift 4.0
let version =Bundle.main.infoDictionary!["CFBundleShortVersionString"]!let build =Bundle.main.infoDictionary!["CFBundleVersion"]!
Eigentlich ist es etwas anders. Ich benutze zum Beispiel das gewaltsame Auspacken. Sie könnten denken, dass das Auspacken von Gewalt im Allgemeinen schlecht ist, dies ist einer der seltenen Fälle, in denen es in Ordnung ist. Um es etwas genauer zu erklären, sollten diese Werte im Wörterbuch enthalten sein, da sonst etwas mit der Projektdatei nicht stimmt. Deshalb verwendet dieser Ansatz das gewaltsame Auspacken :-)
carmen_munich
Das Umbenennen und Erzwingen des Auspackens ist keine Änderung, die als neue Antwort veröffentlicht werden muss. Außerdem können die Leute lernen, dass das Auspacken von Gewalt überall angewendet werden kann, wenn sie Ihre Antwort sehen. Nehmen Sie für die Leser nicht an, dass der Schlüssel vorhanden ist. Es ist immer besser, das optionale Auspacken manuell durchzuführen, als das Auspacken zu erzwingen.
Gunhan
Um fair zu sein, gibt es einige seltene Fälle, in denen das Auspacken von Gewalt in Ordnung ist. Dieser eine Beitrag zeigt nur einen Fall, in dem es in Ordnung sein kann. Wenn Sie mehr über das Auspacken von Gewalt erfahren möchten, finden Sie einige gute Erklärungen und Tutorials von Paul Hudson. Ich kann es wirklich allen Neulingen empfehlen www.hackingwithswift.com
carmen_munich
Es ist eine gute Empfehlung für die Neulinge. Vielleicht können Sie auch mehr lesen und mehr lernen. Außerdem sollten Sie Ihr Verständnis für Kommentare und deren Bedeutung verbessern. ZB hat dir niemand gesagt, dass du niemals / nie Gewalt beim Auspacken anwenden sollst. Aber für das Info-Diktat können diese Schlüssel entfernt werden und das gewaltsame Auspacken kann zu einem Absturz führen. Hier ist das Auspacken sicherer.
Gunhan
Vielleicht können Sie erklären, in welchem Fall sie entfernt werden können und gleich Null sind? Was ich aus der erwähnten Ressource gelernt habe, ist in diesem speziellen Fall nicht der Fall. Sie sollten immer da sein, es sei denn, die Projektdatei ist kaputt. In diesem Fall würde das Projekt wahrscheinlich sowieso nicht kompiliert werden
carmen_munich
16
Für Swift 3.0 funktioniert NSBundle nicht. Der folgende Code funktioniert einwandfrei.
let versionNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString")as!String
und für nur die Build-Nummer ist es:
let buildNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleVersion")as!String
Verwirrenderweise ist 'CFBundleVersion' die Build- Nummer, wie sie in Xcode unter Allgemein-> Identität eingegeben wurde.
Beachten Sie die Verwendung von localizedInfoDictionary, um die richtige Sprachversion des Anzeigenamens des Bundles zu ermitteln.
var displayName:String?var version:String?var build:String?overridefunc viewDidLoad(){super.viewDidLoad()// Get display name, version and build
iflet displayName =Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"]as?String{self.displayName = displayName
}iflet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String{self.version = version
}iflet build =Bundle.main.infoDictionary?["CFBundleVersion"]as?String{self.build = build
}}
let gAppVersion =Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString")??"0"let gAppBuild =Bundle.main.object(forInfoDictionaryKey:"CFBundleVersion")??"0"
importFoundationpublicextensionBundle{publicvar shortVersion:String{iflet result = infoDictionary?["CFBundleShortVersionString"]as?String{return result
}else{
assert(false)return""}}publicvar buildVersion:String{iflet result = infoDictionary?["CFBundleVersion"]as?String{return result
}else{
assert(false)return""}}publicvar fullVersion:String{return"\(shortVersion)(\(buildVersion))"}}
OP fragte sowohl nach der Versionsnummer als auch nach der Build-Nummer. Leider bieten die meisten Antworten nicht beide Optionen. Darüber hinaus fügen andere unnötige Erweiterungsmethoden hinzu. Hier ist eine, die ziemlich einfach ist und das Problem von OP löst:
Nachdem ich mir die Dokumentation angesehen habe, glaube ich, dass Folgendes sauberer ist:
let version =NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")as?String
Quelle : "Die Verwendung dieser Methode wird anderen Zugriffsmethoden vorgezogen, da sie den lokalisierten Wert eines Schlüssels zurückgibt, wenn einer verfügbar ist."
das ist der richtige schnelle Weg, keine Kraft auspacken, irgendwo
Juan Boero
5
Für Swift 1.2 ist es:
let version =NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]as!Stringlet build =NSBundle.mainBundle().infoDictionary!["CFBundleVersion"]as!String
extensionUIApplication{staticvar appVersion:String{iflet appVersion =NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString"){return"\(appVersion)"}else{return""}}staticvar build:String{iflet buildVersion =NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleVersionKey asString){return"\(buildVersion)"}else{return""}}staticvar versionBuild:String{let version =UIApplication.appVersion
let build =UIApplication.build
var versionAndBuild ="v\(version)"if version != build {
versionAndBuild ="v\(version)(\(build))"}return versionAndBuild
}}
Achtung: Sie sollten verwenden, wenn Sie dies hier zulassen, falls die App-Version oder der Build nicht festgelegt ist. Dies führt zu einem Absturz, wenn Sie versuchen, diese zu verwenden! auspacken.
Für alle Interessierten gibt es eine schöne und gepflegte Bibliothek mit dem Namen SwifterSwiftverfügbar unter Github und auch für jede Version von schnellen (siehe vollständig dokumentiert swifterswift.com ).
Mit dieser Bibliothek ist das Lesen der App-Version und der Build-Nummer so einfach:
importSwifterSwiftlet buildNumber =SwifterSwift.appBuild
let version =SwifterSwift.appVersion
Hier ist eine Funktion, mit der ich entscheide, ob eine Seite "Die App aktualisiert" angezeigt werden soll oder nicht. Es gibt die Build-Nummer zurück, die ich in ein Int konvertiere:
iflet version:String=Bundle.main.infoDictionary?["CFBundleVersion"]as?String{guardlet intVersion =Int(version)else{return}ifUserDefaults.standard.integer(forKey:"lastVersion")< intVersion {
print("need to show popup")}else{
print("Don't need to show popup")}UserDefaults.standard.set(intVersion, forKey:"lastVersion")}
Wenn es noch nie zuvor verwendet wurde, wird 0 zurückgegeben, was niedriger als die aktuelle Build-Nummer ist. Um neuen Benutzern einen solchen Bildschirm nicht anzuzeigen, fügen Sie einfach die Build-Nummer nach der ersten Anmeldung oder nach Abschluss des Onboarding hinzu.
Bundle + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Ich habe Ideen aus einigen Antworten kombiniert und ein wenig erweitert:
ein SwiftUI-Beispiel
Zeigt ein Warndreieck-Emoticon an (anstatt die App zum Absturz zu bringen), wenn der Schlüssel in der Info.plist fehlt
Foundation importieren
Erweiterungspaket {
publicvar appVersionShort:String?{iflet result = infoDictionary?["CFBundleShortVersionString"]as?String{return result
}else{return"⚠️"}}publicvar appVersionLong:String?{iflet result = infoDictionary?["CFBundleVersion"]as?String{return result
}else{return"⚠️"}}publicvar appName:String?{iflet result = infoDictionary?["CFBundleName"]as?String{return result
}else{return"⚠️"}}
CFBundleVersion
& CFBundleShortVersionString` nicht. Die erste ist Ihre Build- Version. Die andere ist die Versionsnummer . Siehe hier für weitere InformationenAntworten:
BEARBEITEN
Aktualisiert für Swift 4.2
BEARBEITEN
Wie von @azdev in der neuen Version von Xcode hervorgehoben, wird beim Kompilieren meiner vorherigen Lösung ein Kompilierungsfehler angezeigt. Um dies zu lösen, bearbeiten Sie es einfach wie vorgeschlagen, um das Bundle-Wörterbuch mit einem!
Bearbeiten beenden
Verwenden Sie einfach dieselbe Logik wie in Objective-C, jedoch mit einigen kleinen Änderungen
Ich hoffe das hilft dir weiter.
David
quelle
infoDictionary
sollte mit ausgepackt werden!
. Dies ist, was ich benutze, in eine Globals.swift-Datei gelegt:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Ich weiß, dass dies bereits beantwortet wurde, aber ich persönlich denke, dass dies ein wenig sauberer ist:
Swift 3.0:
Schnell <2.3
Auf diese Weise kümmert sich die if let-Version um die bedingte Verarbeitung (in meinem Fall das Festlegen des Beschriftungstextes), und wenn infoDictionary oder CFBundleShortVersionString gleich Null sind, wird der Code beim optionalen Entpacken übersprungen.
quelle
self.labelVersion.text
ist optionaler Typ, so dass Sie direkt zuweisen könnenNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
let
einig, dass es definitiv vorsichtiger ist und frage mich nur, warum es nötig sein könnte. Vielen Dank!Aktualisiert für Swift 3.0
Die
NS
Präfixe sind jetzt in Swift 3.0 verschwunden und einige Eigenschaften / Methoden haben den Namen geändert, um schneller zu sein. So sieht das jetzt aus:Alte aktualisierte Antwort
Ursprüngliche Antwort
quelle
Ich weiß auch, dass dies bereits beantwortet wurde, aber ich habe die vorherigen Antworten zusammengefasst:
(*) Für Erweiterungen aktualisiert
Verwendungszweck:
@ Veraltet: Alte Antworten
Swift 3.1 :
Für ältere Versionen :
Wenn Sie also Beschriftungstext festlegen oder woanders verwenden möchten;
quelle
Für Swift 4.0
quelle
Ich habe eine Erweiterung für Bundle erstellt
und dann benutze es
quelle
Für Swift 3.0 funktioniert NSBundle nicht. Der folgende Code funktioniert einwandfrei.
und für nur die Build-Nummer ist es:
Verwirrenderweise ist 'CFBundleVersion' die Build- Nummer, wie sie in Xcode unter Allgemein-> Identität eingegeben wurde.
quelle
Xcode 9.4.1 Swift 4.1
Beachten Sie die Verwendung von localizedInfoDictionary, um die richtige Sprachversion des Anzeigenamens des Bundles zu ermitteln.
quelle
Xcode 8, Swift 3:
quelle
Swift 4, nützliche Erweiterung für Bundle
quelle
Bundle + Extensions.swift
Verwendungszweck:
quelle
OP fragte sowohl nach der Versionsnummer als auch nach der Build-Nummer. Leider bieten die meisten Antworten nicht beide Optionen. Darüber hinaus fügen andere unnötige Erweiterungsmethoden hinzu. Hier ist eine, die ziemlich einfach ist und das Problem von OP löst:
quelle
Meine Antwort (Stand August 2015) angesichts von Swift entwickelt sich weiter:
quelle
Ich habe eine Erweiterung für UIApplication erstellt.
quelle
Nachdem ich mir die Dokumentation angesehen habe, glaube ich, dass Folgendes sauberer ist:
Quelle : "Die Verwendung dieser Methode wird anderen Zugriffsmethoden vorgezogen, da sie den lokalisierten Wert eines Schlüssels zurückgibt, wenn einer verfügbar ist."
quelle
Für Swift 1.2 ist es:
quelle
Swift 3:
Versionsnummer
Build-Nummer
quelle
Swift 4
Schnelle alte Syntax
quelle
Achtung: Sie sollten verwenden, wenn Sie dies hier zulassen, falls die App-Version oder der Build nicht festgelegt ist. Dies führt zu einem Absturz, wenn Sie versuchen, diese zu verwenden! auspacken.
quelle
Hier ist eine aktualisierte Version für Swift 3.2:
quelle
Sie können jetzt eine Konstante dafür verwenden, anstatt wie zuvor streng typisierten Code verwenden zu müssen, was die Dinge noch komfortabler macht.
quelle
quelle
SWIFT 4
// Holen Sie sich zuerst das nsObject, indem Sie es als optionales AnyObject definieren
// Dann wandle das Objekt einfach als String um, aber sei vorsichtig, vielleicht möchtest du noch einmal nach Null suchen
quelle
Für alle Interessierten gibt es eine schöne und gepflegte Bibliothek mit dem Namen
SwifterSwift
verfügbar unter Github und auch für jede Version von schnellen (siehe vollständig dokumentiert swifterswift.com ).Mit dieser Bibliothek ist das Lesen der App-Version und der Build-Nummer so einfach:
quelle
Update für Swift 5
Hier ist eine Funktion, mit der ich entscheide, ob eine Seite "Die App aktualisiert" angezeigt werden soll oder nicht. Es gibt die Build-Nummer zurück, die ich in ein Int konvertiere:
Wenn es noch nie zuvor verwendet wurde, wird 0 zurückgegeben, was niedriger als die aktuelle Build-Nummer ist. Um neuen Benutzern einen solchen Bildschirm nicht anzuzeigen, fügen Sie einfach die Build-Nummer nach der ersten Anmeldung oder nach Abschluss des Onboarding hinzu.
quelle
Für Swift 5.0 :
quelle
Einfache Dienstprogrammfunktion zum Zurückgeben der App-Version als Int
quelle
quelle
Bundle + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Ich habe Ideen aus einigen Antworten kombiniert und ein wenig erweitert:
Foundation importieren
Erweiterungspaket {
}}
SwiftUI Beispiel verwenden
quelle
quelle