跳转到内容

迁移 Xcode 项目

迁移 Xcode 项目 {#migrate-an-xcode-project}

Section titled “迁移 Xcode 项目 {#migrate-an-xcode-project}”

除非你使用 Tuist 创建新项目(在这种情况下一切都会自动配置),否则你必须使用 Tuist 的原语来定义你的 Xcode 项目。这个过程的繁琐程度取决于你的项目的复杂程度。

正如你可能知道的,Xcode 项目会随着时间的推移变得混乱和复杂:不匹配目录结构的组、跨目标共享的文件、或指向不存在文件的文件引用(仅举几例)。所有这些累积的复杂性使得我们很难提供一个能够可靠迁移项目的命令。

此外,手动迁移是一个很好的清理和简化项目的练习。不仅项目中的开发者会感谢你,Xcode 也会感谢你,因为它处理和索引它们的速度会更快。一旦你完全采用 Tuist,它将确保项目定义的一致性,并保持项目的简单性。

为了简化这项工作,我们根据用户反馈提供了一些指南。

创建项目脚手架 {#create-project-scaffold}

Section titled “创建项目脚手架 {#create-project-scaffold}”

首先,使用以下 Tuist 文件为你的项目创建脚手架:

::: code-group

import ProjectDescription
let tuist = Tuist()
import ProjectDescription
let project = Project(
name: "MyApp-Tuist",
targets: [
/** Targets will go here **/
]
)
// swift-tools-version: 5.9
import PackageDescription
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(
// Customize the product types for specific package product
// Default is .staticFramework
// productTypes: ["Alamofire": .framework,]
productTypes: [:]
)
#endif
let package = Package(
name: "MyApp",
dependencies: [
// Add your own dependencies here:
// .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
// You can read more about dependencies here: https://docs.tuist.io/documentation/tuist/dependencies
]
)

:::

Project.swift 是定义项目的清单文件,Package.swift 是定义依赖项的清单文件。Tuist.swift 文件是你可以为项目定义项目级 Tuist 设置的地方。

::: tip 项目名称带 -TUIST 后缀

为了防止与现有 Xcode 项目冲突,我们建议在项目名称中添加 -Tuist 后缀。完全迁移到 Tuist 后,你可以删除它。

:::

在 CI 中构建和测试 Tuist 项目 {#build-and-test-the-tuist-project-in-ci}

Section titled “在 CI 中构建和测试 Tuist 项目 {#build-and-test-the-tuist-project-in-ci}”

为确保每次更改的迁移都有效,我们建议扩展你的持续集成,以从清单文件构建和测试 Tuist 生成的项目:

Terminal window
tuist install
tuist generate
xcodebuild build {xcodebuild flags} # or tuist test

将项目构建设置提取到 .xcconfig 文件 {#extract-the-project-build-settings-into-xcconfig-files}

Section titled “将项目构建设置提取到 .xcconfig 文件 {#extract-the-project-build-settings-into-xcconfig-files}”

将项目的构建设置提取到 .xcconfig 文件中,以使项目更精简、更容易迁移。你可以使用以下命令将项目的构建设置提取到 .xcconfig 文件中:

Terminal window
mkdir -p xcconfigs/
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -x xcconfigs/MyApp-Project.xcconfig

然后更新你的 Project.swift 文件,指向你刚刚创建的 .xcconfig 文件:

import ProjectDescription
let project = Project(
name: "MyApp",
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"), // [!code ++]
.release(name: "Release", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"), // [!code ++]
]),
targets: [
/** Targets will go here **/
]
)

然后扩展你的持续集成管道,运行以下命令以确保对构建设置的更改直接添加到 .xcconfig 文件中:

Terminal window
tuist migration check-empty-settings -p Project.xcodeproj

提取包依赖项 {#extract-package-dependencies}

Section titled “提取包依赖项 {#extract-package-dependencies}”

将项目的所有依赖项提取到 Tuist/Package.swift 文件中:

5.9
import PackageDescription
#if TUIST
import ProjectDescription
let packageSettings = PackageSettings(
// Customize the product types for specific package product
// Default is .staticFramework
// productTypes: ["Alamofire": .framework,]
productTypes: [:]
)
#endif
let package = Package(
name: "MyApp",
dependencies: [
// Add your own dependencies here:
// .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
// You can read more about dependencies here: https://docs.tuist.io/documentation/tuist/dependencies
.package(url: "https://github.com/onevcat/Kingfisher", .upToNextMajor(from: "7.12.0")) // [!code ++]
]
)

::: tip 产品类型

你可以通过在 PackageSettings 结构体的 productTypes 字典中添加特定包来覆盖该包的产品类型。默认情况下,Tuist 假设所有包都是静态框架。

:::

确定迁移顺序 {#determine-the-migration-order}

Section titled “确定迁移顺序 {#determine-the-migration-order}”

我们建议按照从依赖最多到最少的顺序迁移目标。你可以使用以下命令列出项目的目标,按依赖数量排序:

Terminal window
tuist migration list-targets -p Project.xcodeproj

从列表顶部开始迁移目标,因为这些是最被依赖的目标。

逐个迁移目标。我们建议为每个目标创建一个拉取请求,以确保在合并之前对更改进行审查和测试。

将目标构建设置提取到 .xcconfig 文件 {#extract-the-target-build-settings-into-xcconfig-files}

Section titled “将目标构建设置提取到 .xcconfig 文件 {#extract-the-target-build-settings-into-xcconfig-files}”

与项目构建设置一样,将目标构建设置提取到 .xcconfig 文件中,以使目标更精简、更容易迁移。你可以使用以下命令将目标的构建设置提取到 .xcconfig 文件中:

Terminal window
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -t TargetX -x xcconfigs/TargetX.xcconfig

Project.swift 文件中定义目标 {#define-the-target-in-the-projectswift-file}

Section titled “在 Project.swift 文件中定义目标 {#define-the-target-in-the-projectswift-file}”

Project.targets 中定义目标:

import ProjectDescription
let project = Project(
name: "MyApp",
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/Project.xcconfig"),
.release(name: "Release", xcconfig: "./xcconfigs/Project.xcconfig"),
]),
targets: [
.target( // [!code ++]
name: "TargetX", // [!code ++]
destinations: .iOS, // [!code ++]
product: .framework, // [!code ++] // or .staticFramework, .staticLibrary...
bundleId: "dev.tuist.targetX", // [!code ++]
sources: ["Sources/TargetX/**"], // [!code ++]
dependencies: [ // [!code ++]
/** Dependencies go here **/ // [!code ++]
/** .external(name: "Kingfisher") **/ // [!code ++]
/** .target(name: "OtherProjectTarget") **/ // [!code ++]
], // [!code ++]
settings: .settings(configurations: [ // [!code ++]
.debug(name: "Debug", xcconfig: "./xcconfigs/TargetX.xcconfig"), // [!code ++]
.debug(name: "Release", xcconfig: "./xcconfigs/TargetX.xcconfig"), // [!code ++]
]) // [!code ++]
), // [!code ++]
]
)

::: info 测试目标

如果目标有关联的测试目标,你也应该在 Project.swift 文件中定义它,重复相同的步骤。

:::

验证目标迁移 {#validate-the-target-migration}

Section titled “验证目标迁移 {#validate-the-target-migration}”

运行 tuist generate 后跟 xcodebuild build 以确保项目可以构建,并运行 tuist test 以确保测试通过。此外,你可以使用 xcdiff 将生成的 Xcode 项目与现有项目进行比较,以确保更改是正确的。

重复此操作,直到所有目标完全迁移完成。完成后,我们建议你更新 CI 和 CD 管道,使用 tuist generate 后跟 xcodebuild buildtuist test 来构建和测试项目。

由于缺少文件导致的编译错误 {#compilation-errors-due-to-missing-files}

Section titled “由于缺少文件导致的编译错误 {#compilation-errors-due-to-missing-files}”

如果与 Xcode 项目目标关联的文件并不都包含在表示目标的文件系统目录中,你最终可能会得到一个无法编译的项目。请确保使用 Tuist 生成项目后的文件列表与 Xcode 项目中的文件列表一致,并借此机会将文件结构与目标结构对齐。