一个原生 SwiftUI iOS 应用:登录 GitHub,浏览仓库的 Actions 运行记录与产物,用多线程分段并发下载大幅加速产物拉取。
GitHub 产物的下载流程是:
- 带 Token 请求
api.github.com/.../artifacts/{id}/zip - GitHub 返回 302 跳转到一个临时的 Azure Blob 签名地址
- 真正的文件从 Azure 服务器下载
ghproxy 等公开镜像无法携带你的 Token 去请求这个接口,所以全部失效。 本 App 在本机完成鉴权和跳转解析,拿到签名地址后直接对 Azure 地址做 HTTP Range 分段并发下载(类似 IDM/aria2 的多线程)。GitHub/Azure 对单连接有限速,多并发通常能提速 3–10 倍。
不限于自己的仓库:搜索 Tab 可以搜全站仓库,别人的公开仓库照样能进去下载产物 / 日志 / 正式版 / 源码;
也可以直接粘贴 owner/repo 或 GitHub 链接打开。
能加速下载的内容——GitHub 上能下载的,这里基本都能下:
| 类型 | 位置 | 说明 |
|---|---|---|
| 构建产物 | 仓库 → 构建 → 某次运行 | Actions Artifacts,主力场景 |
| 构建日志 | 仓库 → 构建 → 某次运行 | GitHub 打包好的 logs.zip |
| 正式版附件 | 仓库 → 正式版 → 某个 Release | Release Assets,含源码包 |
| 源码包 | 仓库 → 源码 / Release 页 | zipball / tarball,可选任意分支或 tag |
功能
- Personal Access Token 登录(Token 只存本机钥匙串,不上传任何服务器)
- 界面参考 GitHub 移动端:Primer 配色、自动适配深色模式、语言色点与 owner/repo 双色标题
- 底部「仓库 / 搜索 / 下载 / 设置」四个 Tab,仓库内分「构建 / 正式版 / 源码」三栏
- 搜索全站仓库(支持最佳匹配 / 星标最多 / 最近更新排序),也能直接粘贴仓库地址打开
- 下载中心统一管理所有任务,可取消 / 移除 / 清空已完成
- 1–128 可调并发上限(默认 16)+ AIMD 自适应并发:这里设的是天花板,不是固定连接数。 引擎按 TCP 拥塞控制的思路自适应 —— 顺畅时加性增、一遇限流(429/503)立刻乘性减半, 于是并发会自己停在「服务器愿意给的那个档位」,而不是盲目砸 128 条连接撞限流。
- 通道并发探测 + 5 分钟缓存:开下载前同时打所有候选镜像,可用的先上岗、死的立刻剔除, 并把实测速度作为初始权重交给引擎;同一 host 5 分钟内复用排序,第二次下载基本瞬发。
- 字节覆盖校验 + 缺口自动修复:收尾不再只看「文件大小对不对」,而是用写入账本核对 「每个字节是否恰好被写过一次」—— 「重复写一段 + 漏写一段」的总量可能相等, 这正是「下载完却解压不了」的元凶。校验发现缺口时会自动把缺的区间重新下一次 (最多 3 轮),能救回来的就不让你重下几百 MB。
- Content-Range 严格校验:有些镜像/CDN 对 Range 支持不完整,返回码仍是 206 但从别的偏移开始给数据。不校验就会把数据写到错误位置 —— 下载"成功"但文件是坏的。
- 卡住看门狗:CDN 的心跳字节会让 URLSession 的 idle 超时永远不触发,连接看着在动其实一动不动。 引擎改用「有没有真的写进文件」判卡住,12 秒无进展就主动掐断重建,不再「时不时卡住」。
- 失败片退避重派:失败的区间带退避时间回池子,不再插到队首被立刻重取(那是「越限越死」的根因)
- 后台续下:未完成任务落盘,进程被杀后下次启动自动恢复下载
- 自动重试(每段最多 3 次)、可随时取消
- 下载完成后一键导出到「文件」App / 分享(也可以在「文件」App → 我的 iPhone → ArtifactBoost → Artifacts 里直接找到)
- 打开本仓库的 Actions 页面 → 选最新一次成功的 Build ArtifactBoost
- 在页面底部的 Artifacts 区域下载 ArtifactBoost-unsigned.ipa
- 在电脑上用免费工具自签安装到手机(未签名包不能直接双击安装):
- Sideloadly(Windows / macOS,最省事):拖入 ipa → 填 Apple ID → Start
- AltStore / SideStore:把 ipa 放进 AltStore 后安装
- 免费 Apple ID 签名的 App 有效期为 7 天,到期重签一次即可
- 装好后打开 App,粘贴 Token 登录即可使用
同一个 Artifacts 里还有 ArtifactBoost-simulator.zip,是给 Mac 上的 iOS 模拟器用的。
-
Mac 上安装 Xcode 16 或更新版本(XcodeGen 生成的是新版工程格式,Xcode 15 打不开)
-
安装 XcodeGen 并生成工程:
brew install xcodegen xcodegen generate open ArtifactBoost.xcodeproj
-
选中 TARGETS → ArtifactBoost → Signing & Capabilities,Team 选择你的 Apple ID(免费 Personal Team 即可)
-
连上 iPhone,选中设备,按
⌘R运行
- 打开 Xcode → Create New Project → iOS → App
- Product Name:
ArtifactBoost;Interface:SwiftUI;Language:Swift
- Product Name:
- 删除 Xcode 自动生成的
ContentView.swift和ArtifactBoostApp.swift - 把
Sources里的全部.swift文件拖进项目导航(勾选 Copy items if needed,Target 勾选 ArtifactBoost) - General 里把 Minimum Deployments 设为 iOS 16.0,Signing 里选好自己的 Team,
⌘R运行
方式 A:Classic Token(最省事)
打开 https://github.com/settings/tokens/new
→ Note 随便填 → Expiration 自选 → 勾选 repo → Generate → 复制 ghp_ 开头的 Token。
方式 B:Fine-grained Token(更安全)
打开 https://github.com/settings/personal-access-tokens/new
→ Repository access 选 Only select repositories 并勾选目标仓库
→ Permissions 里把 Actions 和 Contents 都设为 Read
→ Generate → 复制 github_pat_ 开头的 Token。
在 App 登录页粘贴 Token,点「验证并登录」。
先花 10 秒在「设置」里把加速参数调好,之后每次下载都直接生效:
- 设置 → 加速设置:并发上限选 16(网络好可以拉到 32 / 64,自建中转可以 128)—— 改动即自动保存。 注意这是上限:引擎用 AIMD 自适应算法自己决定实际开多少条连接,设大不会更慢,只会给它更高的天花板
- 设置 → 下载源:点「镜像加速」(推荐)或「官方源」,一点即切换并保存;有自建反代可打开「自建中转」填前缀
- 回到仓库 → 选仓库 →(构建 / 正式版 / 源码)→ 点「加速下载」
下载中的任务都在底部「下载」Tab 里,可以随时取消、重试、导出到「文件」App。
能。搜索 Tab 里搜到的公开仓库,不需要你拥有它,就能下载:
- 构建产物 / 构建日志(Actions)
- 正式版附件(Release Assets)
- 源码包(zipball / tarball,任意分支或 tag)
唯一要求是 Token 能读取公开仓库:
- classic Token:勾选
repo即可 - fine-grained Token:需要在创建时允许读取公开仓库(Public repositories 只读), 或者把目标仓库加进授权范围
如果打开仓库时提示 403 / 404,就是 Token 权限问题,App 会给出对应提示。
官方源:直接连 GitHub 的 Azure 存储,最安全,但国内经常只有几十 KB/s镜像加速(默认):直连与几个公共镜像多通道并行,带宽叠加 (分块初始均分,下载中按实时吞吐动态分配,快通道多干活)自建中转:打开开关后填自己的加速前缀,比如自建的 Cloudflare Worker / 反向代理地址;前缀为空时回退直连
公共镜像只中转「已经签名的产物下载地址」,整个过程不经过你的 Token; 但产物数据本身会经过第三方服务器,因此私有仓库一律强制直连。
在 Cloudflare Workers 新建一个 Worker,粘贴下面几行,把生成的地址填进 App 的「自定义」:
export default {
async fetch(request) {
const target = new URL(request.url).pathname.slice(1) + new URL(request.url).search
return fetch(target, { headers: request.headers, method: request.method })
}
}然后填 https://你的worker名.workers.dev/ 即可(Range 请求会自动透传,支持多线程分段)。
速度由三段链路里最慢的一段决定,App 只能优化其中一段:
| 环节 | 实际情况 |
|---|---|
| 你的宽带 | 100Mbps≈12MB/s、300Mbps≈37MB/s、500Mbps≈62MB/s —— 这是绝对上限 |
| 到 GitHub 存储的链路 | 国内直连 Azure 常见只有几十 KB/s,链路差的时段更慢 |
| 并发 + 中转(App 负责) | 默认 16 连接、可拉到 64;智能加速把多条通道叠加 |
对应的现实预期:
- 直连 + 多连接:国内通常 1~5 MB/s,晚高峰可能只有几百 KB/s
- 公共镜像 + 多连接:常见几 MB/s(镜像本身也会被挤,且不同节点速度差别很大)
- 自建中转 + 32~64 连接:这是唯一能稳定摸到几十 MB/s 的路子。 Cloudflare Worker 或香港/国内 VPS 反代,单连接就能有几 MB/s,多连接叠加后取决于你的宽带上限
一句话:如果不开中转,光靠 App 不可能稳定跑到几十 MB/s——那是链路物理限制,不是并发数能解决的。 用上面的「自建加速前缀」接一个中转,再配合 32~64 并发,才有机会。
下载时产物卡片会显示「通道 + 实测速度」,可以直接用它验证自己环境的上限。
能 —— 前提是「源端能给出的带宽 ≥ 你的带宽」。为了不白白浪费可用带宽,引擎做了两件事:
- 多会话连接:Cloudflare 这类 CDN 会协商 HTTP/2,所有请求会被塞进同一条 TCP 连接, 长链路下单连接就是天花板,开再多"连接"也没用。引擎会拆成多个独立 URLSession 会话, 每个会话有独立连接池,才能拿到真正的并行连接
- 分块数 = 连接数 × 4:多出来的分块在 URLSession 里排队,哪条连接先空出来就接下一条, 不会因为"最慢的那一块"拖住整体
- AIMD 自适应窗口:并发不是一上来就顶满,而是从 16 起步、顺畅时慢慢涨、被限流立刻砍半。 这样既能在服务器给得出来时吃满带宽,又不会在服务器吃不消时越限越死
所以:如果中转能给到 10 MB/s 以上,App 会把这些带宽全部吃满,直到撞上你的宽带上限; 如果速度始终停在几百 KB,那说明源端只给了这么多 —— 换一条中转线路才是解法,加连接没用。
因为 128 现在是上限而不是目标值。老实现会真的同时开 128 条连接: 起步瞬间几百个请求砸过去,Azure 直接回 503 ServerBusy,接着指数退避, 体感就是「刚开始就卡住、速度忽高忽低」。
现在引擎内部维护一个 AIMD 窗口:起始 16,每成功一片 +1,每命中一次限流砍半。 窗口会自己收敛到服务器愿意给的档位(常见 24~64),然后稳稳地跑。 另外还有一个速率闸(每秒请求数上限)配合窗口一起压 QPS —— 光管并发管不住 429。
自建反代的小提示:nginx 建议不要开
http2(写listen 443 ssl;而不是listen 443 ssl http2;)。 HTTP/1.1 下单连接限速更明显,多连接的收益更大;App 的多个会话也能兜住 h2 的情况。
- 下载时尽量保持 App 在前台:已申请系统后台任务,切走后有约 30 秒缓冲,之后 iOS 仍会暂停网络任务
- 大文件建议在 Wi-Fi 下下载
- 国内直连 GitHub 的 Azure 存储常见只有几十 KB/s,这是链路的限制而不是 App 的限制; 多开连接与「智能加速」通道就是为了绕开它,走镜像/自建反代通常能到几 MB/s
- GitHub 产物默认保留 90 天,过期的产物(列表里标红「已过期」)无法下载
- 加速的原理是绕过单连接限速,无法突破你本地网络的物理带宽上限
- Token 不要泄露给他人;怀疑泄露时到 GitHub Settings 里点 Revoke 即可
Sources/
├── ArtifactBoostApp.swift App 入口,按登录状态切换界面
├── SessionManager.swift 登录态管理(Token 存取)
├── KeychainHelper.swift 系统钥匙串读写
├── GitHubModels.swift API 数据模型
├── GitHubClient.swift GitHub REST API 客户端(含 302 签名地址解析)
├── DownloadRoute.swift 下载通道(直连 / 镜像 / 自定义)
├── RouteProbe.swift 通道并发探测 + 5 分钟结果缓存
├── WriteLedger.swift 写入覆盖账本(字节级完整性校验 + 缺口定位)
├── AdaptiveLimiter.swift AIMD 自适应并发窗口 + 速率闸(防限流核心)
├── DownloadEngine.swift 多线程 Range 分段下载引擎(核心加速逻辑)
├── DownloadManager.swift 下载任务调度(状态/进度/取消/重试)
├── Formatters.swift 字节数/网速格式化
│
│ ——— 界面 ———
├── ArtifactBoostApp.swift App 入口:未登录显示登录页,已登录进主界面
├── RootTabView.swift 底部 Tab:仓库 / 搜索 / 下载 / 设置
├── LoginView.swift 登录页
├── RepoListView.swift 我的仓库(筛选 + GitHub 风格仓库行)
├── SearchView.swift 搜索全站仓库 / 直接打开仓库
├── RepoDetailView.swift 仓库详情:构建 / 正式版 / 源码 三栏
├── RunDetailView.swift 单次构建:构建日志 + 全部产物
├── ReleaseDetailView.swift 正式版:附件 + 该 tag 的源码包
├── DownloadsView.swift 下载中心(实时总览 + 进行中 / 已完成)
├── DownloadDetailsView.swift 下载详情:连接热力条 + 分段明细 + 通道速度
├── SettingsView.swift 设置:账户、并发上限、下载源切换
├── DownloadItemRow.swift 通用下载行(渐变进度条 / 速度趋势线 / 状态自适应)
├── Theme.swift 统一视觉元素(配色 / 渐变 / 进度条 / 指标瓦片 / 空态)
└── DownloadItem.swift 可下载项抽象(产物 / 日志 / 附件 / 源码包)