如何构建含多组件的Swift包(SPM)并实现独立版本化?
单仓多Swift组件的版本与结构解决方案
一、目录结构规范
根据是否需要组件独立版本,推荐两种清晰的目录结构:
方案1:单Package多产品(版本统一)
适合接受整个仓库共用一个版本号,仅需多个独立library供外部依赖的场景:
newskit-themes/ ├── .gitignore ├── Package.swift ├── Newskit/ │ ├── Sources/ │ │ └── Newskit/ # 存放Newskit的所有.swift源码 │ └── Tests/ │ └── NewskitTests/ # 存放Newskit的测试代码 └── TheSun/ ├── Sources/ │ └── TheSun/ # 存放TheSun的所有.swift源码 └── Tests/ └── TheSunTests/ # 存放TheSun的测试代码
方案2:单仓多独立Package(组件单独版本)
适合需要每个组件拥有独立版本号的场景:
newskit-themes/ ├── .gitignore ├── Newskit/ │ ├── Package.swift # Newskit专属的包配置文件 │ ├── Sources/ │ │ └── Newskit/ │ └── Tests/ │ └── NewskitTests/ └── TheSun/ ├── Package.swift # TheSun专属的包配置文件 ├── Sources/ │ └── TheSun/ └── Tests/ └── TheSunTests/
二、对应的Package.swift写法
方案1:单Package多产品的配置
优化原有代码,添加测试target并指定路径,确保SwiftPM正确识别源码位置:
// swift-tools-version:5.7 import PackageDescription let package = Package( name: "newskit-themes", platforms: [.iOS(.v12)], products: [ // 定义两个独立的library产品 .library(name: "Newskit", targets: ["Newskit"]), .library(name: "TheSun", targets: ["TheSun"]) ], targets: [ // Newskit主target .target( name: "Newskit", path: "Newskit/Sources/Newskit" ), // Newskit测试target .testTarget( name: "NewskitTests", dependencies: ["Newskit"], path: "Newskit/Tests/NewskitTests" ), // TheSun主target .target( name: "TheSun", path: "TheSun/Sources/TheSun" ), // TheSun测试target .testTarget( name: "TheSunTests", dependencies: ["TheSun"], path: "TheSun/Tests/TheSunTests" ) ] )
这种方式下,给整个仓库打统一git tag(如1.0.0)即可,外部项目可单独依赖某个library:
// 外部项目的Package.swift dependencies: [ .package(url: "https://github.com/你的用户名/newskit-themes.git", from: "1.0.0") ], targets: [ .target( name: "你的项目", dependencies: ["Newskit"] // 仅依赖Newskit ) ]
方案2:多独立Package的配置
每个组件的Package.swift完全独立,以Newskit为例:
// Newskit/Package.swift // swift-tools-version:5.7 import PackageDescription let package = Package( name: "Newskit", platforms: [.iOS(.v12)], products: [ .library(name: "Newskit", targets: ["Newskit"]) ], targets: [ .target(name: "Newskit"), .testTarget(name: "NewskitTests", dependencies: ["Newskit"]) ] )
TheSun的Package.swift只需把name和target名替换为TheSun即可。
这种方式下,需为每个组件单独打git tag(建议前缀区分,如newskit-2.1.0、thesun-1.3.0),外部项目可单独依赖指定版本的组件:
// 外部项目的Package.swift dependencies: [ .package(url: "https://github.com/你的用户名/newskit-themes.git", path: "Newskit", from: "2.1.0"), .package(url: "https://github.com/你的用户名/newskit-themes.git", path: "TheSun", from: "1.3.0") ]
三、关键注意事项
- 命名习惯:Swift包和target名建议用大驼峰格式(如
Newskit而非newskit),符合社区通用规范。 - 版本管理:单Package方案版本统一,更新任意组件都需升级仓库版本;多独立Package方案版本独立,需注意tag命名清晰避免混淆。
- 测试隔离:每个组件都应配置专属的测试target,保证测试代码和业务代码分离,便于维护。
内容的提问来源于stack exchange,提问作者Marco Vanali
相关产品推荐
相关产品推荐

