GitHub Actions 云端编译详细配置教程( iOS 插件授权平台)

一篇讲透「后台一键云端编译」的原理、接入、排障的完整教程。跟着做约 20~30 分钟即可跑通。


一、背景:这套东西是什么

在运营 iOS 插件授权平台时,核心产物是一个已经注入授权验证代码的 dylib / deb 安装包。编译这类苹果生态的二进制,需要 macOS 环境——大多数站长手头只有一台 Linux 服务器(宝塔 + PHP),根本没法本地编译。

解决办法就是借用 GitHub Actions 的免费云端算力:平台后台把编译参数投递到你的 GitHub 仓库,由 GitHub 提供的 macOS 云机器完成编译,再把产物(deb / dylib)传回来供你下载分发。

整条链路涉及三个角色:

角色承担什么你需要准备什么
管理后台发起构建、跟踪进度、提供下载已部署的平台
GitHub 仓库存放编译工作流,执行云端编译一个仓库 + 一个令牌
GitHub Actions免费的 macOS 编译机器无需额外准备,仓库自带

二、它是干什么用的:解决三个真实痛点

  1. 没有 Mac 也能编译 iOS 产物 —— 编译发生在 GitHub 的 macOS 服务器上,你只需要一个浏览器。
  2. 参数化批量出包 —— 后台改一下参数(弹窗文案、主题色、授权策略),一键重新出包,不用手动改代码重编译。
  3. 产物管理闭环 —— 构建历史、成功/失败状态、产物下载、下载留痕,全部在后台完成,不散落在聊天记录里。

三、配置完成后你会实现什么

配置打通后,日常工作流变成这样:

  1. 在后台「应用管理」新建应用 → 自动生成 app_key
  2. 在「自定义参数」里按表单填写插件参数
  3. 在「云端构建」点一下「创建构建」
  4. 几分钟后,构建状态变绿 → 点「下载」拿到编译好的 deb / dylib
  5. 把包发给客户,配合卡密 / UDID 授权即刻可用

一句话总结:改参数 → 点按钮 → 下载成品包。


四、整体流程与三个硬性约定

┌─ 你的后台 ──────────────┐      ┌─ GitHub 仓库 ─────────────┐      ┌─ 回到后台 ───────────┐
│ 1. 应用管理建应用(app_key)│      │ 4. Actions 收到            │      │ 6. 每8秒轮询"读时对账" │
│ 2. 自定义参数填参数       │ ───▶ │    repository_dispatch    │ ───▶ │    状态→成功/失败      │
│ 3. 云端构建→创建构建      │      │ 5. 编译→上传 artifact      │      │ 7. 接口转发下载产物    │
└─────────────────────────┘      │    (命名: 前缀-runId)       │      └─────────────────────┘
                                 └───────────────────────────┘

后台与工作流之间靠三处严格对齐才能通信,配置前先记住:

#硬性约定不对齐的后果
1工作流顶层 name: 必须等于后台投递的 buildRef任务永远停在「已投递」
2on.repository_dispatch.types 必须等于后台「Dispatch 事件类型」GitHub 返回 204 看似成功,实际不运行
3artifact 名必须 = {产物前缀}-{runId}后台提示找不到产物

五、具体怎么用:六步实操

步骤 1:创建构建仓库

操作入口:登录 GitHub 后,页面右上角你的头像左侧有一个 「+」号按钮,点开菜单选第一项 New repository;如果找不到,直接在浏览器地址栏输入 github.com/new 也能到达同一页面。

逐项填写:

项目示例说明
Repository nameios-dylib自定义;这个名字要填进后台「构建仓库名」
可见性Public(推荐)后台「拉取契约」按钮走的是匿名 raw 地址,Private 仓库会返回 404;仓库里只放 CI 流水线和 JSON 契约,不含任何密钥,公开无风险
Add a README file✅ 勾上保证仓库非空,有默认分支

创建完成后确认三件事(都在仓库首页完成):

  1. 浏览器地址栏此时应为 github.com/你的用户名/ios-dylib——这两段名字就是后台字段 1(账号名)和字段 2(仓库名)的来源;
  2. 左上角分支下拉按钮显示的分支名(一般是 main)就是后台字段 3「触发分支」要填的内容;
  3. 页面中能看到 README 文件,说明仓库非空、创建成功。

