mcpField
S
Shared SwiftUI App Workflow

Shared SwiftUI App Workflow

github.com/mosif16开发1837 次安装48 周前更新
代码仓库

关于 Shared SwiftUI App Workflow

介绍如何构建、测试并分发适用于 iOS 和 macOS 的 SwiftUI 应用,也涵盖可选的 Catalyst。内容包括共享项目设置、架构选择、调试、自动化测试、CI/CD 和 TestFlight 发布。

主要功能

  1. 01设置共享的 iOS 和 macOS 项目
  2. 02使用 SPM 或 CocoaPods 管理依赖
  3. 03采用 MVVM 或 TCA 组织应用
  4. 04使用 Xcode 工具调试和分析性能
  5. 05规划单元测试与 UI 测试
  6. 06配置 CI/CD 和 TestFlight 发布

适用场景

  1. 01启动适用于 iOS 和 macOS 的 SwiftUI 应用
  2. 02为应用项目选择架构
  3. 03排查 UI 或性能问题
  4. 04准备测试和应用分发

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mosif16/codex-skills --skill shared-swiftui-app-workflow

安装后在 Claude Code 中输入/shared-swiftui-app-workflow确认已加载。

详细介绍

说明

  • 概述: 此工作流概述了构建、测试和部署面向 iOS 和 macOS(可选支持 Catalyst)的 SwiftUI 应用的最佳实践。内容涵盖项目设置、架构选择、开发实践和持续交付步骤。
  • 前提条件: 请确保已安装最新版 Xcode(Xcode 15 或更高版本),并已加入 Apple Developer Program(代码签名、Xcode Cloud 和 TestFlight 均需要)。默认你熟悉 SwiftUI、Git 源代码管理以及 iOS/macOS 应用开发基础知识。
  • 用法: 按顺序执行以下步骤,配置多平台 Xcode 项目、管理依赖项、实现架构(MVVM 或 TCA)、高效调试和性能分析、设置 CI/CD 流水线,最后通过 TestFlight 分发应用。
  • 约定: 本指南使用粗体标题标示关键操作,并用斜体标示工具名称或概念。应用这些步骤时,请将示例占位符(如包标识符或方案名称)替换为适合你项目的值。

