跳转到内容

合成文件

Tuist 可以在生成时生成文件和代码,为管理和使用 Xcode 项目带来一些便利。在本页中,你将了解此功能以及如何在项目中使用它。

Xcode 项目支持向 target 添加资源。但是,它们给团队带来了一些挑战,尤其是在处理模块化项目时,源代码和资源经常被移动:

  • 不一致的运行时访问:资源在最终产品中的位置以及如何访问它们取决于 target 产品。例如,如果你的 target 代表一个应用,资源会被复制到应用 bundle 中。这导致访问资源的代码对 bundle 结构做出假设,这不理想,因为它使代码更难理解,资源也难以移动。
  • 不支持资源的产品:某些产品(如静态库)不是 bundle,因此不支持资源。因此,你必须使用不同的产品类型,例如框架,这可能会给你的项目或应用带来一些开销。例如,静态框架将静态链接到最终产品,并且需要一个构建阶段才能将资源仅复制到最终产品。或者对于动态框架,Xcode 会将二进制文件和资源都复制到最终产品,但会增加应用的启动时间,因为框架需要动态加载。
  • 容易出现运行时错误:资源通过其名称和扩展名(字符串)来标识。因此,任何一个中的拼写错误都会导致尝试访问资源时出现运行时错误。这不理想,因为它不会在编译时被捕获,并可能导致发布版本崩溃。

Tuist 通过合成统一的 bundle 和资源访问接口来解决上述问题,抽象了实现细节。

::: warning 推荐 虽然通过 Tuist 合成的接口访问资源不是强制的,但我们推荐使用它,因为它使代码更容易理解,资源更容易移动。 :::

Tuist 提供了用 Swift 声明 Info.plist 或 entitlements 等文件内容的接口。这对于确保跨 target 和项目的一致性以及利用编译器在编译时捕获问题很有帮助。你也可以提出自己的抽象来建模内容并在 target 和项目之间共享。

当你的项目被生成时,Tuist 会合成这些文件的内容并将它们写入相对于定义它们的项目目录的 Derived 目录。

::: tip 将 DERIVED 目录加入 GITIGNORE 我们建议将项目的 Derived 目录添加到 .gitignore 文件中。 :::

Tuist 合成一个访问包含 target 资源的 bundle 的接口。

target 将包含一个 Bundle 类型的扩展来暴露 bundle:

let bundle = Bundle.module

在 Objective-C 中,你将获得一个 {Target}Resources 接口来访问 bundle:

NSBundle *bundle = [MyFeatureResources bundle];

::: warning 内部 TARGET 的限制 目前,Tuist 不会为仅包含 Objective-C 源代码的内部 target 生成资源 bundle 访问器。这是 issue #6456 中跟踪的已知限制。 :::

::: tip 通过 BUNDLES 支持库中的资源 如果 target 产品(例如库)不支持资源,Tuist 会将资源包含在产品类型为 bundle 的 target 中,确保它最终出现在最终产品中,并且接口指向正确的 bundle。这些合成的 bundle 会自动标记为 tuist:synthesized 并继承其父 target 的所有标签,允许你在缓存配置中定位它们。 :::

资源通过其名称和扩展名使用字符串来标识。这不理想,因为它不会在编译时被捕获,并可能导致发布版本崩溃。为了防止这种情况,Tuist 将 SwiftGen 集成到项目生成过程中,以合成访问资源的接口。借助这一点,你可以放心地访问资源,利用编译器来捕获任何问题。

Tuist 默认包含模板来合成以下资源类型的访问器:

资源类型合成的文件
图片和颜色Assets+{Target}.swift
字符串Strings+{Target}.swift
属性列表{NameOfPlist}.swift
字体Fonts+{Target}.swift
文件Files+{Target}.swift

注意:你可以通过将 disableSynthesizedResourceAccessors 选项传递给项目选项来禁用每个项目合成资源访问器。

如果你想提供自己的模板来合成对其他资源类型的访问器,这些资源类型必须由 SwiftGen 支持,你可以在 Tuist/ResourceSynthesizers/{name}.stencil 处创建它们,其中名称是资源的小驼峰命名版本。

资源模板名称
stringsStrings.stencil
assetsAssets.stencil
plistsPlists.stencil
fontsFonts.stencil
coreDataCoreData.stencil
interfaceBuilderInterfaceBuilder.stencil
jsonJSON.stencil
yamlYAML.stencil
filesFiles.stencil

如果你想配置要合成访问器的资源类型列表,可以使用 Project.resourceSynthesizers 属性,传入你想使用的资源合成器列表:

let project = Project(resourceSynthesizers: [.string(), .fonts()])

::: info 参考 你可以在此示例中查看如何使用自定义模板合成资源访问器的示例。 :::