Swift & UI 进阶 20m
认识 Swift Package 插件
Meet Swift Package plugins
2022年6月6日
一句话判断
Swift Package Plugins 让你用纯 Swift 脚本自动化开发工作流——代码格式化、文档生成、版权更新——全部集成在 Xcode 14 中,无需额外工具。
这场 Session 讲了什么
Xcode 14 引入了 Swift Package Plugins,这是一种用 Swift 编写的脚本,可以对你的 Swift Package 或 Xcode Project 执行操作。插件分为两类:Command Plugins(命令插件)和 Build Tool Plugins(构建工具插件)。
Command Plugins 用于开发工作流自动化,比如运行代码格式化工具(SwiftFormat)、根据 Git 历史生成贡献者列表、更新源文件中的版权日期。Build Tool Plugins 扩展构建系统的依赖图,用于在构建过程中生成源代码或资源文件。
插件运行在沙盒中,默认没有网络访问权限,文件写入也受限。Command Plugins 可以声明需要文件写入权限,Xcode 会向用户请求确认。插件通过 PackagePlugin 模块提供的 API 访问 Package 的源文件和结构信息。
Session 完整演示了如何使用现成的插件(基于 Xcode 的右键菜单),以及插件的工作原理和架构。
值得深挖的点
- 插件的依赖管理:插件可以依赖其他 Package 中的工具(比如 SwiftFormat)。Xcode 会自动构建这些工具。工具可以是源码形式也可以是二进制形式。
- 沙盒安全模型:插件默认无法访问网络,只能写入特定的输出目录。需要修改源文件的插件必须声明权限,用户批准后才能运行。Xcode 会记住用户的选择。
- 插件与工具的分离:提供插件的 Package 和提供底层工具的 Package 可以是不同的。比如一个通用工具插件 Package 可以依赖 SwiftFormat,而你不需要修改 SwiftFormat 的源码。
- Private vs Public 插件:插件可以只在定义它的 Package 内部使用(private),也可以作为 Product 对外发布(public),让其他 Package 通过依赖声明使用。
代码片段
// Package.swift 中定义插件
// .plugin 目标声明
.product(
name: "MyPackage",
targets: [
// 定义一个命令插件
.plugin(
name: "GenerateContributors",
capability: .command(
intent: .sourceCodeEditing(),
permissions: [
.writeToPackageDirectory(
reason: "需要创建 CONTRIBUTORS 文件"
)
]
),
dependencies: [
// 插件可以依赖外部工具
.product(name: "SwiftFormat", package: "SwiftFormat")
]
),
// 定义一个构建工具插件
.plugin(
name: "GenerateSwiftCode",
capability: .buildTool()
)
]
)
// 插件的主入口——Command Plugin 示例
import PackagePlugin
struct GenerateContributors: CommandPlugin {
func performCommand(
context: PluginContext,
arguments: [String]
) async throws {
// 获取 Package 的源文件
let package = context.package
// 调用 Git 获取贡献者信息
let gitTool = try context.tool(named: "git")
let process = Process()
process.executableURL = URL(fileURLWithPath: gitTool.path.string)
process.arguments = ["log", "--format='%an'", "|", "sort", "-u"]
try process.run()
process.waitUntilExit()
// 将结果写入 CONTRIBUTORS 文件
// (需要声明 writeToPackageDirectory 权限)
}
}
最佳实践
- 优先搜索社区已有的插件,不要重复造轮子
- 需要修改源文件的插件要给出清晰的 reason 说明,让用户信任你的操作
- 插件脚本要处理错误情况,给出有意义的错误信息
- Build Tool Plugins 要注意增量构建——只在输入变化时重新生成
- 把插件作为 Product 发布可以让整个社区受益
还有什么值得关注
- “Create Swift Package plugins” 提供了完整的插件开发教程
- SwiftFormat、SwiftLint 等流行工具已经提供了插件适配
- Xcode 14 的插件支持也适用于 Xcode Project(不仅限于 Swift Package)
- 插件机制为代码生成的自动化(比如 Protocol Buffer、GraphQL)提供了标准化的方案
WWDC 2022