Pastikan untuk tidak membingungkan CFBundleVersion& CFBundleShortVersionString`. Yang pertama adalah versi build Anda . Yang lainnya adalah nomor versi . Lihat di sini untuk info lebih lanjut
Sayang
1
@ ØyvindVik Kebanyakan orang beranggapan bahwa Anda dapat menerjemahkan solusi Objective-C ke Swift tanpa berpegangan tangan.
gnasher729
Jawaban:
425
EDIT
Diperbarui untuk Swift 4.2
let appVersion =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String
EDIT
Seperti yang ditunjukkan oleh @azdev pada versi baru Xcode Anda akan mendapatkan kesalahan kompilasi untuk mencoba solusi saya sebelumnya, untuk menyelesaikan ini cukup edit seperti yang disarankan untuk membuka bungkusan kamus bundel menggunakan!
let nsObject:AnyObject?=Bundle.main.infoDictionary!["CFBundleShortVersionString"]
Akhiri Edit
Cukup gunakan logika yang sama daripada di Objective-C tetapi dengan beberapa perubahan kecil
//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
Ketika saya menggunakan ini, saya mendapatkan kesalahan kompiler "[NSObject: AnyObject]? Tidak memiliki anggota bernama 'subskrip'"
andreas
Anda dapat mencoba mengganti AnyObject? oleh AnyObject! tanpa mengetahui persis kode yang Anda gunakan sangat sulit untuk menebak apa yang salah, juga perlu diingat bahwa Swift dapat berubah dari satu rilis Xcode ke yang lain, sehingga juga relevan untuk mengetahui versi Xcode Anda.
David
18
@andreas infoDictionaryharus dibuka menggunakan !. Inilah yang saya gunakan, ditempatkan dalam file Globals.swift:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
azdev
1
Saya harus menambahkan satu lagi "!" setelah "as". let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
yosei
3
Anda harus menghindari menggunakan membuka paksa "!" karena mereka akan menyebabkan aplikasi Anda mogok setiap kali salah satu dari nilai-nilai itu nol
Julius
279
Saya tahu ini sudah dijawab tetapi secara pribadi saya pikir ini sedikit lebih bersih:
Swift 3.0:
iflet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version
}
Cepat <2.3
iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{self.labelVersion.text = version
}
Dengan cara ini, versi if let menangani pemrosesan bersyarat (mengatur teks label dalam kasus saya) dan jika infoDictionary atau CFBundleShortVersionString adalah nihil, pembatalan opsional akan menyebabkan kode dilewati.
self.labelVersion.textadalah tipe opsional, sehingga Anda dapat langsung menetapkanNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
Jonauz
8
Apakah ada alasan nilainya tidak akan ditetapkan? Setuju itu pasti lebih berhati-hati let, hanya bertanya-tanya mengapa itu mungkin diperlukan. Terima kasih!
Crashalot
@ Crashalot terlepas dari nama Anda;) Anda tidak ingin aplikasi Anda mogok jika, katakanlah, Anda membuat kesalahan ketik, alih-alih minta nomor versi menjadi "ada yang salah".
Daniel Springer
OP: Anda bisa mengganti? dengan! dan hapus "as String". Jika nihil, tidak akan crash
Daniel Springer
245
Diperbarui untuk Swift 3.0
Itu NS -prefixes sekarang hilang di Swift 3.0 dan beberapa properti / metode telah berubah nama menjadi lebih Swifty. Seperti inilah bentuknya sekarang:
Saya sudah sering bekerja dengan Kerangka sejak jawaban asli saya, jadi saya ingin memperbarui solusi saya untuk sesuatu yang lebih sederhana dan jauh lebih berguna dalam lingkungan multi-bundel:
Sekarang ekstensi ini akan berguna dalam aplikasi untuk mengidentifikasi bundel utama dan bundel lain yang disertakan (seperti kerangka kerja bersama untuk pemrograman ekstensi atau kerangka kerja ketiga seperti AFNetworking), seperti:
Saya ingin memperbaiki beberapa jawaban yang sudah diposting. Saya menulis ekstensi kelas yang dapat ditambahkan ke rantai alat Anda untuk menangani ini dengan cara yang lebih logis.
extensionNSBundle{classvar applicationVersionNumber:String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]
sebagai? String {return version} return "Nomor Versi Tidak Tersedia"}
classvar applicationBuildNumber:String{iflet build =NSBundle.mainBundle().infoDictionary?["CFBundleVersion"]as?String{return build
}return"Build Number Not Available"}}
Jadi sekarang Anda dapat mengakses ini dengan mudah dengan:
let versionNumber =NSBundle.applicationVersionNumber
classfunc getVersion()->String{guardlet version =Bundle.main.infoDictionary?["CFBundleShortVersionString"]as?Stringelse{return"no version info"}return version
}
Untuk versi yang lebih lama :
classfunc getVersion()->String{iflet version =NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]as?String{return version
}return"no version info"}
Jadi jika Anda ingin mengatur teks label atau ingin menggunakan tempat lain;
atau: kelas func getVersion () -> String {return NSBundle.mainBundle (). infoDictionary? ["CFBundleShortVersionString"] sebagai? String ?? "no info info"}
tapmonkey
Saya pikir menyalin jawaban lain tidak masuk akal. Jika jawaban Anda tidak valid lagi maka Anda selalu memiliki kemungkinan untuk menghapusnya dan memberikan ruang untuk jawaban lainnya :)
carmen_munich
1
@carmen_munich Karena Anda memfitnah saya harus menjawabnya. Pertama-tama, jawaban ini diposting Maret 2015 dan jawaban Anda diposting Februari 2017. Oleh karena itu, inspirasi Anda harus berasal dari jawaban sebelumnya. Kedua, saya belum melihat jawaban Anda sama sekali, saya memperbarui jawaban saya karena saya menggunakannya sekarang. Saya kira, menggunakan ekstensi tidak unik bagi seseorang di komunitas iOS. Sungguh, coba untuk menjadi dewasa dan menghormati pengembang lain. Saya tidak mendapatkan apa pun yang diposkan di sini. Saya ingin membantu orang. Tolong usahakan untuk tidak mengecilkan hati orang yang mencoba membantu pada SO.
Gunhan
Saya mendengar banyak umpan balik dari para pemula bahwa mereka memposting jawaban dan ingin melihat seseorang mengklik "naik" yang sangat bagus untuk dilihat dan memotivasi orang. Tetapi jika seseorang menyalin jawaban dalam jawaban yang sudah ketinggalan zaman, orang yang berusaha mempostingnya tidak akan mendapatkan motivasi bahwa seseorang memilihnya. Jadi para pemula benar-benar merasa kecewa dan merasa bahwa mereka tidak membawa nilai bagi komunitas dan berhenti memposting. Dan jangan salah, maksud saya ini secara umum. Semoga Anda tidak merasa tersinggung dan mengerti sekarang lebih baik mengapa saya membuat saran ini.
carmen_munich
@carmen_munich Jika Anda secara kronologis memesan jawaban atas pertanyaan ini, Anda akan melihat bahwa orang lain sudah memberikan jawaban yang sama seperti yang Anda lakukan sebelumnya! Jadi Anda menyalahkan saya sesuatu yang Anda lakukan sendiri. Karena saya memiliki riwayat untuk pertanyaan ini, saya membagikan preferensi penggunaan baru saya dalam pembaruan. Itu saja.
Gunhan
32
Untuk Swift 4.0
let version =Bundle.main.infoDictionary!["CFBundleShortVersionString"]!let build =Bundle.main.infoDictionary!["CFBundleVersion"]!
Sebenarnya agak berbeda. Saya menggunakan kekuatan membuka bungkus misalnya. Anda mungkin berpikir bahwa membuka paksa secara umum adalah buruk, ini salah satu kasus yang jarang terjadi di mana itu boleh saja. Untuk menjelaskannya sedikit lebih, nilai-nilai ini harus ada di kamus jika tidak ada yang salah dengan file proyek. Itu sebabnya pendekatan ini menggunakan kekuatan membuka :-)
carmen_munich
Mengganti nama dan memaksa membuka bukan merupakan perubahan untuk memposting sebagai jawaban baru. Juga, orang-orang mungkin belajar memaksa membuka bungkus dapat digunakan di mana saja ketika mereka melihat jawaban Anda. Bagi para pembaca, jangan menganggap kuncinya ada di sana, selalu lebih baik untuk menangani pembatalan pilihan secara manual daripada memaksakan pembungkusan.
Gunhan
Agar adil ada beberapa kasus langka di mana membuka paksa paksa baik-baik saja. Posting yang satu ini hanya menunjukkan satu kasus di mana itu bisa baik-baik saja. Jika Anda ingin tahu lebih banyak tentang kasus membuka paksa ada beberapa penjelasan yang baik dan tutorial dari Paul Hudson. Saya benar-benar dapat merekomendasikan kepada semua pemula www.hackingwithswift.com
carmen_munich
Ini adalah rekomendasi yang bagus untuk para pemula. Mungkin Anda juga bisa membaca lebih banyak dan belajar lebih banyak. Anda juga harus meningkatkan pemahaman Anda tentang komentar dan apa implikasinya. Misalnya tidak ada yang bilang tidak pernah menggunakan kekuatan membuka bungkus. Tapi untuk info dict kunci-kunci itu bisa dilepas dan force undrap bisa mengakibatkan crash. Lebih aman untuk menangani membuka bungkus di sini.
Gunhan
Mungkin Anda bisa menjelaskan dalam hal apa mereka bisa dihapus dan menjadi nol? Apa yang saya pelajari dari sumber daya menyebutkan itu tidak dalam kasus partiuclare ini. Mereka harus selalu ada di sana kecuali file proyek rusak, dalam hal ini proyek mungkin tidak akan dikompilasi pula
carmen_munich
16
Untuk Swift 3.0 NSBundle tidak berfungsi, Kode berikut berfungsi dengan baik.
let versionNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleShortVersionString")as!String
dan hanya untuk nomor build, itu adalah:
let buildNumberString =Bundle.main.object(forInfoDictionaryKey:"CFBundleVersion")as!String
Yang membingungkan 'CFBundleVersion' adalah nomor build seperti yang dimasukkan dalam Xcode pada General-> Identity.
Perhatikan penggunaan localizedInfoDictionary untuk mengambil versi bahasa yang tepat dari nama tampilan bundel.
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 meminta nomor versi dan nomor pembuatan. Sayangnya sebagian besar jawaban tidak menyediakan kedua opsi tersebut. Selain itu, yang lain menambahkan metode ekstensi yang tidak perlu. Inilah satu yang cukup sederhana dan menyelesaikan masalah OP:
itu cara Swift yang tepat, tanpa kekuatan membuka, di mana saja
Juan Boero
5
Untuk Swift 1.2 itu:
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
}}
Perhatian: Anda harus menggunakan jika biarkan di sini jika versi aplikasi atau build tidak disetel yang akan menyebabkan crash jika Anda mencoba menggunakannya! untuk membuka
Anda sekarang dapat menggunakan konstanta untuk ini, daripada harus menggunakan kode yang diketik seperti sebelumnya, yang membuat segalanya lebih nyaman.
var appVersion:String{returnBundle.main.infoDictionary![kCFBundleVersionKey asString]as!String}
bagi siapa pun yang tertarik, ada perpustakaan yang bagus dan rapi yang disebut SwifterSwifttersedia di github dan juga sepenuhnya didokumentasikan untuk setiap versi swift (lihat swifterswift.com ).
menggunakan perpustakaan ini, membaca versi aplikasi dan nomor build akan semudah ini:
importSwifterSwiftlet buildNumber =SwifterSwift.appBuild
let version =SwifterSwift.appVersion
inilah fungsi yang saya gunakan untuk memutuskan apakah akan menampilkan halaman "aplikasi yang diperbarui" atau tidak. Ini mengembalikan nomor build, yang saya konversi menjadi Int:
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")}
Jika tidak pernah digunakan sebelumnya akan mengembalikan 0 yang lebih rendah dari nomor build saat ini. Untuk tidak menampilkan layar seperti itu kepada pengguna baru, cukup tambahkan nomor build setelah login pertama atau ketika on-boarding selesai.
Bundel + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Saya menggabungkan ide dari beberapa jawaban, dan sedikit memperluas:
contoh SwiftUI
Menampilkan emoticon segitiga peringatan (daripada menabrak aplikasi) jika kunci tidak ada dari Info.plist
Yayasan impor
bundel ekstensi {
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`. Yang pertama adalah versi build Anda . Yang lainnya adalah nomor versi . Lihat di sini untuk info lebih lanjutJawaban:
EDIT
Diperbarui untuk Swift 4.2
EDIT
Seperti yang ditunjukkan oleh @azdev pada versi baru Xcode Anda akan mendapatkan kesalahan kompilasi untuk mencoba solusi saya sebelumnya, untuk menyelesaikan ini cukup edit seperti yang disarankan untuk membuka bungkusan kamus bundel menggunakan!
Akhiri Edit
Cukup gunakan logika yang sama daripada di Objective-C tetapi dengan beberapa perubahan kecil
Saya harap ini membantu Anda.
David
sumber
infoDictionary
harus dibuka menggunakan!
. Inilah yang saya gunakan, ditempatkan dalam file Globals.swift:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
Saya tahu ini sudah dijawab tetapi secara pribadi saya pikir ini sedikit lebih bersih:
Swift 3.0:
Cepat <2.3
Dengan cara ini, versi if let menangani pemrosesan bersyarat (mengatur teks label dalam kasus saya) dan jika infoDictionary atau CFBundleShortVersionString adalah nihil, pembatalan opsional akan menyebabkan kode dilewati.
sumber
self.labelVersion.text
adalah tipe opsional, sehingga Anda dapat langsung menetapkanNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
let
, hanya bertanya-tanya mengapa itu mungkin diperlukan. Terima kasih!Diperbarui untuk Swift 3.0
Itu
NS
-prefixes sekarang hilang di Swift 3.0 dan beberapa properti / metode telah berubah nama menjadi lebih Swifty. Seperti inilah bentuknya sekarang:Jawaban Yang Diperbarui Lama
Jawaban Asli
sumber
Saya juga tahu ini sudah dijawab tetapi saya membungkus jawaban sebelumnya:
(*) Diperbarui untuk ekstensi
Pemakaian:
@Drecrecated: Jawaban lama
Swift 3.1 :
Untuk versi yang lebih lama :
Jadi jika Anda ingin mengatur teks label atau ingin menggunakan tempat lain;
sumber
Untuk Swift 4.0
sumber
Saya membuat Ekstensi di Bundel
dan kemudian menggunakannya
sumber
Untuk Swift 3.0 NSBundle tidak berfungsi, Kode berikut berfungsi dengan baik.
dan hanya untuk nomor build, itu adalah:
Yang membingungkan 'CFBundleVersion' adalah nomor build seperti yang dimasukkan dalam Xcode pada General-> Identity.
sumber
Xcode 9.4.1 Swift 4.1
Perhatikan penggunaan localizedInfoDictionary untuk mengambil versi bahasa yang tepat dari nama tampilan bundel.
sumber
Xcode 8, Swift 3:
sumber
Swift 4, Ekstensi berguna untuk Bundel
sumber
Bundel + Extensions.swift
Pemakaian:
sumber
OP meminta nomor versi dan nomor pembuatan. Sayangnya sebagian besar jawaban tidak menyediakan kedua opsi tersebut. Selain itu, yang lain menambahkan metode ekstensi yang tidak perlu. Inilah satu yang cukup sederhana dan menyelesaikan masalah OP:
sumber
Jawaban saya (per Agustus 2015), mengingat Swift terus berevolusi:
sumber
Saya membuat ekstensi untuk aplikasi UIA.
sumber
Setelah melihat dokumentasi, saya percaya bahwa yang berikut ini lebih bersih:
Sumber : "Penggunaan metode ini lebih disukai daripada metode akses lainnya karena metode ini mengembalikan nilai kunci yang dilokalkan ketika ada."
sumber
Untuk Swift 1.2 itu:
sumber
Swift 3:
Nomor Versi
Bangun nomor
sumber
Cepat 4
Sintaks lama yang cepat
sumber
Perhatian: Anda harus menggunakan jika biarkan di sini jika versi aplikasi atau build tidak disetel yang akan menyebabkan crash jika Anda mencoba menggunakannya! untuk membuka
sumber
Ini versi terbaru untuk Swift 3.2:
sumber
Anda sekarang dapat menggunakan konstanta untuk ini, daripada harus menggunakan kode yang diketik seperti sebelumnya, yang membuat segalanya lebih nyaman.
sumber
sumber
SWIFT 4
// Pertama dapatkan nsObject dengan mendefinisikan sebagai opsional AnyObject
// Kalau begitu, masukkan saja objek sebagai String, tapi hati-hati, kamu mungkin ingin mengecek nil
sumber
bagi siapa pun yang tertarik, ada perpustakaan yang bagus dan rapi yang disebut
SwifterSwift
tersedia di github dan juga sepenuhnya didokumentasikan untuk setiap versi swift (lihat swifterswift.com ).menggunakan perpustakaan ini, membaca versi aplikasi dan nomor build akan semudah ini:
sumber
Pembaruan untuk Swift 5
inilah fungsi yang saya gunakan untuk memutuskan apakah akan menampilkan halaman "aplikasi yang diperbarui" atau tidak. Ini mengembalikan nomor build, yang saya konversi menjadi Int:
Jika tidak pernah digunakan sebelumnya akan mengembalikan 0 yang lebih rendah dari nomor build saat ini. Untuk tidak menampilkan layar seperti itu kepada pengguna baru, cukup tambahkan nomor build setelah login pertama atau ketika on-boarding selesai.
sumber
Untuk Swift 5.0 :
sumber
Fungsi utilitas sederhana untuk mengembalikan versi Aplikasi sebagai Int
sumber
sumber
Bundel + Extension.swift (SwiftUI, Swift 5, Xcode 11)
Saya menggabungkan ide dari beberapa jawaban, dan sedikit memperluas:
Yayasan impor
bundel ekstensi {
}
Contoh penggunaan SwiftUI
sumber
sumber