Avatar ·

Как получить версию и номер сборки приложения в Swift?

Всем привет! Я новичок в Swift и пишу своё первое iOS-приложение. Мне нужно отобразить текущую версию приложения (например, "1.2.3") и номер сборки (например, "45") на экране настроек. Я знаю, что эта информация хранится в Info.plist, но не могу понять, как правильно её извлечь через код. Я пробовал использовать Bundle.main.object(forInfoDictionaryKey:), но получаю nil или странные типы данных. Например, мой код: let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") print(version) // Выводит Optional(1.0) Пробовал также: let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") print(build) // Выводит Optional(1) Но когда я пытаюсь привести результат к String, у меня возникают ошибки. Кроме того, я слышал, что есть более современный способ через ProcessInfo. Подскажите, как правильно и надёжно получить эти значения? Желательно с примерами кода и объяснением, что делают эти ключи. Заранее спасибо! <<>>

Правильный способ получения версии и сборки приложения

В Swift для получения версии и номера сборки приложения используется класс Bundle. Вот самый надёжный и лаконичный способ:

let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Нет данных"
let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Нет данных"

print("Версия: \(appVersion), Сборка: \(buildNumber)")

Подробное объяснение

1. Что такое Info.plist?
Каждое iOS-приложение содержит файл Info.plist, где хранятся метаданные: название, идентификатор пакета, версия и т.д. Два ключа отвечают за версионирование:

  • CFBundleShortVersionString — версия приложения (например, "1.2.3"), видимая пользователю в App Store.
  • CFBundleVersion — номер сборки (например, "45"), используемый разработчиками для внутренней нумерации.

2. Почему ваш код не работал?
Вы использовали object(forInfoDictionaryKey:), который возвращает Any?. Проблема в том, что значения в Info.plist могут быть разных типов (String, Number). Попытка напрямую использовать их как строки приводит к ошибкам. Решение — явно привести к String через as? String.

3. Рекомендуемый подход
Используйте свойство infoDictionary — оно возвращает словарь [String: Any] со всеми ключами Info.plist. Затем извлекайте значения по ключам с безопасным приведением типов:

// Полная функция для удобства
func getAppVersionInfo() -> (version: String, build: String) {
    let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Неизвестно"
    let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Неизвестно"
    return (version, build)
}

// Использование
let info = getAppVersionInfo()
print("Версия: \(info.version), Сборка: \(info.build)")

4. Альтернативный метод через ProcessInfo (не рекомендуется)
Некоторые разработчики предлагают использовать ProcessInfo.processInfo.operatingSystemVersionString, но это даёт версию iOS, а не приложения. Для версии приложения этот способ не подходит.

Проверка в Xcode

Чтобы убедиться, что ключи заданы правильно, откройте Info.plist в Xcode и проверьте наличие полей:

  • Bundle versions string, short (CFBundleShortVersionString)
  • Bundle version (CFBundleVersion)

Если их нет, добавьте их вручную, нажав "+" в редакторе Info.plist.

Итоговый пример для экрана настроек

import UIKit

class SettingsViewController: UIViewController {
    @IBOutlet weak var versionLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "—"
        let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "—"
        versionLabel.text = "Версия \(version) (сборка \(build))"
    }
}

Этот код надёжен, безопасен и соответствует лучшим практикам Swift. Используйте его в своих проектах!

<<>>

Дополнительный подход: создание расширения для Bundle

Для удобства можно добавить вычисляемые свойства в расширение Bundle. Это сделает код чище и переиспользуемым:

extension Bundle {
    var appVersion: String {
        infoDictionary?["CFBundleShortVersionString"] as? String ?? "Неизвестно"
    }
    
    var buildNumber: String {
        infoDictionary?["CFBundleVersion"] as? String ?? "Неизвестно"
    }
    
    var fullVersionString: String {
        "Версия \(appVersion) (сборка \(buildNumber))"
    }
}

// Использование:
print(Bundle.main.fullVersionString) // "Версия 1.2.3 (сборка 45)"

Важные замечания

  • Всегда используйте as? String для безопасного приведения, так как ключи могут отсутствовать или иметь другой тип.
  • Не путайте CFBundleShortVersionString с CFBundleVersion: первый — для пользователей, второй — для внутреннего использования.
  • Если вы используете SwiftUI, можно создать @Environment или просто вызвать расширение в Text:
Text(Bundle.main.fullVersionString)
    .font(.caption)
    .foregroundColor(.gray)

Этот подход особенно полезен, когда версия приложения нужна в нескольких местах проекта.