工作流

  1. 创建多平台 Xcode 项目: 首先创建一个同时支持 iOS 和 macOS 目标的 Xcode 项目。Xcode 14+ 提供了多平台 App模板,可创建一个使用 SwiftUI 构建 iOS(及 iPadOS)和 macOS 应用的统一目标。此统一目标可在各平台间共享大部分代码和资源。如果你更倾向于使用单独的目标,也可以先创建 iOS 应用,再添加 macOS 目标(或为 iOS 目标启用 Mac Catalyst)。确保将共享代码(如 SwiftUI 视图和模型)归入跨平台组,并对任何平台专属代码使用平台检查(#if os(iOS)、#if os(macOS))。通过将项目构建为共享代码库,你可以尽可能减少重复,同时仍可根据需要为每种设备类型定制 UI。

  2. 设置目标、方案和配置: 对于多平台项目,Xcode 可能已包含 Debug 和 Release 的单独配置。你也可以根据需要添加自定义构建配置(例如 Staging 或 QA)。如果使用单独的目标(用于 Catalyst 或不同环境版本),请为每个目标设置唯一的包标识符和 Info.plist。例如,macOS 目标的包 ID 可添加 ".mac" 后缀,开发版本可添加 ".dev" 后缀。为每个 App 目标或环境创建对应的方案,以便轻松运行和归档各个版本。将方案标记为“Shared”,以便纳入源代码管理(这对团队协作和 CI 很重要)。这种多目标设置让你可以在一个项目中同时拥有 iOS 应用、原生 macOS 应用,甚至 Catalyst 应用,并为每个应用设置自己的方案和包 ID。

  3. 配置环境设置: 使用 Xcode 的构建配置选项管理特定环境的设置。例如,你可以定义自定义XCConfig文件,或使用用户定义的构建设置来配置 API 端点或功能标志等值。在 Info.plist 中定义引用这些设置的键。例如,在 Info.plist 中添加 BaseURL 键,并将其值设为 $(BASE_URL),再按配置设置该值。在 Build Settings 中,为每个配置(例如 Dev、QA、Prod)创建一个用户定义变量 BASE_URL,并分别指向相应的 URL。应用可以在运行时读取这些值,例如:

    let apiURL = Bundle.main.object(forInfoDictionaryKey: "BaseURL") as? String 这样可以避免将环境值硬编码。此外,还可以考虑使用编译器标志来编写条件代码。你可以在每种配置的构建设置中添加 Swift 标志,例如 -DDEVELOPMENT 或 -DPRODUCTION。然后在 Swift 代码中使用 #if DEVELOPMENT,加入仅用于调试的逻辑,或使用占位内容进行测试。通过这种方式,可在构建时隔离不同配置之间的差异。最后,如果需要,确保每个应用目标使用不同的应用图标和名称(例如,为开发构建的应用名称添加后缀“Dev”)——你可以通过 Info.plist 或各目标对应的 Asset catalogs 进行设置。

  4. 管理依赖项(SPM 和 CocoaPods): 使用 Swift Package Manager (SPM) 作为添加库和框架的首选工具。SPM 内置于 Xcode 中,能为 SwiftUI 项目提供无缝的依赖项管理体验。要添加软件包,请前往 File ▸ Add Packages... 并输入软件包的 Git URL。将依赖项添加到你的应用目标(而不是任何由 CocoaPods 生成的目标),以确保软件包正确集成。SPM 会自动获取并更新软件包,并将其保存在 Xcode 的沙盒中。请提交 Package.resolved 文件,以便团队成员和 CI 使用相同的版本。如果某个库无法通过 SPM 获取(或包含大量 Objective-C/旧版代码),可以集成 CocoaPods。初始化 Podfile(pod init)并指定 Pods,然后运行 pod install 生成 .xcworkspace。之后请始终在工作空间中继续开发。你可以在一个项目中混用 SPM 和 CocoaPods——只需确保添加 SPM 软件包时,在添加对话框中选择主项目(而不是 Pods 项目)。按需使用 pod update 更新 Pod 依赖项。通常,纯 Swift 依赖项优先使用 SPM,因为它原生支持 Xcode 且易于使用;仅在特殊情况下使用 CocoaPods。请在 README 中清晰记录第三方软件包。

  5. 应用架构模式(MVVM 或 TCA): 使用稳健的架构组织 SwiftUI 代码,以管理复杂性。一个流行的选择是 MVVM(Model-View-ViewModel),它 与 SwiftUI 的数据绑定机制天然契合。在 MVVM 中,定义数据 模型来表示应用数据,使用 SwiftUI 视图构建 UI,并创建 ViewModel 类(遵循 ObservableObject),以处理业务逻辑和 状态。例如,GameViewModel 可以发布一个 @Published var score,并提供用于更新 分数的方法。对应的 GameView 使用 @StateObject 或 @ObservedObject 观察 ViewModel 并更新 UI。这种 分离能让 SwiftUI 视图保持声明式且轻量,同时将逻辑放在 ViewModel 中 (便于测试)。对于较大的应用或更复杂的状态管理,可以考虑采用 The Composable Architecture(TCA)。TCA 是一个库(可通过 SPM 添加), 遵循单向数据流(受 Redux 启发)。你可以将应用拆分为 State、Actions 和 Reducers。Reducer 是一个纯函数,接收当前 State 和一个 Action,并生成新的 State(也可以产生称为 Effects 的副作用)。Store 将 SwiftUI 视图与状态和业务逻辑连接起来:视图发送 Actions(例如按钮点击), Store 接收这些 Actions 并传递给 Reducer,更新后的 State 随后流回视图。TCA 鼓励采用高度模块化的结构:你可以将小型功能组合成更大型的功能,并且 它提供了以受控方式管理依赖和副作用的工具。虽然 TCA 有一定的学习曲线,但它在 可测试性(可以轻松为 reducer 逻辑编写测试)和大型应用的可扩展性方面表现出色。根据 项目需求选择 MVVM(更简单,使用 SwiftUI 内置的响应式状态功能)或 TCA(结构更严谨, 适合复杂应用)——两者都有助于在代码中保持清晰的关注点分离。

  6. 调试和性能分析实践: 在开发过程中,使用 Xcode 强大的调试工具及早发现并修复问题。通过 点击行号旁的代码栏,在代码中设置 断点,以暂停执行并检查运行时变量。暂停期间,可以使用 LLDB 控制台(po 命令)打印值或调用函数,以验证状态。这对检查 ViewModel 或 TCA reducer 中的逻辑 非常有用,可确保数据流正确。对于 SwiftUI 视图,视图层级调试器尤其 实用:在 Simulator 中运行应用,然后选择 Debug ▸ View Debugging ▸ Capture View Hierarchy。这可以让你在暂停后检查 UI 布局,从而找出视图未显示或位置不正确的原因。此外,还可以使用 Instruments 进行 性能分析。Xcode 的 Instruments 应用提供了多种模板,例如 Time Profiler(用于测量 CPU 性能并查找运行缓慢的函数)和 Leaks (用于检测内存泄漏和循环引用)。例如,如果 SwiftUI 视图响应迟缓,可以在与视图交互时运行 Time Profiler, 以找出开销较大的计算。Xcode 15+ 中的 SwiftUI 还包含专用的“SwiftUI”动画和渲染时间线 工具,可用于分析 UI 性能。也要定期在 Release 模式下测试和进行性能分析,因为 SwiftUI 的性能可能 会因 Debug 和 Release 构建而异。可以使用 os_log 或 print 语句进行轻量级调试,尤其适合跟踪执行路径或数据变化(请确保在生产环境中移除或禁用过多的日志)。 在整个开发过程中定期调试和进行性能分析,有助于确保应用运行流畅,并在发布前发现错误。

  7. 编写单元测试和 UI 测试: 设置自动化测试,以确保代码质量。创建项目时,Xcode 可以生成单元测试目标和 UI 测试目标(如果没有,也可以通过 File ▸ New ▸ Target 手动添加)。单元测试(使用 XCTest 框架)应覆盖核心业务逻辑。对于 MVVM,应独立于 UI 测试 ViewModel 方法和状态变化。对于 TCA,可以利用 TCA 测试工具向 reducer 发送操作,并断言状态变化或效果输出。尽量测试边缘情况和错误条件(例如,网络调用失败时,ViewModel 应呈现错误状态)。UI 测试使用 Xcode 的 UI 测试框架(基于 XCTest)启动应用并模拟用户交互。你可以在模拟器中与应用交互,录制 UI 测试脚本,自动生成点击和滑动的代码;也可以手动编写,以获得更多控制。UI 测试应重点覆盖关键流程,例如新手引导或购买流程——这些流程必须万无一失。使用断言验证预期元素是否出现,或是否成功导航到指定屏幕。将测试分组整理,并为测试方法取描述性名称。使用不同配置运行测试也很有帮助(Xcode 的 Test Plans 可以在多个方案或环境中运行测试套件)。通过自动化测试,你可以快速发现回归问题,并确保新更改不会破坏现有功能。开发期间请定期运行测试套件,并务必将测试执行纳入 CI 流水线。

  8. 使用 Xcode Cloud 持续集成: 为简化构建和测试,如果你将代码托管在受支持的 Git 仓库(GitHub、Bitbucket、GitLab 等)中,请设置 Xcode Cloud。Xcode Cloud 是 Apple 集成的 CI 服务,可以在 Apple 的服务器上自动构建应用。要进行配置,请在 Xcode 中打开项目,前往 Xcode Cloud 设置(位于 Report Navigator 中,或通过 Product ▸ Xcode Cloud 进入)并启用新工作流。选择仓库分支(例如 main),并选择 build、analyze、test 和 archive 等操作。你可以指定触发条件——例如,每次推送时运行,或仅在拉取请求时运行。Xcode Cloud 会通过关联你的 Apple Developer 账户来处理配置;如果使用自动签名,它可以无缝管理云构建所需的证书和描述文件。将需要构建和测试的所有方案添加到工作流中(例如,同时添加 iOS 和 macOS 应用方案及测试目标)。Xcode Cloud 提供简单的网页界面(也可在 Xcode 中查看),用于监控构建状态和查看日志或测试结果。你还可以将其配置为自动把成功的构建分发到 TestFlight(参见第 10 步)。Xcode Cloud 的一大优势是深度集成:它使用与本地 Xcode 相同的环境,并可在多台设备上并行运行测试。请留意 Xcode Cloud 分钟数的使用情况(Apple 提供一定的免费额度,但使用量较大时可能需要订阅)。对于团队项目,Xcode Cloud 可确保持续验证每个人的更改。只要项目配置得当,它就是 Apple 平台应用一个省心省力的 CI 服务。

  9. 使用 GitHub Actions 持续集成: 除了 Xcode Cloud,或者与之搭配使用,你还可以使用 GitHub Actions 设置 CI/CD,获得更多自定义选项。在仓库中创建工作流 YAML(例如 .github/workflows/ci.yml)。使用 macOS 运行器(例如 runs-on: macos-latest)构建 iOS/macOS 应用。典型的作业会安装依赖项、构建应用、运行测试并归档应用构件。例如,添加用于检出代码(actions/checkout)、设置所需 Ruby 或 Node 环境(如果使用 Fastlane 或 CocoaPods 等工具),然后运行 Xcode 构建命令的步骤。你可以在命令行模式下使用 xcodebuild 进行构建和测试:

    • name: Build and Test (iOS) run: xcodebuild -workspace YourApp.xcworkspace -scheme "YourApp-iOS" -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14' clean test

上述示例命令会构建 iOS 方案并在模拟器上运行测试。类似地,你也可以通过指定方案和 Mac 作为目标来构建 macOS 方案。如果使用 CocoaPods,请记得在构建前运行 pod install。如有需要,可保存构建构件(Xcode 会生成 .xcarchive 归档,你可以为 iOS 导出 .ipa)。你可以使用 GitHub Secrets 存储分发签名证书(Base64 编码的 .p12 文件)和配置描述文件,以及 App Store Connect API 密钥或专用应用密码。然后添加一个步骤,将证书安装到 Keychain,并设置用于签名的环境变量。许多团队会将 Fastlane 集成到 GitHub Actions 中,以简化代码签名和上传流程。例如,构建完成后,调用 fastlane deliver 或自定义 lane 上传到 TestFlight(Fastlane 可以使用 App Store Connect 的 API 密钥进行身份验证)。也有一些社区 GitHub Actions(例如 apple-actions/app-store-connect)可用于将二进制文件上传到 TestFlight。确保工作流在拉取请求和合并到 main 时运行,以验证每项更改。借助 GitHub Actions,你可以完全掌控工作流,添加其他检查(如 lint、SwiftLint 等),或按设备和操作系统版本矩阵并行执行任务。如果你倾向于将 CI 配置作为代码存储在仓库中,它是 Xcode Cloud 灵活的补充或替代方案。

  1. **管理代码签名和配置描述文件:**在设备上运行和通过 TestFlight/App Store 分发都需要代码签名。 在开发过程中,可以为每个目标启用 Xcode 的自动签名——这会将项目关联到你的 Apple Developer Team,并为 Debug 和 Release 构建创建必要的证书和配置描述文件。 确保每个 App 目标的 Signing & Capabilities 中都选择了团队,并且拥有唯一的 Bundle ID。 分发到 TestFlight/App Store 时,每个 App 目标都需要一个 iOS Distribution certificate 和一个 App Store provisioning profile。 如果启用了自动签名,并且项目的归档构建设置为“Any iOS Device”(适用于 iOS)或“Any Mac”(适用于 Mac App),Xcode 可以创建这些文件。 如果在 Xcode 之外使用 CI(例如 GitHub Actions),则需要提供签名材料:将 Distribution 证书导出为 .p12 文件,并从 Apple Developer 门户下载配置描述文件(.mobileprovision)。 将这些文件安全存储(例如存入 CI 中的环境机密或钥匙串),并在构建期间通过脚本或 Fastlane 导入。 推荐使用 Fastlane Match 或 codemagic/xcodesign,以安全、自动化的方式管理签名身份。 如果计划通过 API 上传构建版本(CI 工具和 Fastlane 会使用此方式),还需生成 App Store Connect API Key(在 App Store Connect > Users and Access > Keys 中)。 妥善保管 Key ID、Issuer ID 和私钥文件;这些信息可让 CI 无需 Apple ID 凭据即可向 App Store Connect 进行身份验证。 总之,应尽早设置签名,并在本地测试能否归档和导出 App。 这样,CI 执行相同操作时,流程才能顺利进行。 确保本地和 CI 环境中的 Bundle ID、配置描述文件和 Entitlements 保持一致,这一点至关重要。

  2. **部署到 TestFlight:**获得已签名的归档构建(一个 .xcarchive)后,下一步是将其分发给测试人员。 TestFlight 是集成在 App Store Connect 中的 Apple Beta 分发平台。 如果在本地使用 Xcode,请依次选择 Product ▸ Archive,然后在 Organizer 中选择 Distribute App → App Store Connect → Upload。 Xcode 会负责上传到 TestFlight(每次上传都需要递增 App 版本号或构建号)。 对于基于 CI 的上传,可使用 Xcode 命令行工具或 Fastlane。 使用 Xcode 命令行时,归档后可通过 xcodebuild -exportArchive(并提供导出选项 plist)导出 IPA,然后使用 Apple 的 altool 或较新的 Transporter CLI 上传。 Fastlane 可通过 fastlane pilot(用于 TestFlight)或 fastlane upload_to_testflight 简化这一流程。 在 Xcode Cloud 中,启用工作流中的“Upload to TestFlight”操作后,云端构建成功时会自动将归档上传到 App Store Connect。 上传后,App Store Connect 会处理构建版本(可能需要几分钟)。 随后,你可以登录 App Store Connect 管理测试人员,并将构建版本发送给内部或外部测试人员组。 最好为测试人员注明构建版本包含的变更(TestFlight 发行说明)。 使用 CI/CD 时,可以选择将每次提交都部署到内部 TestFlight 组,以便快速迭代;然后再将特定构建版本推广给外部测试人员或提交至 App Store。 最后,务必留意 TestFlight 构建版本是否被 Apple 标记为存在任何 严重问题(例如崩溃或缺少合规信息)——如果需要处理问题,你会在 App Store Connect 收到通知。 构建版本通过测试并确认无误后,即可用于提交 App Store 审核。

示例

  • GitHub Actions CI 工作流(节选): 以下是 iOS 应用的 GitHub Actions 工作流文件简化示例,其中包含安装依赖项、构建、测试和上传 TestFlight 构建版本的步骤。它展示了如何在 CI 中使用 Xcode 命令行工具和 Fastlane:

    name: CI-iOS-TestFlight on: push: branches: [ main ] jobs: build-test-deploy: runs-on: macos-latest steps: - name: 检出代码 uses: actions/checkout@v3

        - name: 安装 CocoaPods 依赖项
          run: pod install
          continue-on-error: true  # 仅在使用 CocoaPods 时
    
        - name: 构建并运行单元测试(iOS)
          run: xcodebuild clean test -workspace YourApp.xcworkspace -scheme "YourApp-iOS" -sdk iphonesimulator -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 14,OS=latest'
    
        - name: 归档应用以供分发
          run: xcodebuild clean archive -workspace YourApp.xcworkspace -scheme "YourApp-iOS" -configuration Release -destination 'generic/platform=iOS' -archivePath ${{ github.workspace }}/YourApp.xcarchive
    
        - name: 从归档导出 .ipa
          run: xcodebuild -exportArchive -archivePath ${{ github.workspace }}/YourApp.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath ${{ github.workspace }}/build
    
        - name: 安装 Fastlane
          run: gem install fastlane
    
        - name: 上传到 TestFlight
          env:
            APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
            APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
            APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_KEY }}
          run: fastlane pilot upload -u ${{ secrets.APP_STORE_CONNECT_EMAIL }} -ipa ${{ github.workspace }}/build/YourApp.ipa --api_key_path ./ApiKeyFile.p8
    

