Customize your advanced Xcode Cloud workflows
Developer Tools 高级 13m

自定义高级 Xcode Cloud 工作流

Customize your advanced Xcode Cloud workflows

2021年6月8日

在 Apple 官方观看视频

一句话判断

如果你的 Xcode Cloud workflow 超出了「构建-测试-分发」的标准模板,这个 Session 教你用脚本和环境变量填平那些边角需求。

这场 Session 讲了什么

前两个 Xcode Cloud Session 覆盖了基本概念和 workflow 配置,这个 Session 聚焦在高级自定义场景。核心是 ci_scripts 目录——你在项目根目录下创建这个文件夹,放入特定的 shell 脚本,Xcode Cloud 会在构建生命周期的不同节点自动调用它们。

关键脚本有两个:ci_post_clone.sh(代码克隆后执行)和 ci_post_xcodebuild.sh(构建完成后执行)。Session 展示了几个典型用例:在克隆后安装 CocoaPods 或 SPM 的本地工具、运行代码风格检查、在构建后上传 dSYM 到第三方服务、发送通知到 Slack。Xcode Cloud 注入了大量环境变量(以 CI_ 开头),你可以在脚本中读取当前分支、scheme 名称、构建号等信息来驱动条件逻辑。

Session 还提到了一个容易踩的坑:脚本必须有可执行权限(chmod +x),否则 Xcode Cloud 会跳过它。另外,脚本执行失败会导致整个构建失败,所以如果你某个步骤是非关键的(比如代码风格检查),需要自己处理错误退出。

值得深挖的点

ci_post_clone.sh 的时序陷阱。 这个脚本执行时机是「代码已克隆,但尚未开始构建」。如果你在这里安装依赖(比如 pod install),要确保生成的 .xcworkspace 文件是 workflow 中 scheme 能找到的。一个常见的坑是:你的 workflow 配置的是 .xcodeproj,但 pod install 之后需要用 .xcworkspace 才能编译。解决办法是在脚本里直接修改 workspace 文件,或者在 workflow 设置中选择正确的 workspace。

环境变量的安全使用。 Xcode Cloud 允许你在 workflow 设置中定义自定义环境变量,可以标记为「敏感」(Secure),这样在构建日志中会被掩码显示。这很适合存放 API Key、Slack Webhook URL 等。但要注意,这些变量会以明文形式注入到 shell 脚本的环境中,所以不要在 echo 或日志中意外泄露。

代码片段

#!/bin/bash
# ci_scripts/ci_post_clone.sh
# 安装依赖并准备构建环境

set -euo pipefail

echo "=== 开始准备构建环境 ==="
echo "仓库: $CI_REPOSITORY_URL"
echo "分支: $CI_COMMIT_BRANCH"
echo "Scheme: $CI_XCODEBUILD_SCHEME"

# 安装 CocoaPods
if [ -f "Podfile" ]; then
    echo "检测到 Podfile,开始安装依赖..."
    gem install cocoapods --no-document --quiet
    pod install --repo-update
    echo "CocoaPods 依赖安装完成"
fi

# 安装 SwiftGen 等代码生成工具
if [ -f "swiftgen.yml" ]; then
    brew install swiftgen
    swiftgen
fi
#!/bin/bash
# ci_scripts/ci_post_xcodebuild.sh
# 构建完成后的后处理

set -euo pipefail

if [ "$CI_RESULT" = "success" ]; then
    echo "构建成功!版本号: $CI_BUILD_NUMBER"

    # 上传 dSYM 到 Firebase Crashlytics
    if [ -n "${FABRIC_API_KEY:-}" ]; then
        echo "上传符号文件..."
        # 找到 dSYM 文件并上传
        find "$CI_DERIVED_DATA_PATH" -name "*.dSYM" -exec \
            ./Pods/Fabric/upload-symbols -a "$FABRIC_API_KEY" {} \;
    fi

    # 发送构建成功通知到 Slack
    if [ -n "${SLACK_WEBHOOK:-}" ]; then
        curl -s -X POST "$SLACK_WEBHOOK" \
            -H 'Content-Type: application/json' \
            -d "{\"text\": \"✅ 构建 #$CI_BUILD_NUMBER 成功 ($CI_COMMIT_BRANCH)\"}"
    fi
fi
#!/bin/bash
# 示例:在脚本中读取 Xcode Cloud 的环境变量
# 常用变量列表:
# CI_BUILD_NUMBER          - 构建编号
# CI_COMMIT_BRANCH         - 当前分支
# CI_COMMIT_SHA            - 提交哈希
# CI_PRODUCT               - 产品名称
# CI_SCHEME                - scheme 名称
# CI_XCODE_VERSION         - Xcode 版本
# CI_PLATFORM              - 目标平台
# CI_ARCHIVE_PATH          - 归档文件路径
# CI_DERIVED_DATA_PATH     - DerivedData 路径
# CI_RESULT                - 构建结果(success/failure)
# CI_WORKFLOW              - workflow 名称

最佳实践

  • 把非关键步骤的错误用 || true 吞掉,避免因为 lint 警告或通知发送失败导致整个构建标红
  • 在脚本开头加 set -euo pipefail 可以让脚本遇到未定义变量或管道错误时立刻失败,避免静默出错
  • 敏感信息(API Key、token)始终通过 Xcode Cloud 的 Secure Environment Variables 配置,不要写在代码里
  • 测试脚本时可以先在本地模拟 Xcode Cloud 的环境变量,手动设置 CI_* 变量后执行脚本验证

还有什么值得关注

  • Xcode Cloud 的 macOS 环境预装了 Homebrew 和常用工具,不需要每次在脚本里从头安装
  • 脚本的超时时间有限制,如果你的依赖安装特别耗时,考虑用 SPM 替代 CocoaPods 以减少构建时间
  • 构建日志中会显示脚本的 stdout 和 stderr 输出,利用 echo 做好日志标记方便排查问题
WWDC 2021