若你坚持用 Private:后台「拉取契约」按钮会一直报 HTTP 404,跳过它即可——程序自带 resources/params.schema.json,构建功能不受影响。

步骤 2:创建 build.yml 工作流

  1. 回到仓库首页 → 点右上方的 Add file 按钮 → 选 Create new file
  2. 文件名输入框逐字输入:.github/workflows/build.yml——输入第一个 / 时 GitHub 会自动把前面的部分识别为目录,输入完应看到面包屑路径为 用户名 / 仓库名 / .github / workflows /,末尾是高亮的 build.yml
  3. 在下方代码编辑区整段粘贴下面的模板
  4. 拉到页面最底部点绿色 Commit changes 按钮,弹出确认框后保持默认选项 Commit directly to the main branch(不要选 “Create a new branch”),再点一次 Commit changes 即提交成功
# 顶层 name 就是本次 run 的名称。
# 后台轮询进度时按 buildRef 精确匹配 run.name,这一行绝对不能改!
name: ${{ github.event.client_payload.buildRef }}

# 触发方式:repository_dispatch
# types 必须与后台「Dispatch 事件类型」字段完全一致(默认 build-plugin)
on:
  repository_dispatch:
    types: [build-plugin]

permissions:
  contents: read

jobs:
  build:
    # 编译 iOS dylib 需要 macOS 环境
    runs-on: macos-latest

    steps:
      - name: 拉取仓库代码
        uses: actions/checkout@v4

      - name: 校验构建参数
        env:
          PARAMS: ${{ toJson(github.event.client_payload.params) }}
        run: |
          # 后台投递的 params 必须是 JSON 对象
          echo "$PARAMS" | jq -e 'type == "object"' >/dev/null \
            || { echo "::error::params 必须是 JSON 对象"; exit 1; }
          echo "$PARAMS" > build_params.json
          echo "参数校验通过:"
          jq . build_params.json

      - name: 编译插件
        run: |
          # ↓↓↓ 这里替换成你自己的编译/注入逻辑 ↓↓↓
          # 示例:用注入脚本把 app_key 与参数烧进 dylib 模板
          # python3 render.py build_params.json templates/AuthDylib_template.dylib
          mkdir -p out
          # cp build/*.dylib out/
          echo "在此处放置你的编译命令,产物放入 out/ 目录"

      - name: 上传产物
        uses: actions/upload-artifact@v4
        with:
          # 命名必须 = {前缀}-{runId},后端按这个名字精确反查!
          name: ${{ github.event.client_payload.artifactPrefix }}-${{ github.run_id }}
          path: out/*
          # 与后台产物保留时长(7天)保持一致
          retention-days: 7
          # 没产物时直接失败,避免"构建成功却下载不到包"的迷惑现象
          if-no-files-found: error

模板关键点逐条解释:

代码片段作用为什么必须这样写
顶层 name: ${{ ...buildRef }}定义本次运行的名称后台按 run.name === buildRef 精确反查进度,写死文字则永远查不到
types: [build-plugin]声明接受哪种 dispatch 事件必须与后台字段一字不差,否则事件石沉大海
jq -e 'type == "object"'校验参数是 JSON 对象拦截上游误传数组等脏数据,第一时间报清晰错误
runs-on: macos-latest指定 macOS 编译机编译 iOS 二进制必须 macOS
artifact name: 表达式产物命名后端按 {前缀}-{runId} 精确查找
if-no-files-found: error无产物即失败避免”绿灯但没包”的迷惑现象
retention-days: 7产物在 GitHub 保留 7 天与平台侧产物清理周期对齐

注意:「编译插件」步骤是占位符,需要替换为你自己的编译/注入脚本(例如用平台提供的 dylib 模板 + 注入脚本生成成品)。在替换之前发起的构建会在「上传产物」一步失败,这是预期行为,正好用来验证前四步连通性。

步骤 2.5:上传参数契约文件

后台的「拉取契约」和「资源体检」都依赖仓库里的 build/params.schema.json,仓库缺这个文件时点「拉取契约」会报 HTTP 404。

  1. 仓库首页 → Add file → Create new file
  2. 文件名输入:build/params.schema.json
  3. 内容来源:服务器上的 /www/wwwroot/你的项目/resources/params.schema.json(随程序自带,约 41 个字段的 JSON)
  4. 粘贴内容后拉到最底部 → Commit changes

该文件只声明「有哪些参数、类型与默认值是什么」,不含任何密钥,公开也无风险。 也可以不做这步——程序自带的契约副本已能正常工作,只是「拉取契约」按钮会报 404。

步骤 3:生成 Fine-grained Token

3.1 进入创建页并完成安全验证

GitHub → 右上角头像 → Settings → 左侧拉到底 → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token。

首次进入会弹出安全确认页(Confirm access,即 sudo 模式),这是 GitHub 在敏感操作前的本人校验,两种方式任选其一:

  • 手机装了 GitHub App 并已登录 → 点绿色按钮 Use GitHub Mobile,然后到手机 App 里点确认
  • 没装 App → 点下方 Having problems? 里的蓝色链接 Use your password,输入 GitHub 登录密码确认

验证通过后会自动回到创建 Token 的表单页。

3.2 填写 Token 表单

表单从上往下依次填写:

项目填什么说明
Token nameyzplus-build随意备注
ExpirationNo expiration 或 90 daysNo expiration 一劳永逸;90 days 更安全但要记得换。选 No expiration 时令牌保管好,泄露可在 GitHub 上随时 Delete 作废

3.3 限定仓库

继续往下拉到 Repository access 区块,三个单选项中选择第二个 Only select repositories(默认可能选中的是 “Public repositories” 或 “All repositories”,要改过来):

  1. 选中后下方出现 Select repositories 下拉框
  2. 点开下拉框 → 搜索并点选你的构建仓库(如 ios-dylib)
  3. 不要选 All repositories——权限最小化,令牌泄露时损失可控

3.4 设置权限(最容易错的一步)

继续往下拉到 Permissions 大区块,点开其中的 Repository permissions 分组,在这个分组里逐项找到下表的权限项并设置下拉框:

权限项下拉选漏配的后果
ActionsRead and write后台提示「可读不可写」,触发不了构建——最关键的一项
ContentsRead-only读不到仓库内容;若希望用 API/脚本把 params.schema.json 推送到仓库,需改成 Read and write
MetadataRead-only(自动)GitHub 必选项,不用动
其余全部No access保持不动

补充一:修改权限不会改变令牌值。在令牌页面点 Edit 改权限再 Update token,后台已保存的令牌继续有效,不用重新粘贴;只有「重新生成」才产生新令牌。 补充二:Token 有效期到了会直接 401,构建全线失败,到期前记得换。

3.5 生成与保存

拉到底点 Generate token → 页面显示 github_pat_ 开头的令牌 → 立刻点复制。

⚠️ 令牌只完整显示这一次,离开页面就再也看不到;丢了只能重新生成。

步骤 4:后台填写「构建接入配置」

登录后台 → 插件管理 → 构建接入配置,把 8 个字段填完(详见第七、八节)→ 保存配置。

步骤 5:验证连通

依次点页面上的验证按钮:

  1. 测试连接 → 必须看到「连接正常,仓库可写」
  2. 拉取契约 → 从仓库拉取 build/params.schema.json 到服务器(仓库为 Private 或缺少该文件时会报 404,不影响使用)
  3. 资源体检 → 确认 dylib 模板等本地构建资源齐全

步骤 6:发起第一次构建

  1. 「应用管理」新建测试应用 → 「自定义参数」填参数(可先点「只校验」)
  2. 「云端构建」→ 创建构建 → 观察状态流转:已投递 → 排队 → 运行中 → ✅ 成功
  3. 成功后点「下载」,得到 {前缀}-{runId}.zip

进度原理是「读时对账」:前端每 8 秒调一次状态接口,后端顺手去 GitHub 查 run 进度——CI 侧无需配置回调地址,服务器无需挂计划任务,超时 30 分钟自动判失败。


六、以后其他平台怎么接入

这套约定与具体平台无关——任何能调 GitHub API 的系统都可以复用同一套构建仓库。接入只需实现三步 API 调用:

① 触发构建(repository_dispatch):

curl -X POST \
  -H "Authorization: Bearer github_pat_xxxx" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/OWNER/REPO/dispatches \
  -d '{
    "event_type": "build-plugin",
    "client_payload": {
      "buildRef": "b20260101xxxx",
      "artifactPrefix": "gzhmod",
      "params": { "app_key": "xxx", "popup_text": "授权弹窗文案" }
    }
  }'

返回 204 = 受理成功。

② 查询进度(按 run name 反查 buildRef):

curl -H "Authorization: Bearer github_pat_xxxx" \
  "https://api.github.com/repos/OWNER/REPO/actions/runs?event=repository_dispatch&per_page=50"

在返回的 workflow_runs[] 里找 name === buildRef 的记录,读 status / conclusion。

③ 下载产物(按 {前缀}-{runId} 精确匹配 artifact):

curl -H "Authorization: Bearer github_pat_xxxx" \
  "https://api.github.com/repos/OWNER/REPO/actions/runs/{run_id}/artifacts"
# 找到 name 匹配的 artifact 后:
curl -L -H "Authorization: Bearer github_pat_xxxx" \
  -o artifact.zip \
  "https://api.github.com/repos/OWNER/REPO/actions/artifacts/{artifact_id}/zip"

这就是为什么 build.yml 的三处约定不能改:它们是所有接入方共同遵守的「通信协议」。换后台系统、写小程序端、做自动化机器人,都走同一套契约。


七、配置所需字段一览

后台「构建接入配置」共 8 个字段:

#字段示例值必填
1GitHub 账号 / 组织名your-username✅
2构建仓库名ios-dylib✅
3触发分支main✅
4Workflow 文件名build.yml✅
5Dispatch 事件类型build-plugin✅
6产物名称前缀gzhmod可留默认
7GitHub Personal Access Tokengithub_pat_xxxx✅
8GitHub API 地址https://api.github.com可留默认

八、逐字段详细介绍

每个字段按「它是干什么的 → 在哪里找 → 怎么填 → 填错的典型表现」四段讲。

字段 1:GitHub 账号 / 组织名(owner)

  • 干什么的:标识构建仓库的归属者,与字段 2 拼出完整仓库路径 github.com/{owner}/{repo}。后端所有 API 调用的 URL 都由它俩拼出来。
  • 在哪里找:打开你的仓库页面,看浏览器地址栏 https://github.com/your-username/ios-dylib——斜杠前那段就是。也可以点自己头像看 Public profile 页显示的用户名。
  • 怎么填:直接填用户名。如果是组织仓库,填组织名。
  • 填错的表现:测试连接报 404 / 找不到仓库。注意大小写要与 GitHub 实际用户名一致。

字段 2:构建仓库名(repo)

  • 干什么的:与 owner 一起定位仓库;这个仓库里必须已放好本项目(含 .github/workflows/build.yml)。
  • 在哪里找:地址栏斜杠后那段。
  • 怎么填:只填仓库名,如 ios-dylib。不要带 https://、不带账号名、不带 .git 后缀。
  • 填错的表现:测试连接 404;或连到了别人的同名仓库。

字段 3:触发分支(branch)

  • 干什么的:告诉平台去哪个分支找 workflow 文件;查询构建进度时也按此分支过滤。
  • 在哪里找:仓库首页左上角的分支下拉按钮(显示 main ▾ 或 master ▾)。
  • 怎么填:下拉显示什么就填什么,一般 main。
  • 填错的表现:任务一直停在「已投递」——因为反查 run 时按分支过滤,永远查不到。这是新手最常见的卡点。

字段 4:Workflow 文件名(workflow)

  • 干什么的:指定触发 .github/workflows/ 目录下的哪个工作流文件。
  • 在哪里找:仓库里 .github/workflows/ 目录下的文件名。
  • 怎么填:只填文件名含后缀,如 build.yml;不带目录路径。
  • 填错的表现:不报错,但 dispatch 受理后没有任何工作流启动,任务永远「已投递」。改过文件名的(如 ios-build.yml)两边必须同步。

字段 5:Dispatch 事件类型(event_type)

  • 干什么的:repository_dispatch 的事件名,相当于「暗号」——工作流只响应与自己 types: 匹配的事件。
  • 在哪里找:build.yml 里的 on: repository_dispatch: types:。
  • 怎么填:默认 build-plugin,与教程模板一致即可;改了必须两边同步。
  • 填错的表现:最阴险的一个——GitHub 对 dispatch 返回 204(成功),后台显示「已投递」,但工作流根本不会启动。排查时先核对这个字段。

字段 6:产物名称前缀(artifact_prefix)

  • 干什么的:CI 产物 artifact 的命名前缀,最终产物名 = {前缀}-{runId}(如 gzhmod-17310948213)。后端按这个名字精确反查产物供你下载。
  • 在哪里找 / 怎么填:保持默认 gzhmod 即可。前缀会由后台在投递时自动传给 workflow(client_payload.artifactPrefix),模板已按此动态拼接,两边天然一致。
  • 填错的表现:后台提示找不到产物。只要 build.yml 用的是动态表达式(不是写死名字),改这里不需要动 workflow;但手动写死了 artifact 名就必须同步。

字段 7:GitHub Personal Access Token(token)

  • 干什么的:后台代替你操作 GitHub 的”钥匙”——触发构建(写)、查进度、拉契约、下载产物(读)全靠它。
  • 在哪里找:需要你手动生成:GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token。权限三件套:只勾构建仓库 + Actions Read and write + Contents Read-only。
  • 怎么填:粘贴完整令牌(github_pat_ 或 ghp_ 开头)。留空保存 = 不修改已保存的令牌(改其他字段时不用重贴)。
  • 填错的表现:401 Bad credentials(令牌错/过期/被删);「可读不可写」(Actions 权限只给了 Read)。注意 Fine-grained 令牌有有效期,到期前记得换。

字段 8:GitHub API 地址(api_base)

  • 干什么的:所有 GitHub API 请求的基地址。
  • 怎么填:公有 GitHub 留空/保持 https://api.github.com。两种情况才需要改:自建 GitHub Enterprise(填 https://你的域名/api/v3);国内访问 api.github.com 不稳定时换成反代地址。
  • 填错的表现:全部请求超时或 404。

九、常见故障排查

现象原因解决
任务一直停在「已投递」Workflow 文件名 / 触发分支 / 事件类型 三者之一不对逐个核对字段 3、4、5 与 build.yml
dispatch 成功但 Actions 页面没有 run事件类型不匹配或 Token 权限不足核对字段 5;确认 Actions 为 Read and write
「可读不可写」Token 的 Actions 权限只给了 Read重新生成或编辑 Token 权限
401 Bad credentialsToken 错误 / 过期 / 被删重新生成并更新后台
构建失败参数格式错误或仓库缺文件先「只校验」参数;去仓库 Actions 页看红叉日志
构建成功但没有产物编译步骤是占位符 / 产物没放进 out/看「上传产物」步骤是否报 No files were found
找不到产物artifact 命名不符合 {前缀}-{runId}检查 upload-artifact 的 name 表达式
拉取契约报 404仓库为 Private,或缺少 build/params.schema.json改 Public 或手动上传该文件;不影响构建

万能排查入口:打开仓库 → Actions 标签页。有 run 就看日志(哪一步红叉点开看详情);没 run 说明 dispatch 没送达(查事件类型与 Token 权限)。


十、安全建议

  1. 仓库可见性:想用后台「拉取契约」按钮,仓库必须是 Public(后端为匿名拉取 raw 地址)。若坚持 Private,跳过拉取契约——程序自带契约,功能不受影响
  2. 令牌权限最小化:只勾一个仓库;Actions 读写 + Contents 只读(无需 API 推送文件时);其余 No access
  3. 令牌即钥匙:不贴群、不进代码、不进截图;泄露立即在 GitHub 上 Delete 并重新生成
  4. 定期检查:Fine-grained tokens 列表页可随时查看/作废;后台「操作日志」有全部构建与下载留痕
  5. 产物 7 天自动清理,重要成品及时下载归档

附:速查卡片

后台字段                        ↔  build.yml
───────────────────────────────────────────────────────
Workflow 文件名   build.yml     ↔  .github/workflows/build.yml
Dispatch 事件类型 build-plugin  ↔  on.repository_dispatch.types
产物名称前缀       gzhmod        ↔  name: ${{ ...artifactPrefix }}-${{ github.run_id }}
触发分支           main          ↔  工作流所在分支
(自动投递 buildRef)             ↔  顶层 name: ${{ github.event.client_payload.buildRef }}

三步验证口诀:保存配置 → 测试连接(看”连接正常,仓库可写”)→ 发起一次测试构建(看状态变绿)。

完成以上配置,你就拥有了一条「改参数 → 点按钮 → 下载成品包」的全自动云端编译流水线。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容