Gitea Actions 可以构建 iOS 应用,但只能在您注册的 Mac 上,因为 Gitea 没有托管的运行器,Xcode 只能在 macOS 上运行。两种实用的设置是 Mac 运行在主机模式下,或者是正常的 Linux 运行器,发送 iOS 构建到云构建服务。这篇指南将指导您完成两种设置,包括一个 __CAPGO_KEEP_0__ 应用,带有您可以将工作流文件直接拖放到 Gitea Actions 中的工作流文件。 act_runner 团队选择 Gitea 是因为他们希望在他们控制的基础设施上托管他们的 Capacitor。这应该不会因为应用需要 Xcode 就改变。以下的两种设置都可以让您在服务器上保留源代码。 .gitea/workflows/.
Teams pick Gitea because they want their code on infrastructure they control. That should not change just because the app needs Xcode. Both setups below keep your source on your server.
How Gitea Actions 运行作业
Gitea Actions 使用一个 GitHub Actions 兼容的语法,作业在您注册的 Gitea 服务器上运行的实例上运行。 act_runner Gitea Actions 使用的实例标签如下: ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest实例标签后面的部分决定了作业如何运行:
docker://image在 Linux 运行器中,默认使用容器运行作业。host在机器上直接运行作业,机器上安装的所有内容都将被使用。
macOS 不能在 Docker 容器中运行,因此 Mac 运行器必须使用一个标签。这个标签的后果我们将在后面讨论。 host 在您从 __CAPGO_KEEP_0__ 复制工作流程之前,注意以下两点:
Two compatibility notes before you copy a workflow from GitHub:
- 并在第一个文件夹不存在时回退到
.gitea/workflows/当第一个文件夹不存在时,Gitea 读取.github/workflows/并回退到 uses: actions/checkout@v4因为 Gitea 默认从 GitHub 解析动作 (设置)DEFAULT_ACTIONS_URL空中断网实例需要镜像使用的动作并通过完整 URL 来引用它们。
选项 1:使用 act_runner 的 Mac 运行器
注册 Mac
下载 macOS (arm64) 二进制文件(适用于 Apple Silicon) act_runner 从 Gitea 发布页面下载二进制文件,然后从 站点管理 > 动作 > 运行器 (实例范围)或从组织或仓库设置中获取注册令牌。
./act_runner register --no-interactive \
--instance https://gitea.example.com \
--token <registration_token> \
--name mac-mini-01 \
--labels macos-arm64:host
./act_runner daemon
以特定用户身份以启动代理的方式运行守护进程,以便在重启后重新启动并拥有自己的登录密钥链。
在宿主上安装工具链
宿主模式意味着该作业使用 Mac 自身的工具。安装:
- Xcode 26(自 2026 年 4 月 28 日起,App Store Connect 上传所需)并运行
sudo xcodebuild -license accept - Node.js 22 或更高版本和 Bun (Capacitor 8 需要 Node 22)
- Ruby 和 fastlane,或者使用
Gemfile使用bundle exec - CocoaPods,只有当您的 iOS 项目仍然使用它时。新 Capacitor 8 项目使用 Swift Package Manager。
工作流程
# .gitea/workflows/ios-mac.yaml
name: iOS release (Mac runner)
on:
push:
tags:
- 'v*'
jobs:
ios:
runs-on: macos-arm64
env:
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APP_STORE_CONNECT_TEAM_ID: ${{ vars.APP_STORE_CONNECT_TEAM_ID }}
PROFILE_NAME: ${{ vars.IOS_PROFILE_NAME }}
steps:
- uses: actions/checkout@v4
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ios
- name: Decode signing files
run: |
echo "${{ secrets.IOS_CERTIFICATE_BASE64 }}" | base64 --decode > dist.p12
echo "${{ secrets.IOS_PROFILE_BASE64 }}" | base64 --decode > profile.mobileprovision
- run: bundle exec fastlane ios beta
- name: Clean up
if: always()
run: rm -f dist.p12 profile.mobileprovision
The beta lane 将证书导入临时密钥链,切换项目到手动签名,升级 TestFlight 中的构建号,打包,上传。一个完整的 Fastfile 对于一个 Capacitor 项目在 使用 Bitbucket Pipelines 构建和部署 iOS 应用;它在 Gitea 上无需修改。有关 fastlane 背景,请参阅 GitHub Actions iOS 指南.
主机模式的成本
The act_runner 文档中有明确说明:主机任务并非隔离。实际上:
- 每个任务共享相同的用户、磁盘和钥匙链。一个任务在途中死亡可能会留下一个临时钥匙链或一个过期的分发配置文件,从而破坏下一个任务。
- 任何针对标签的工作流程都会在该 Mac 上使用该用户的访问权限运行 code。只需为您信任的仓库注册主机运行器,并避免在从分支的拉取请求中运行它们。
- DerivedData、存档和模拟器运行时会持续增长直到磁盘满载。
- Xcode 升级由您负责,苹果每年都会提高最低 SDK。
- 一台 Mac 只能同时构建一个任务。发布日排队。
如果您的团队已经拥有 Mac,并且有人负责管理它们,这个选项就有效。如果没有,那么下一个选项会从您的基础设施中移除 Mac。
选项 2:使用 Capgo Build 在 Linux 运行器上构建 iOS
Capgo 构建 编译并签名 Capacitor 应用程序在 Capgo 管理的 Mac 上。您的 Gitea 任务将保持在您已经有的 Linux 运行器上。它检查出 code,构建 web 层,运行 cap sync ios,并调用 build request。Capgo CLI 将准备好的本机项目上传,流式传输 Xcode 日志回 Gitea 任务日志,并在失败时退出非零值。
本模型适合自托管的Gitea:
- 无入站访问。 Capgo不会克隆您的仓库。您的运行器通过HTTPS将准备好的项目推送到服务器,因此位于防火墙或VPN后面的Gitea服务器无需进行任何更改。
- 无仓库令牌。 在Capgo侧没有Git连接需要配置。
- 您的Web源代码仍在家中。 仅上传本机
ios/文件夹、Capacitor配置和插件的本机部分。src/,.git/,.env文件不会。
一次性设置
在开发机器上:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest app add
bunx @capgo/cli@latest build init --platform ios
build init 创建或重用您的分发证书和App Store配置文件,并存储App Store Connect API密钥。运行一次本地构建以确认一切签名:
bun run build && bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
然后导出凭据:
bunx @capgo/cli@latest build credentials manage --appId com.example.app --platform ios
# select "Export to .env"
添加Gitea机密
打开 仓库设置>动作>机密 并添加每个密钥从导出的文件中,plus您的Capgo API密钥:
| 机密 | 目的 |
|---|---|
CAPGO_TOKEN |
Capgo API 具有上传权限的密钥 |
BUILD_CERTIFICATE_BASE64 |
页面/区域:Capgo营销网站。角色:短UI标签或导航项。消息键`subprocessors_table_purpose`(子处理程序表目的)。.p12) |
P12_PASSWORD |
__CAPGO_KEEP_0__ __CAPGO_KEEP_1__密钥具有上传权限 |
CAPGO_IOS_PROVISIONING_MAP_BASE64 |
分发证书(( |
APPLE_KEY_ID |
App Store Connect API 密钥 ID |
APPLE_ISSUER_ID |
App Store Connect 发行者 ID |
APPLE_KEY_CONTENT |
Base64 .p8 密钥 |
APP_STORE_CONNECT_TEAM_ID |
Apple 团队 ID |
Gitea 拒绝以 secret 和变量名开头的名称 GITEA_ 或 GITHUB_因此,请保留这些名称不变。将非密钥值,如应用 ID,放在 变量 并使用 ${{ vars.NAME }}读取它们。组织级别设置的密钥将被每个仓库共享,这对于从同一个 Apple 团队发布多个应用非常方便。删除导出的文件完成后。
根据标签推送发布
# .gitea/workflows/ios-release.yaml
name: iOS release
on:
push:
tags:
- 'v*'
jobs:
release-ios:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ios
- name: Build, sign, and upload to TestFlight
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
CAPGO_IOS_PROVISIONING_MAP_BASE64: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
run: |
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} \
--platform ios \
--build-mode release \
--ios-distribution app_store \
--store-release-name "${{ gitea.ref_name }}"
注意:
${{ gitea.ref_name }}是标签名称。github.*上下文也可以作为别名,帮助在迁移工作流时- Gitea 在每个作业中设置
CI=trueCapgo CLI 从不等待交互输入。 - Capgo 从最新的 TestFlight 构建中递增构建号,因此两次标签不会冲突。
- 没有
--submit-to-store-review,构建将在 TestFlight 中停留。添加标志以便 CI 提交 App Review。
现在是 git tag v2.3.0 && git push origin v2.3.0。任何可以推送标签的人都可以发布,因此添加一个保护标签规则以限制 v* 的权限 v* under 设置 > 标签 并将其限制为发布经理。
测试者专用
对于直接安装在已注册设备上的QA构建,构建为测试者模式并获取下载链接:
# .gitea/workflows/ios-adhoc.yaml
name: iOS ad hoc build
on:
workflow_dispatch:
jobs:
adhoc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile && bun run build
- run: bunx cap sync ios
- name: Ad hoc build
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
run: |
echo "${{ secrets.ADHOC_PROFILE_BASE64 }}" | base64 --decode > adhoc.mobileprovision
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} \
--platform ios \
--ios-distribution ad_hoc \
--ios-provisioning-profile ./adhoc.mobileprovision \
--output-upload --output-retention 3d \
--output-record /tmp/build.json
bunx @capgo/cli@latest build last-output --path /tmp/build.json --field outputUrl
测试者模式构建需要一个列出测试设备的测试者配置文件。将该配置文件以base64编码的形式存储为一个密钥(ADHOC_PROFILE_BASE64 上面所述),在作业中解码它,并将其传递给 --ios-provisioning-profile。 CLI标志优先于环境变量,因此此构建仅覆盖App Store配置文件。使用 iOS UDID Finder收集UDIDs。对于大多数测试者,TestFlight内部测试更简单,因为它不需要UDIDs。
手动发布审批
GitHub允许您在环境中要求审批人。Gitea Actions不实现环境保护规则,因此命名环境的作业不会暂停等待审批。两种模式可以代替:
- 受保护的标签 只有发布经理才能推送
v*标签,标签工作流程将会运输。 - 构建,然后推广。 在每次推送时构建并推广到
main与--ios-distribution ad_hoc或上传到 TestFlight 内部测试仅限,随后使用一个workflow_dispatch可在当前 Gitea 发布版本中找到--submit-to-store-review.
(可用于重建已批准的提交)
大多数提交到Capacitor应用程序中只改变JavaScript、CSS和HTML。重新构建iOS会浪费分钟和App Review时间。使用Capacitor的Live Update功能可以实时更新应用程序。 大多数提交到 Capgo 应用程序仅改变 JavaScript、CSS 和 HTML。重建 iOS 将浪费分钟和 App Review 时间。使用__CAPGO_KEEP_0__ 实时更新
- name: Live update or native build
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
# plus the iOS signing secrets from above
run: |
if bunx @capgo/cli@latest build needed ${{ vars.APP_ID }} --channel production; then
bunx @capgo/cli@latest bundle upload ${{ vars.APP_ID }} --channel production
else
bunx cap sync ios
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} --platform ios --build-mode release
fi
build needed ,一个工作可以选择正确的路径: ios/ 或 capacitor.config.* 因为这些不是依赖项比较的一部分。请参见 自动选择 live update 或原生构建.
Mac 运行器与云构建
| act_runner 在您的 Mac 上 | Capgo 从 Linux 构建 | |
|---|---|---|
| 硬件 | 您购买并托管它 | 无 |
| Xcode 升级 | 手动,按机器 | 由 Capgo 处理 |
| 与工作流隔离 | 无主机模式 | 每个工作流都有一个新环境 |
| 并行构建 | 每台Mac | 从任何运行器中获取多个 |
| 签署文件 | Gitea 秘密中,Mac 解码 | Gitea 秘密中,发送每个构建 |
| 在防火墙后面工作 | 是 | 是,仅限出站HTTPS |
| 原生 Swift 应用 (无 Capacitor) | 是 | 没有,Capacitor应用 |
| 否,仅 __CAPGO_KEEP_0__ 应用 | 构建时间限制 | 自定 |
每次构建 10 分钟
| 故障排除 | 症状 |
|---|---|
| 修复 | 构建任务永远处于队列中 runs-on无在线运行器具有此标签。检查运行器列表和标签拼写。 |
uses: actions/checkout@v4 下载失败 |
运行器无法访问GitHub。请在Gitea中镜像该动作,并通过全URL引用它。 |
| 工作流程中的密钥值为空 | 名称以 GITEA_/GITHUB_或密钥定义在另一个仓库。 |
security: SecKeychainItemImport: MAC verification failed |
错误 .p12 密码,或者一个 .p12 由OpenSSL 3创建而没有 -legacy重新导出它。 |
No profiles for 'com.example.app' were found |
密钥值不匹配bundle ID或证书的配置文件。重新运行 build init 并重新导出。 |
| 拒绝上传SDK版本 | Mac 运行器仍然使用 Xcode 的旧版本(小于 26)。 |
cap sync ios 警告 Linux 上的 CocoaPods |
预期结果。Capgo 构建机器安装了 pods。 |
更多故障模式,请参见 CI/CD 的 Capacitor: 常见陷阱 和 Capgo 构建指南.
摘要
Gitea Actions 可以很好地处理 iOS, 只要你决定 Xcode 在哪里运行。使用主机模式的 Mac 运行器可以让你拥有完全的控制权和完全的责任。使用 Linux 任务调用 Capgo Build 可以保持 Gitea 的设置不变,不需要任何入站访问,并且可以将 TestFlight 发布转换为标签推送。无论你选择哪种方式,都要在 Gitea 秘密中保留签名材料,保护发布标签,并将 Web-only 更改作为实时更新发送,以便原生管道只有在必须时才运行。