Swiftを使用してアプリのバージョンとビルド番号を取得するにはどうすればよいですか?


387

Azureバックエンドを備えたIOSアプリがあり、ログインやユーザーが実行しているアプリのバージョンなど、特定のイベントをログに記録したいと考えています。

Swiftを使用してバージョンとビルド番号を返すにはどうすればよいですか?



6
それはSwiftではなくObjective-Cです。
Øyvindヴィック

10
CFBundleVersion&CFBundleShortVersionString`と混同しないように注意してください。1つ目はビルドバージョンです。もう1つはバージョン番号です。詳細については、こちらを参照してください
Honey

1
@ØyvindVikほとんどの人は、Objective-Cソリューションを手で持たなくてもSwiftに変換できると考えています。
gnasher729

回答:


424

編集

Swift 4.2向けに更新

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String

編集

新しいバージョンのXcodeで@azdevが指摘したように、以前の解決策を試みるとコンパイルエラーが発生します。これを解決するには、!

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

これがお役に立てば幸いです。

デビッド


これを使用すると、コンパイラエラー "[NSObject:AnyObject]?does not have a member named 'subscript'"が発生します
andreas

AnyObjectを置き換えてみることができますか?AnyObject!使用しているコードを正確に知らないと、何が悪いのかを推測するのが非常に難しくなります。また、SwiftはXcodeのリリースごとに変更される可能性があるため、Xcodeのバージョンを知ることも重要です。
デビッド

18
@andreas infoDictionaryはを使用してラップ解除する必要があります!。これはGlobals.swiftファイルに置かれ、私が使用していますものです:let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as String
azdev

1
「!」をもう1つ追加する必要がありました。「として」の後。let appVersion = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String
yosei

3
強制アンラップ「!」の使用は避けてください。これらの値のいずれかがnilになるとアプリがクラッシュするため
Julius

279

私はこれがすでに回答されていることを知っていますが、個人的にはこれは少しクリーンだと思います:

Swift 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の場合、オプションのアンラップによりコードがスキップされます。


6
self.labelVersion.textはオプションタイプなので、直接割り当てることができますNSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as? String
ジョナウズ2015年

8
値が設定されない理由はありますか?letなぜそれが必要になるのか疑問に思っているだけで、は間違いなくより慎重であることに同意しました。ありがとう!
Crashalot 2016

@Crashalotあなたの名前にもかかわらず;)たとえば、タイプミスをしたとしても、バージョン番号が「何か問題があった」という場合にアプリをクラッシュさせたくありません。
ダニエルスプリンガー

OP:置き換えることができますか?と!そして、「as String」を削除します。それがnilなら、とにかくクラッシュしないでしょう
ダニエル・スプリンガー

245

Swift 3.0用に更新

NS-prefixesは今スウィフト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? String
    }

    var buildVersionNumber: String? {
        return self.infoDictionary?["CFBundleVersion"] as? String
    }

}

次のように、この拡張機能はアプリでメインバンドルと他の含まれているバンドル(拡張プログラミングの共有フレームワークやAFNetworkingなどの3番目のフレームワークなど)の両方を識別するのに役立ちます。

NSBundle.mainBundle().releaseVersionNumber
NSBundle.mainBundle().buildVersionNumber

// or...

NSBundle(URL: someURL)?.releaseVersionNumber
NSBundle(URL: someURL)?.buildVersionNumber

元の回答

すでに投稿されている回答のいくつかを改善したいと思いました。これをより論理的な方法で処理するためにツールチェーンに追加できるクラス拡張を作成しました。

extension NSBundle {

class var applicationVersionNumber: String {
    if let version = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"]

なので?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

CFBundleVersionKeyはSwift 3、Xcode 8では動作しなくなりました。使用する新しいキーを知っていますか?
Crashalot 2016

71

これはすでに回答済みであることも知っていますが、以前の回答をまとめました。

(*)拡張機能用に更新

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

@非推奨:古い回答

Swift 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()

1
または:クラスfunc getVersion()-> String {return NSBundle.mainBundle()。infoDictionary?["CFBundleShortVersionString"] as?ストリング ??「バージョン情報なし」}
tapmonkey 2015年

他の答えをコピーすることは意味がないと思います。あなたの答えがもう有効でない場合、あなたはいつでもそれを削除して他の答えのための場所を作る可能性があります:)
carmen_munich

1
@carmen_munichあなたがここで中傷するので、私はあなたに答えなければなりません。まず、この回答は2015年3月に投稿され、あなたの回答は2017年2月に投稿されます。したがって、あなたのインスピレーションは以前の回答から来ているはずです。第二に、私はあなたの答えをまったく見ていません。私はこの方法を最近このように使用しているので、答えを更新しました。拡張機能の使用は、私が推測するiOSコミュニティの誰かに固有のものではありません。本当に、成熟して他の開発者を尊重するようにしてください。ここに投稿しても何も得られません。私はそれだけの人々を助けたいです。SOを支援しようとする人々を落胆させないようにしてください。
Gunhan

初心者が回答を投稿し、誰かが「上」をクリックするのを見たいというフィードバックをたくさん聞きました。しかし、誰かが彼の古い回答で回答をコピーした場合、それを投稿しようと努力した人は、誰かが投票したという動機を得られません。したがって、初心者は本当にがっかりし、コミュニティに価値をもたらしたり、投稿を停止したりしないと感じています。誤解しないでください。これは一般的なことです。あなたが気分を害したり、私がこの提案をした理由を今よりよく理解したりしないことを願っています。
carmen_munich

@carmen_munichこの質問の回答を時系列で並べ替えると、他の誰かがすでにあなたの前と同じ回答をしていることに気付くでしょう。だからあなたは自分でやったことを私に責めているのです。この質問の履歴があるので、アップデートで新しい使用設定を共有しました。それで全部です。
Gunhan


29

バンドルの拡張を行いました

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

実際には少し異なります。たとえば、強制アンラップを使用します。強制アンラップは一般に悪いと思うかもしれませんが、これは大丈夫なまれなケースの1つです。もう少し説明すると、これらの値はディクショナリにあるはずです。そうでなければ、プロジェクトファイルに本当に問題があります。これが、このアプローチが強制アンラップを使用している理由です:-)
carmen_munich

名前の変更とアンラップの強制は、新しい回答として投稿するための変更ではありません。また、人々はあなたの答えを見たときに、力のアンラップがどこでも使用できることを学ぶかもしれません。読者にとって、キーがそこにあると想定しないでください。強制的にアンラップするよりも、オプションのアンラップを手動で処理する方が常に優れています。
ガンハン

公平を期すために、強制的にアンラップしても問題ないまれなケースがいくつかあります。この1つの投稿は、大丈夫なケースを1つだけ示しています。フォースアンラッピングのケースについて詳しく知りたい場合は、Paul Hudsonによる優れた説明とチュートリアルがあります。私はすべての初心者に本当にお勧めできますwww.hackingwithswift.com
carmen_munich

初心者にはお勧めです。たぶん、あなたはもっと読んで、もっと学ぶこともできます。また、コメントとその意味についての理解を深める必要があります。たとえば、強制アンラップを決して/決して使用しないと誰も言っていません。ただし、情報ディクショナリの場合、これらのキーを削除して強制アンラップを行うとクラッシュする可能性があります。ここでアンラップを処理する方が安全です。
Gunhan

たぶん、あなたは彼らが取り除かれ、nilになることができる場合を説明できますか?このリソースから私が学んだことは、この部分的なケースにはないということです。プロジェクトファイルが壊れていない限り、これらは常に存在している必要があります。その場合、プロジェクトはおそらくコンパイルされません
carmen_munich

16

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に入力されたビルド番号です。


16

Xcode 9.4.1 Swift 4.1

バンドル表示名の正しい言語バージョンを取得するために、localizedInfoDictionaryを使用していることに注意してください。

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

14

Xcode 8、Swift 3:

let gAppVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "0"
let gAppBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "0"

13

Swift 4、バンドル向けの便利な拡張機能

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.main.fullVersionと言う必要があります
Joseph Astrahan

12

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

使用法:

someLabel.text = Bundle.main.versionNumber

11

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

9

私の答え(2015年8月現在)、Swiftが進化し続けることを考えると:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

8

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

6

ドキュメントを見て、次の方がきれいだと思います。

let version = 
NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") 
as? String

出典:「このメソッドの使用は、キーのローカライズされた値が利用可能な場合にローカライズされた値を返すため、他のアクセスメソッドよりも優先されます。」


1
それが正しいSwiftの方法で、どこにも力をかけずに
Juan Boero

5

Swift 1.2の場合:

let version = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
let build = NSBundle.mainBundle().infoDictionary!["CFBundleVersion"] as! String

1
あなたは使うことができますか?同様に
Dan Rosenstark 2015

4

スウィフト3:

バージョンナンバー

if let versionNumberString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { // do something }

ビルド番号

if let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { // do something }

ビルド番号はどうですか?ありがとう!CFBundleVersionKeyが機能しません。
Crashalot 2016

@Crashalotビルド番号も更新しました。ここでは、すべてのCore Foundationのキーのリストもあります:developer.apple.com/library/content/documentation/General/...は
jasonnoahchoi

3

スウィフト4

func getAppVersion() -> String {
    return "\(Bundle.main.infoDictionary!["CFBundleShortVersionString"] ?? "")"
}

Bundle.main.infoDictionary!["CFBundleShortVersionString"]

Swiftの古い構文

let appVer: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]

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

}

注意:アプリのバージョンまたはビルドが設定されていない場合に使用すると、使用しようとするとクラッシュする可能性があります。アンラップする。


2

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

2

これで定数を使用できるようになりました。以前のように文字列型のコードを使用する必要がなくなり、さらに便利になりました。

var appVersion: String {
    return Bundle.main.infoDictionary![kCFBundleVersionKey as String] as! String
}


1

SWIFT 4

//まず、オプションのAnyObjectとして定義してnsObjectを取得します

let nsObject: AnyObject? = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as AnyObject

//オブジェクトを文字列としてキャストするだけですが、nilを再確認することをお勧めします

let version = nsObject as! String

1

興味のある方のためにSwifterSwiftgithubで利用できる素晴らしいライブラリがあり、すべてのバージョンのswiftについて完全に文書化されています(swifterswift.comを参照)。

このライブラリを使用すると、アプリのバージョンとビルド番号を読み取るのが次のように簡単になります。

import SwifterSwift

let buildNumber = SwifterSwift.appBuild
let version = SwifterSwift.appVersion

1

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を返します。このような画面を新しいユーザーに表示しないようにするには、最初のログイン後、またはオンボーディングが完了したときにビルド番号を追加します。


1

スウィフト5.0

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String

1

アプリのバージョンを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
    }

1
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            self.lblAppVersionValue.text = version
        }

1

Bundle + Extension.swift(SwiftUI、Swift 5、Xcode 11)

私はいくつかの回答からのアイデアを組み合わせ、少し拡張しました:

  • SwiftUIの例
  • Info.plistからキーが欠落している場合、(アプリをクラッシュさせるのではなく)警告三角形の絵文字を表示します

輸入財団

拡張バンドル{

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.