我有一个带有 Azure 后端的 IOS 应用程序,并且想要记录某些事件,例如登录以及用户正在运行的应用程序版本。
如何使用 Swift 返回版本和内部版本号?
CFBundleVersion
& CFBundleShortVersionString`。第一个是您的 build 版本。另一个是版本号。有关详细信息,请参阅 here
编辑
为 Swift 4.2 更新
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
编辑
正如@azdev 在新版本的 Xcode 中指出的那样,尝试我以前的解决方案时会出现编译错误,要解决这个问题,只需按照建议编辑它,使用 !
let nsObject: AnyObject? = Bundle.main.infoDictionary!["CFBundleShortVersionString"]
结束编辑
只需使用与 Objective-C 相同的逻辑,但有一些小的变化
//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
为 Swift 3.0 更新
NS
前缀现在在 Swift 3.0 中消失了,并且一些属性/方法的名称已更改为更加 Swifty。这是现在的样子:
extension Bundle {
var releaseVersionNumber: String? {
return infoDictionary?["CFBundleShortVersionString"] as? String
}
var buildVersionNumber: String? {
return infoDictionary?["CFBundleVersion"] as? String
}
}
Bundle.main.releaseVersionNumber
Bundle.main.buildVersionNumber
旧的更新答案
自从我最初的回答以来,我一直在使用框架,所以我想将我的解决方案更新为在多捆绑环境中更简单且更有用的东西:extension NSBundle { var releaseVersionNumber: String? { return self.infoDictionary?["CFBundleShortVersionString"] as?字符串} var buildVersionNumber:字符串? { return self.infoDictionary?["CFBundleVersion"] as? String } } 现在这个扩展将在应用程序中用于识别主包和任何其他包含的包(例如用于扩展编程的共享框架或第三个框架,如 AFNetworking),如下所示:NSBundle.mainBundle().releaseVersionNumber NSBundle。 mainBundle().buildVersionNumber // 或... NSBundle(URL: someURL)?.releaseVersionNumber NSBundle(URL: someURL)?.buildVersionNumber
原始答案
我想改进一些已经发布的答案。我编写了一个类扩展,可以将其添加到您的工具链中,以便以更合乎逻辑的方式处理此问题。扩展 NSBundle { class var applicationVersionNumber: String { if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String { return version } return "Version Number Not Available" } class var applicationBuildNumber: String { if let build = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as? String { return build } return "Build Number Not Available" } } 所以现在您可以通过以下方式轻松访问它: let versionNumber = NSBundle.applicationVersionNumber
我知道这已经得到了回答,但我个人认为这更干净一些:
斯威夫特 3.0:
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
self.labelVersion.text = version
}
斯威夫特 <2.3
if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
self.labelVersion.text = version
}
这样,if let 版本负责条件处理(在我的情况下设置标签文本),如果 infoDictionary 或 CFBundleShortVersionString 为 nil,则可选展开将导致代码被跳过。
self.labelVersion.text
是 Optional 类型,所以你可以直接赋值 NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
let
肯定会更加谨慎,只是想知道为什么可能需要它。谢谢!
我也知道这已经得到回答,但我总结了以前的答案:
(*) 为扩展更新
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")"
}
}
用法:
someLabel.text = Bundle.main.releaseVersionNumberPretty
@Deprecated:旧答案
斯威夫特 3.1:
class func getVersion() -> String {
guard let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else {
return "no version info"
}
return version
}
对于旧版本:
class func getVersion() -> String {
if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String {
return version
}
return "no version info"
}
所以如果你想设置标签文字或者想在别的地方使用;
self.labelVersion.text = getVersion()
对于 Swift 4.0
let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"]!
let build = Bundle.main.infoDictionary!["CFBundleVersion"]!
我在 Bundle 上做了一个扩展
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
}
}
然后使用它
versionLabel.text = "\(Bundle.main.appName) v \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"
Swift 5 作为 UIApplication 扩展
extension UIApplication {
static var release: String {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String? ?? "x.x"
}
static var build: String {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String? ?? "x"
}
static var version: String {
return "\(release).\(build)"
}
}
示例使用:
print("release: \(UIApplication.release)")
print("build: \(UIApplication.build)")
print("version: \(UIApplication.version)")
2021 年,斯威夫特 5
extension Bundle {
public var appName: String { getInfo("CFBundleName") }
public var displayName: String {getInfo("CFBundleDisplayName")}
public var language: String {getInfo("CFBundleDevelopmentRegion")}
public var identifier: String {getInfo("CFBundleIdentifier")}
public var copyright: String {getInfo("NSHumanReadableCopyright").replacingOccurrences(of: "\\\\n", with: "\n") }
public var appBuild: String { getInfo("CFBundleVersion") }
public var appVersionLong: String { getInfo("CFBundleShortVersionString") }
//public var appVersionShort: String { getInfo("CFBundleShortVersion") }
fileprivate func getInfo(_ str: String) -> String { infoDictionary?[str] as? String ?? "⚠️" }
}
用法(SwiftUI 示例):
Text("Ver: \(Bundle.main.appVersionLong) (\(Bundle.main.appBuild)) ")
Text(Bundle.main.copyright)
.font(.system(size: 10, weight: .thin))
.multilineTextAlignment(.center)
奖励:版权支持 \n 符号!
https://i.stack.imgur.com/ksGua.png
getInfo
?需要导入哪个包?
getInfo
是我回答的第一个代码块中编写的函数:)
Bundle+Extension.swift (SwiftUI, Swift 5, Xcode 11)
我结合了一些答案的想法,并扩展了一点:
一个 SwiftUI 示例
如果 Info.plist 中缺少该键,则显示警告三角形表情符号(而不是使应用程序崩溃)
进口基金会
extension Bundle {
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 "⚠️"
}
}
}
SwiftUI 示例使用
VStack {
Text("Version: \(Bundle.main.appVersionShort!) (\(Bundle.main.appVersionLong!))")
.font(.subheadline)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
我为 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: " ")
}
}
enum Constants {
enum InfoPlist {
static let versionNumber = "CFBundleShortVersionString"
static let buildNumber = "CFBundleVersion"
}
}
对于 Swift 3.0 NSBundle 不起作用,以下代码可以完美运行。
let versionNumberString =
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
as! String
对于内部版本号,它是:
let buildNumberString =
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")
as! String
令人困惑的是,'CFBundleVersion' 是 Xcode 在 General->Identity 上输入的内部版本号。
Xcode 9.4.1 斯威夫特 4.1
请注意使用本地化信息字典来获取包显示名称的正确语言版本。
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
}
}
Xcode 8,斯威夫特 3:
let gAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let gAppBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"
Swift 4,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))"
}
}
捆绑+扩展.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
}
}
用法:
someLabel.text = Bundle.main.versionNumber
OP 要求提供版本号和内部版本号。不幸的是,大多数答案都没有提供这两种选择。此外,其他人添加了不必要的扩展方法。这是一个非常简单并解决了 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 ""
}
}
鉴于 Swift 不断发展,我的回答(截至 2015 年 8 月):
let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
查看文档后,我认为以下内容更清晰:
let version =
NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")
as? String
Source:“使用此方法优于其他访问方法,因为它会在可用时返回键的本地化值。”
斯威夫特 5.3
let infoDictionaryKey = kCFBundleVersionKey as String
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: infoDictionaryKey) as? String
else { fatalError("Expected to find a bundle version in the info dictionary") }
对于 Swift 5.0:
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
对于 Swift 1.2,它是:
let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
斯威夫特 3:
版本号
if let versionNumberString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { // do something }
内部编号
if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }
这是 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)"
}
}
斯威夫特 4
func getAppVersion() -> String {
return "\(Bundle.main.infoDictionary!["CFBundleShortVersionString"] ?? "")"
}
Bundle.main.infoDictionary!["CFBundleShortVersionString"]
Swift 旧语法
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
}
}
注意:如果没有设置应用程序版本或构建,请在此处使用if let,如果您尝试使用会导致崩溃!展开。
Swift 5 更新
这是我用来决定是否显示“应用程序更新”页面的功能。它返回内部版本号,我将其转换为 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")
}
如果之前从未使用过,它将返回 0,它低于当前的内部版本号。要不向新用户显示这样的屏幕,只需在首次登录后或登录完成时添加内部版本号。
您现在可以为此使用常量,而不必像以前那样使用字符串类型的代码,这使事情变得更加方便。
var appVersion: String {
return Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String
}
public var appVersionNumberString: String {
get {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
}
}
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
self.lblAppVersionValue.text = version
}
斯威夫特 4
//首先通过定义为可选的AnyObject来获取nsObject
let nsObject: AnyObject? = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as AnyObject
//然后将对象转换为字符串,但要小心,您可能需要仔细检查 nil
let version = nsObject as! String
infoDictionary
应该使用!
展开。这就是我正在使用的,放入 Globals.swift 文件中:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String