大多数浏览器和
Developer App 均支持流媒体播放。
-
Swift 软件包插件简介
探索如何利用 Swift 软件包插件对 Swift 软件包和 Xcode 项目执行操作。我们将讨论这些插件的运行方式,以及您可以如何借助它们来生成源代码,并对您的开发工作流程进行自动化。
资源
相关视频
WWDC23
WWDC22
WWDC19
-
下载
♪ 柔和乐器演奏的嘻哈音乐 ♪ ♪ 您好 我的名字叫 Anders 在这个视频中 我将向您展示 如何开始使用 Swift 软件包插件 Swift 软件包 是在 Xcode 11 中引入的 它们提供了一种将库作为源代码分发 的好方法 Xcode 14 将这种方法 扩展到开发工作流程 让您可以使用插件来执行操作 例如在构建过程中生成源代码 或自动完成发布任务 我们先来看看软件包插件是什么 以及它们是如何工作的 然后更详细地讨论 Xcode 14 支持的 两种软件包插件 即命令插件和构建工具插件 首先 插件是什么 软件包插件是一种可以对 Swift 软件包 或 Xcode 项目 执行操作的 Swift 脚本 插件使用 Xcode 专门为此目的 提供的 API 软件包插件以 Swift 软件包的形式实现 软件包可以将插件 连同库和可执行文件一起提供 也可以只专注于提供插件 一个软件包插件可以 使用多个源文件实现 而用一个 Swift 软件包 可定义多个插件 一个高度专业化的插件 可以是提供该插件的包私有的 在这种情况下 它只能在这个包中使用 但是 如果一个通用插件 被定义为软件包产品 该插件即可供其他包使用 这样其他包也可以使用该插件 使用方式类似于 一个软件包如何使用另一个软件包中的库 但与库不同的是 插件的依赖项 不会将运行时内容引入您的 App 相反 它允许您访问 在您自己的机器上 或在您的自动构建过程中 运行的开发工具 那么软件包插件能做什么呢 Xcode 14 中有两种软件包插件 即命令插件和构建工具插件 命令插件执行 您可以随时运行的自定义操作 它们可以运行源代码格式化程序 或 Linter 或者执行 开发工作流程中包含的其他任务 这可能包括根据 Git 历史记录 更新源文件中的贡献者列表 或版权日期 也可能包括您今天 要使用任意脚本完成的其他工作 如果需要 命令插件可以请求权限 以修改包中的文件 这对于代码格式化特别有用 并非所有命令插件都需要写权限 一些命令可以创建报告 或计算代码的相关指标 而无需进行任何更改 构建工具插件扩展了 构建系统的依赖图 在构建过程中生成源代码或资源时 这些插件特别有用 与每次为整个包或项目调用的 命令插件不同 构建工具插件应用于 每个需要它们的目标 我们来看看如何在 Xcode 中使用命令插件 这是一个小的 iOS App 可显示各种几何形状 它由一个 App 项目 和一个本地软件包组成 这个软件包实现了 一个为此 App 提供 Core Data 类型和逻辑的库 我正在考虑将该包拆分到 其自己的存储库中 以便其他人使用 在此过程中 我想创建一个贡献者文件 其中列出 所有为该包贡献代码的开发者 我可以编写一个自定义脚本 来完成此工作 但我知道一个包提供了 一些有用的插件来处理代码 我认为这个包中有一个插件 可以完全满足我的需求 在访问这些插件时 我的操作 与我需要另一个包中的库时 执行的操作相同 我将在本地包的清单中 添加包依赖项 当我保存此清单时 Xcode 会获取远程包 这个包出现在 Package Dependencies 部分 我注意到 Xcode 还获取了 SwiftFormat SwiftFormat 是一种 流行的代码格式化工具 这是因为工具包中的一个命令插件 在 SwiftFormat 上 有一个依赖项 现在我已经添加了这个依赖项 我可以访问该包提供的 任何插件命令 我在要应用命令的包上 使用上下文菜单 现在菜单中有三个新命令 一个是为了使用 SwiftFormat 重新格式化源代码 另外两个提供专门的操作 其中一个 根据 Git 中的提交历史记录 生成或更新贡献者列表 另一个用于更新 源文件中的版权日期 此处中间的命令可执行我想要的操作 当我在我的包上调用该插件命令时 Xcode 让我可以选择 将哪个目标传递给插件 在本例中 我会在整个包上调用该命令 如果该插件接受自定义参数 我也可以传递这里的参数 我点击 Run 因为该插件会修改文件系统 Xcode 向我发出了警告 我可以看到插件作者所述的 想要修改代码的原因 但我也想看看该插件的实现过程 我选择 Show Command Xcode 向我显示了代码
这个插件执行的操作是安全的 因此我将再次调用命令 这次我会选择 Run
我会告诉 Xcode 记住我对这个插件做出的选择 这个特定的插件使用 Git 历史记录 来生成显示贡献者姓名的文件列表 但是命令插件可以做的事 有很大的灵活性 现在我们已经在 Xcode 中 使用了一个命令插件 让我们仔细看看 插件在后台是如何工作的 软件包插件是 根据需要编译和运行的 Swift 脚本 每个插件都作为一个单独的进程运行 插件可以访问输入包的提炼表示 包括其源文件 插件还获取 有关包的任何依赖项的信息 作为其工作的一部分 许多插件会调用命令行工具 插件还可以创建文件和目录 并使用 Foundation 等标准库 执行其他操作 插件在阻止网络访问的沙盒中运行 只能写入文件系统中的几个位置 例如构建输出目录 但是命令插件可以请求权限 以修改包源目录中的文件 如果用户批准 沙箱将被配置为 允许写入这些位置 插件也可以 将结果发送回 Xcode 并发出警告和错误提示 构建工具插件还可以定义工具调用 让 Xcode 在构建期间运行 所有软件包插件 都使用 Xcode 提供的 PackagePlugin 模块中的 API 这个 API 允许插件访问输入包 并在适当时将结果返回 Xcode 实现插件的主源文件 还定义了主入口点 这个类或结构体应符合 与插件类型匹配的协议 Xcode 调用的具体入口点函数 取决于它是什么类型的插件 您可以在 “构建 Swift 软件包插件” 视频中 了解有关 PackagePlugin API 的更多信息 之前 我们使用一个命令插件 对我们的包进行了修改 让我们看一下命令插件的更多细节 命令插件扩展了开发工作流程 它们直接应用于包 而不是在构建期间运行 并非所有命令插件都会修改文件系统 有些有用的操作 不涉及更改任何文件 但是如果一个命令 确实想写入文件系统 它必须在实现插件的包的清单中 对此进行声明 这会导致 Xcode 在让插件运行之前请求用户提供权限 插件通常很小 往往依赖其他工具来完成实际工作 之前 我们看到一个插件 使用 SwiftFormat 完成所有实际工作 工具包的依赖项 可以是二进制文件或源代码 Xcode 将在调用命令之前 从源代码构建任何所需的工具 请注意 插件可以由 与其依赖的工具不同的包提供 在命令插件的实现中 主类型符合 CommandPlugin 协议 插件实现 performCommand 入口点 这个入口点采用 上下文和用户提供的任何自定义参数 让我们看一下另一种 调用命令插件的方式 我将使用与之前相同的项目 因为我之前 在 SourceCodeUtilities 包上 添加了依赖项 所以我可以在终端中调用相同的插件 首先我要将目录改为 CoreLibs 包 因为这是我要应用命令插件的包 Swift Package Manager 5.6 有一个新的插件子命令 我将输入 “swift package plugin --list” 以查看可用的插件 这显示了 与 Xcode 菜单中相同的插件 在此处的命令行中 每个命令还显示了 应该用来运行此命令的动词 我将使用动词来重新生成 贡献者列表 就像我在 Xcode 中所做的那样 这个插件需要写入文件系统的权限 因为它将创建一个文件 我输入 “yes” 以允许此操作 这样该插件就可以 运行并更新贡献者列表 我还可以使用 包管理器选项 这个选项允许插件 无需询问即可写入文件系统 如果您从 CI 系统 或其他构建自动化中 调用该插件 这将特别有用 但在使用这个选项之前 请务必了解该插件的功能 就像在 Xcode 中一样 我可以将命令行参数传递给该插件 插件动作动词之后的任何参数 都将传递给该插件 在本例中 我传递了一个 verbose 标志 以查看该插件运行时的更多输出 每个命令插件都定义了其支持的参数 到目前为止 我们主要讨论的是命令插件 但是关于构建工具插件 我还有几点要说明 与命令插件不同 构建工具插件不会立即完成工作 反之 它创建并返回构建工具调用 以便 Xcode 稍后在构建包时运行 每个这种工具调用都有 一个要运行的命令行 还有告诉 Xcode 何时运行命令行的输入和输出 构建工具插件可以定义 在构建期间或构建之前运行的命令 我们将在一分钟内看看差异
构建工具插件返回的命令通常配置为 将其输出写入构建目录 因此它们在增量构建之间持续存在 与插件本身一样 构建工具插件定义的命令 在阻止网络访问的沙盒中运行 不能对包做任何更改 在构建工具插件的实现中 主类型符合 BuildToolPlugin 协议 插件实现 createBuildCommands 入口点 这个入口点需要上下文和目标 来创建构建命令 它返回应该在构建包时运行的 任何自定义构建命令 构建工具插件可以返回 两种基本的构建命令 普通构建命令指定输入和输出路径 仅在输出不存在 或输入更改时运行 预构建命令在构建开始之前运行 可以在事先不知道 输出名称时使用 预构建命令在每次构建之前运行 因此它们应确保在没有更改时 尽可能少地执行操作 构建命令和预构建命令 非常适合生成源代码或资源 那么 Xcode 如何知道 将哪些构建工具插件 应用于包目标呢 在 SwiftPM 5.6 及更高版本中 包清单中有一个 新的插件参数 其中列出了目标所需的构建工具插件 此参数指定了目标所需的 任何构建工具插件 就像它所依赖的任何运行时库一样 这些插件可以在同一个包中 也可以在不同的包中 让我们回到 Xcode 我要配置我的几何 App 以使用构建工具插件 在这个特定的案例中 我有一个自定义命令行工具 此工具可根据 我的 Core Library 目标中的 一些数据文件生成 Swift 代码 具体细节不重要 但我最后想谈谈 如何为每条数据 生成安全类型的 Swift 访问器 除了数据文件 我一直在使用一个自定义工具 来生成源代码 我已将这些源代码签入代码库中 我一直在手动运行这个工具 以重新生成 Swift 包装器代码 并在我的数据文件更改时提交更改 但是有了构建工具插件 我可以做得更好 我可以在构建期间生成代码 而不必将生成的代码保存在代码库中
为了访问插件 我转到包清单 并在提供我要使用的源生成器插件 的包上添加依赖项
我的包中的目标现在可以访问 该包中定义的任何构建工具插件
现在我转到需要使用插件的目标 并在其定义中添加一个插件参数
这告诉 Xcode 它想将该包中的特定构建工具 应用到我的目标 现在我可以从我的代码库中 删除生成的源文件 我们将在构建期间 根据需要创建或更新这些文件
这么做 整洁多了 现在 当我构建和运行 App 时 我的构建工具插件 会告诉 Xcode 在我的数据文件发生更改时 调用代码生成工具 生成的代码将 与我的构建文件夹中的其他构建文件 一起存储 以保持代码库清洁 在本视频中 我们讨论了 Swift 软件包插件是什么 以及它们是如何工作的 我们还讨论了 命令插件和构建工具插件之间的 一些相似之处和区别 这两种类型的插件 让您可以将各种随机脚本替换为 软件包中的一种更加结构化的可扩展性 构建工具插件允许您扩展构建系统 以生成源代码和资源 或在构建过程中完成其他自定义工作 命令插件允许您通过自定义操作 自动完成常见的开发任务 它们可以 针对特定的工作流程进行定制 也可以进行编写 以用于各种不同的情况 要了解如何创建您自己的软件包插件 请务必观看 “创建 Swift 包插件”视频 感谢观看本视频 希望您喜欢 WWDC 2022 的其余部分 ♪
-
-
import PackagePlugin @main struct MyPlugin: ... { // Entry points specific to plugin capability. These entry points are invoked // when the plugin is applied to a package. } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension MyPlugin: ... { // Entry points specific to plugin capability. These entry points are invoked // when the plugin is applied to an Xcdeo project. } #endif
-
8:33 - Structure of a command plugin with conditional support for Xcode projects when running in Xcode
import PackagePlugin @main struct MyPlugin: CommandPlugin { /// This entry point is called when operating on a Swift package. func performCommand(context: PluginContext, arguments: [String]) throws { debugPrint(context) } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension MyPlugin: XcodeCommandPlugin { /// This entry point is called when operating on an Xcode project. func performCommand(context: XcodePluginContext, arguments: [String]) throws { debugPrint(context) } } #endif
-
11:13 - Structure of a build tool plugin with conditional support for Xcode projects when running in Xcode
import PackagePlugin @main struct MyPlugin: BuildToolPlugin { /// This entry point is called when operating on a Swift package. func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] debugPrint(context) return [] } } #if canImport(XcodeProjectPlugin) import XcodeProjectPlugin extension MyPlugin: XcodeBuildToolPlugin { /// This entry point is called when operating on an Xcode project. func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] debugPrint(context) return [] } } #endif
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。