如何编程获取Swift Package的名称与版本并在主应用展示?
解决方案:Swift Package 版本与名称的编程式获取
方案一:自动生成版本信息结构体(推荐,无需手动维护)
核心思路是通过预构建脚本从Package.swift中自动提取包名和版本号,生成可被主应用调用的信息结构体,彻底避免手动维护出错。
- 在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)
- 修改
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 ) ] )
- 主应用中直接调用获取信息:
let myPackageInfo = (name: MyPackage.PackageInfo.name, version: MyPackage.PackageInfo.version) // 收集所有包的信息后绑定到页面UI展示
方案二:利用Bundle.module读取Info.plist
延续你之前框架的Bundle用法,给Swift Package添加Info.plist并通过Bundle.module访问:
- 在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>
- 在
Package.swift中配置资源处理:
.target( name: "MyPackage", resources: [.process("Info.plist")] )
- 在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) }
- 主应用调用每个Package的该函数收集信息即可。
方案三:通过编译宏传递信息
直接在Package编译设置中注入包名和版本号,通过宏快速访问:
- 在
Package.swift中配置编译宏:
.target( name: "MyPackage", swiftSettings: [ .define("PACKAGE_NAME", to: "\"MyPackage\""), .define("PACKAGE_VERSION", to: "\"1.0.0\"") ] )
- 在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
相关产品推荐
相关产品推荐