在此 YAML 文件中,工作流会在向 main 分支推送时触发。它会检出代码库、安装 Pods(如果适用),然后在 iOS 模拟器上构建并测试应用。接着,它会归档应用,并使用 ExportOptions.plist 导出 IPA(该文件会指定 method "app-store" 和配置描述文件)。最后,它会使用存储在 GitHub Secrets 中的 App Store Connect API 密钥凭据,通过 Fastlane Pilot 将 IPA 上传到 TestFlight。此示例可以扩展,添加用于 Mac 构建、代码 lint 检查等的其他作业或步骤,也展示了 CI 如何全面自动化构建和部署流程。

  • MVVM ViewModel 示例(SwiftUI): 以下是一个简短示例,展示了遵循 MVVM 模式的 SwiftUI 视图和 ViewModel。它展示了视图模型如何驱动 UI 状态并处理逻辑,之后可以独立于视图进行单元测试:

    import SwiftUI import Combine

    // Model struct Game { var score: Int }

    // ViewModel class GameViewModel: ObservableObject { @Published var game: Game private var cancellables = Set()

      init(game: Game = Game(score: 0)) {
          self.game = game
      }
    
      func increaseScore() {
          game.score += 1
      }
    
      func resetScore() {
          game.score = 0
      }
    

    }

    // View struct GameView: View { @StateObject private var viewModel = GameViewModel()

      var body: some View {
          VStack {
              Text("Score: \(viewModel.game.score)")
                  .font(.largeTitle)
              HStack {
                  Button("Increase") {
                      viewModel.increaseScore()
                  }
                  Button("Reset") {
                      viewModel.resetScore()
                  }
              }
          }
          .padding()
      }
    

    } 在此示例中,GameViewModel 是一个管理状态(Game 模型)的 ObservableObject。SwiftUI 的 GameView 使用 @StateObject 实例化并观察 ViewModel。点击 “Increase” 按钮会调用 ViewModel 方法来更新分数;得益于 @Published,视图会自动反映更改。这种架构将 UI 与逻辑清晰地分离开来:我们可以为 GameViewModel.increaseScore() 和 resetScore() 编写单元测试,确保它们行为正确,而完全不涉及 SwiftUI。视图只需根据当前状态进行渲染。这种模式可以扩展到每个屏幕或组件都有对应的 ViewModel(以及可能存在的服务/模型层),从而让应用更易于维护和测试。

参考资料

  • Apple Developer Documentation -- **Multiplatform Apps:**关于如何为 iOS 和 macOS 配置单个 Xcode 目标,以及如何在平台之间共享代码的指南。
  • Apple Developer Documentation -- **Xcode Cloud:**介绍如何设置 Xcode Cloud 工作流,以持续集成和交付应用(通过 TestFlight 构建、测试和部署)。
  • Apple Developer Documentation -- **TestFlight Distribution:**介绍如何通过 Xcode 或 CI 工具对应用进行归档并将构建上传到 TestFlight。
  • **Pointfree (Composable Architecture):**The Composable Architecture (TCA) 库的官方 GitHub 仓库和文档,其中包括将其集成到 SwiftUI 项目中的指南。
  • **XCTest Framework Reference:**Apple 提供的 XCTest 单元测试和 UI 测试编写参考,包括使用 XCTAssert 函数和记录 UI 测试。
  • **Fastlane Documentation:**介绍如何使用 Fastlane 工具(match、pilot 等)自动执行代码签名和 TestFlight 部署,适用于在 Xcode Cloud 之外设置 CI/CD 流水线。

评论

支持 Markdown