本文字数:12182字
预计阅读时间:31分钟
Swift Package Manager
(下文简称 SwiftPM
)是苹果官方提供的一个用于管理源代码分发的工具,它与Swift构建系统集成在一起,可以自动执行依赖项的下载,编译和链接过程。该工具可以帮助我们编译和链接 Swift packages(包),管理依赖关系、版本控制,以及支持灵活分发和协作(公开、私有、团队共享)等。支持Swift、Objective-C、Objective-C ++、C或C ++。SwiftPM
包管理器支持 macOS 和 Linux,与CocoaPods和Carthage功能类似,不过比这两个更简洁,代码的侵入性更小,也不需要额外安装工具。
狐友iOS技术团队深度使用了SwiftPM
,在实际项目中全面替代曾经长期使用的CocoaPods
;本文将详细介绍狐友团队在引入SwiftPM
进行工程实践中,探索和累积的相关知识和实践经验,我们将从结构设计、资源处理、链接方式的选择、编译与链接参数设置、异常处理,这五个方面展开详细介绍,每个小部分结尾都提供了最佳实践的总结;希望能够帮助其他想要尝试SwiftPM
的开发者顺利过渡;
本文面向了解SwiftPM
基本知识,但是没有深度使用的开发者;如果你还不了解SwiftPM
,建议首先阅读WWDC相关视频;
结构设计
代码组织方式
目录结构
创建SwiftPM
组织结构与路径设置
依赖处理
Objc与Swift混编
最佳实践
资源处理
Package内部几种资源处理的方式
读取资源
读取Asset Catalog中图片
获取prcoess处理的资源
获取copy处理的资源
最佳实践
链接方式的选择
静态链接与动态链接的区别
SwiftPM编译链接选项
最佳实践
编译与链接参数设置
定制编译参数
关闭ARC
预编译宏设置
链接参数设置
异常处理
非Clang Module生成的SwiftPM接入
无法解决的包管理的问题
总结
参考
结构设计
梳理清楚代码之间的依赖关系,对于设计SwiftPM
中,模块如何组成和进行合理拆分,非常重要!
代码组织方式
建议从两个维度考虑组件的组织方式,组件的性质:基础组件,业务组件;代码的依赖关系:通用组件,专用组件;
优先统一代码语言,把Objc代码全部转成Swift后,会很方便整合到
SwiftPM
中;如果Objc代码过多,或者这部分OBjc代码是一个完整的功能模块,即不存在Swift/Objc互相依赖混编的情况,也可以拆分到一个
SwiftPM
中;如果一个模块依赖另一个模块中的极少数代码,可以考虑复制所需代码到本模块,并标记为非
public
,解除模块之间耦合关系;
目录结构
推荐使用命令行方式创建SwiftPM
;注意命名时尽可能与模块功能相符,不要包含Lib、Framework等不能体现功能的描述;
创建SwiftPM
$ mkdir MyPackage
$ cd MyPackage
$ swift package init # or swift package init --type library
默认创建的SwiftPM
项目的名字就是文件夹的名字;这将创建带有目标target和相应测试target的库,包含所需的目录结构和单元测试,如下面所示:
Tests //单元测试
--MyPackageTests
-----MyPackageTests.swift
Sources
--MyPackage //同顶层目录名的target目录
-----MyPackage.swift
README.md //文档
Package.swift //配置文件,类似Cocoapods自定义pod库的podspec文件
组织结构与路径设置
生成的Package.swift
如下面所示:
let package = Package(
name: "MyPackage",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MyPackage",
targets: ["MyPackage"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target( //单独一个Target
name: "MyPackage",
dependencies: []), //此处没有设置path,默认查找Sources下MyPackage目录
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]),
]
)
由于一个SwiftPM
库包可以包含多个target
,所以Sources/Tests
目录下存放源代码的目录结构组织方式,有不同的选择;有两种方式可供参考:
单Target模式,默认情况下,SwiftPM自动创建生成对应的target目录,如当前目录结构所示,查找Sources下MyPackage目录,**
Sources
目录下仅有一个目录MyPackage</