Swift项目高级CI/CD:使用GitHub Actions优化流水线
构建、测试和部署的自动化是现代iOS和macOS开发中不可或缺的一部分。基础的CI/CD流水线能解决简单问题,但在涉及Swift、Swift Package Manager (SPM)、多个目标和复杂依赖的实际项目中,需要更高级的方法。本文将深入探讨如何利用GitHub Actions,通过矩阵构建、缓存优化、并行测试以及自动部署到TestFlight / App Store,将您的CI/CD流程提升到新水平。
1. 跨平台矩阵构建 (Matrix Builds)
GitHub Actions的关键功能之一是矩阵策略。它允许使用不同的参数(Xcode版本、构建方案、平台)运行同一个工作流。这对于支持iOS、macOS、tvOS和watchOS的Swift项目尤其有用。
Swift项目的矩阵配置示例:
jobs: build: strategy: matrix: platform: [iOS, macOS, tvOS] xcode-version: ['15.0', '15.2'] exclude: - platform: tvOS xcode-version: '15.0' # 排除不兼容的组合 runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: 选择 Xcode ${{ matrix.xcode-version }} run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode-version }}.app - name: 为 ${{ matrix.platform }} 构建 run: | xcodebuild clean build \ -scheme MyApp \ -destination "platform=${{ matrix.platform }}" \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO这种方法允许在一次推送中,在所有支持的平台和Xcode版本上验证构建,从而节省开发人员的时间。
2. 高级缓存:将构建速度提升2-3倍
Swift项目的构建是一个资源密集型过程。缓存SPM依赖项和DerivedData可以将流水线时间缩短50-70%。不要使用基本缓存,而应使用考虑依赖项版本的自定义键。
针对SPM和Xcode的优化缓存:
- name: 缓存 SPM uses: actions/cache@v3 with: path: | .build SourcePackages key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }} restore-keys: | ${{ runner.os }}-spm-
- name: 缓存 DerivedData uses: actions/cache@v3 with: path: ~/Library/Developer/Xcode/DerivedData key: ${{ runner.os }}-derived-${{ hashFiles('**/*.swift') }} restore-keys: | ${{ runner.os }}-derived-重要提示: 使用 hashFiles('**/Package.resolved') 可以在依赖项更改时精确地使缓存失效。对于DerivedData,键可以是所有Swift文件的哈希值——这确保缓存仅在代码实际更改时更新。
3. 并行测试与报告
对于包含数百个单元测试的大型Swift项目,顺序运行可能需要20-30分钟。解决方案是将测试分组并在多个运行器上并行执行。
并行测试的实现:
test: strategy: matrix: test-group: [1, 2, 3, 4] runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: 运行测试 (第 ${{ matrix.test-group }} 组) run: | xcodebuild test \ -scheme MyApp \ -destination "platform=iOS Simulator,name=iPhone 15 Pro" \ -only-testing:MyAppTests/TestGroup${{ matrix.test-group }} \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO - name: 上传测试结果 if: always() uses: actions/upload-artifact@v4 with: