You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程获取Swift Package的名称与版本并在主应用展示?

解决方案:Swift Package 版本与名称的编程式获取

方案一:自动生成版本信息结构体(推荐,无需手动维护)

核心思路是通过预构建脚本从Package.swift中自动提取包名和版本号,生成可被主应用调用的信息结构体,彻底避免手动维护出错。

  1. 在Swift Package根目录创建Scripts文件夹,添加GeneratePackageInfo.swift脚本:
import Foundation

// 读取Package.swift内容
guard let packageContent = try? String(contentsOfFile: "../Package.swift") else {
    fatalError("Failed to read Package.swift")
}

// 提取包名
let nameRegex = try! NSRegularExpression(pattern: #""name":\s*"([^"]+)""#, options: .caseInsensitive)
guard let nameMatch = nameRegex.firstMatch(in: packageContent, range: NSRange(packageContent.startIndex..., in: packageContent)),
      let nameRange = Range(nameMatch.range(at: 1), in: packageContent) else {
    fatalError("Failed to extract package name")
}
let packageName = String(packageContent[nameRange])

// 提取版本号
let versionRegex = try! NSRegularExpression(pattern: #""version":\s*"([^"]+)""#, options: .caseInsensitive)
guard let versionMatch = versionRegex.firstMatch(in: packageContent, range: NSRange(packageContent.startIndex..., in: packageContent)),
      let versionRange = Range(versionMatch.range(at: 1), in: packageContent) else {
    fatalError("Failed to extract package version")
}
let packageVersion = String(packageContent[versionRange])

// 生成PackageInfo.swift文件到Target目录
let outputPath = "../Sources/\(packageName)/PackageInfo.swift"
let outputContent = """
public struct PackageInfo {
    public static let name = "\(packageName)"
    public static let version = "\(packageVersion)"
}
"""

try! outputContent.write(toFile: outputPath, atomically: true, encoding: .utf8)
  1. 修改Package.swift,配置预构建插件确保脚本自动运行:
let package = Package(
    name: "MyPackage",
    products: [
        .library(name: "MyPackage", targets: ["MyPackage"]),
    ],
    targets: [
        .target(
            name: "MyPackage",
            dependencies: [],
            plugins: [.plugin(name: "GeneratePackageInfo")]
        ),
        .executableTarget(
            name: "GeneratePackageInfoScript",
            path: "Scripts",
            sources: ["GeneratePackageInfo.swift"]
        )
    ],
    plugins: [
        .command(
            name: "GeneratePackageInfo",
            executable: .target(name: "GeneratePackageInfoScript"),
            invocation: .whenPrebuild
        )
    ]
)
  1. 主应用中直接调用获取信息:
let myPackageInfo = (name: MyPackage.PackageInfo.name, version: MyPackage.PackageInfo.version)
// 收集所有包的信息后绑定到页面UI展示

方案二:利用Bundle.module读取Info.plist

延续你之前框架的Bundle用法,给Swift Package添加Info.plist并通过Bundle.module访问:

  1. 在Package的Target目录(如Sources/MyPackage)下添加Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundleShortVersionString</key>
    <string>$(MARKETING_VERSION)</string>
</dict>
</plist>
  1. 在Package.swift中配置资源处理:
.target(
    name: "MyPackage",
    resources: [.process("Info.plist")]
)
  1. 在Package中添加获取函数:
public func getPackageInfo() -> (name: String, version: String)? {
    guard let infoDict = Bundle.module.infoDictionary else { return nil }
    guard let name = infoDict["CFBundleName"] as? String,
          let version = infoDict["CFBundleShortVersionString"] as? String else {
        return nil
    }
    return (name, version)
}
  1. 主应用调用每个Package的该函数收集信息即可。

方案三:通过编译宏传递信息

直接在Package编译设置中注入包名和版本号,通过宏快速访问:

  1. 在Package.swift中配置编译宏:
.target(
    name: "MyPackage",
    swiftSettings: [
        .define("PACKAGE_NAME", to: "\"MyPackage\""),
        .define("PACKAGE_VERSION", to: "\"1.0.0\"")
    ]
)
  1. 在Package中暴露信息:
public func getPackageInfo() -> (name: String, version: String) {
    return (name: PACKAGE_NAME, version: PACKAGE_VERSION)
}

注意:此方案需手动维护编译宏中的版本号,适合版本更新不频繁的场景,也可配合脚本自动更新宏内容。

主应用统一收集建议

为了更优雅地管理所有Package的信息,可定义公共协议:

public protocol PackageInfoProvider {
    static func packageInfo() -> (name: String, version: String)
}

让每个Package的信息结构体实现该协议:

extension PackageInfo: PackageInfoProvider {
    public static func packageInfo() -> (name: String, version: String) {
        return (name: name, version: version)
    }
}

主应用中统一收集:

let allPackageInfos: [(name: String, version: String)] = [
    MyPackage1.PackageInfo.packageInfo(),
    MyPackage2.PackageInfo.packageInfo(),
    // 其他Package...
]

将收集到的数据绑定到页面UI,即可完成所有包的名称与版本展示。

内容的提问来源于stack exchange,提问作者Nicolai Schneider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:02:48