用途
asc-ad-hoc-distribution 用于把已有的 iOS 归档(.xcarchive)转换为面向已注册设备的私有、可验证的安装链接,适用于不走 TestFlight 或 App Store 的私有发布测试分发场景。当构建需要经由 Apple 托管的渠道分发时,应改用 TestFlight 或 App Store 发布相关技能。
前置确认
执行前先确认已安装的命令契约:
asc distribute --help
asc distribute plan --help
asc distribute apply --help
asc distribute resume --help
asc distribute status --help
asc distribute verify --help
工作流选择
- 端到端、基于哈希授权的运行:使用 plan -> apply -> resume/status -> verify,从 .xcarchive 开始。
- 若调用方已持有 ad hoc IPA,并希望分别操作底层边界,则使用 inspect -> prepare -> publish。
安全护栏
分发规格(spec)、设备文件、PKCS#12 身份、密码文件、运行状态和确切的安装链接产物都应视为私密资料,须排除在 Git 之外并要求仅属主权限。
不得把 S3 凭据或预签名 URL 写入分发规格、命令输出、日志、issue 或聊天。应使用 ASC_S3_ACCESS_KEY_ID、ASC_S3_SECRET_ACCESS_KEY 及可选的 ASC_S3_SESSION_TOKEN,或标准 AWS SDK 凭据链。
plan 为只读操作,可能在 ready: false 的情况下以成功状态退出;继续前应先检查类型化的阻断项(blockers)与影响清单(effects)。
apply 可以注册缺失的设备、创建安全的 App ID 与后继 ad hoc 描述文件、写入本地产物并发布不可变对象。只有在用户授权确切的 plan hash 与影响清单之后才能运行。
该编排工作流支持对已有 S3 兼容存储桶的私有访问。它不会创建存储桶、修改策略、删除旧构建、安装应用或启动应用。
输入漂移、不可变对象冲突、签名材料过期或私有链接过期,都需要重新生成计划,不得强行推进旧运行。
前置条件
- 已存在的 iOS .xcarchive,且仅含一个主应用 target。内嵌应用、扩展、Watch 应用和 App Clip 会使 v1 计划无法就绪。
- 本地 iOS 分发用 PKCS#12 身份,以及可选的受保护密码文件。
- 受保护的 strict-v1 设备文件,例如:
{"schemaVersion":1,"devices":[{"name":"Test iPhone","udid":"DEVICE_UDID","platform":"IOS"}]}
- App Store Connect 认证,且可访问设备、Bundle ID、证书和描述文件。
- 已存在的 S3 兼容存储桶及有效凭据。
1. 创建私有分发规格
相对路径从规格文件所在目录解析。规格不会插值环境变量,也不接受凭据。一个代表性的私有配置如下:
{
"schemaVersion": 1,
"devicesFile": "devices.json",
"signing": {
"identity": {
"format": "pkcs12",
"path": "../signing/distribution.p12",
"passwordFile": "../secrets/distribution-p12-password"
},
"minimumValidityDays": 7,
"maxMutations": 32
},
"publication": {
"endpoint": "https://objects.example.com",
"downloadEndpoint": "https://downloads.example.com",
"region": "auto",
"bucket": "ios-builds",
"prefix": "team/app",
"addressingStyle": "path",
"urlTtl": "24h",
"downloadGrace": "1h",
"verifyTimeout": "30s"
},
"metadata": {
"title": "App",
"channel": "pull-request-42",
"sourceRevision": "abc123",
"sourceUrl": "https://example.com/team/app/commit/abc123"
}
}
passwordFile、certificateSha256、downloadEndpoint 以及所有 metadata 字段均为可选。省略密码文件意味着 PKCS#12 必须使用空密码。规划前先保护配置与密钥输入:
chmod 600 ".asc/distribution/config.json" ".asc/distribution/devices.json"
chmod 600 ".asc/signing/distribution.p12" ".asc/secrets/distribution-p12-password"
2. 只读规划(plan)
asc distribute plan \
--archive-path ".asc/artifacts/App.xcarchive" \
--config ".asc/distribution/config.json" \
--plan ".asc/distribution/plan.json" \
--state-dir ".asc/distribution/runs" \
--output json
检查 ready、planHash、签名有效期、目标位置以及完整有序的影响清单。当 ready 为 false 时,解决阻断项并重新生成计划,不能仅凭退出码推断就绪状态。
3. 执行经授权的精确计划(apply)
在批准确切影响后,传入完整的 64 位哈希:
PLAN_HASH="$(jq -er '.planHash' ".asc/distribution/plan.json")"
asc distribute apply \
--plan ".asc/distribution/plan.json" \
--confirm "$PLAN_HASH" \
--output json
缺失、格式错误或不一致的确认会在产生副作用前被拒绝。成功意味着发布与实时抓取验证已完成,但不意味着某台设备已安装或启动该应用。
4. 查看、恢复与验证
使用返回的 runId:
asc distribute status --run "RUN_ID" --state-dir ".asc/distribution/runs" --output json
asc distribute resume --run "RUN_ID" --state-dir ".asc/distribution/runs" --output json
asc distribute verify --run "RUN_ID" --state-dir ".asc/distribution/runs" --timeout 30s --output json
status 仅本地执行,对 running、recoverable 和 blocked 状态的运行都会成功;应依据类型化字段而非文字描述分支处理。resume 在重试前会重新验证持久证据,绝不盲目重复远程写入。verify 为只读,但会执行实时抓取。仅当用户要求观察已连接设备上匹配的已安装 bundle、版本与构建号时,才添加 --device "DEVICE_SELECTOR";该观察不能证明 IPA 字节一致。
确切的私有安装 URL 是一种 bearer 凭据,仅存储在运行完成后报告的、仅属主可读的链接产物中,只应通过经批准的私有渠道共享给目标测试者。
底层 IPA 工作流
当签名与导出已完成时使用此路径。把 prepare 返回的精确 bundleDir 传给 publish:
asc distribute inspect --ipa ".asc/artifacts/App.ipa" --output json
asc distribute prepare --ipa ".asc/artifacts/App.ipa" --channel "pull-request-42" --output json
asc distribute publish \
--bundle-dir ".asc/distribution/com.example.app/1.2-42-IPA_SHA_PREFIX" \
--endpoint "https://objects.example.com" \
--region "auto" \
--bucket "ios-builds" \
--prefix "team/app" \
--receipt ".asc/publishes/app-1.2-42.json" \
--link-path ".asc/publishes/app-1.2-42-link.json" \
--output json
inspect 默认省略原始设备 UDID,除非显式需要 --include-devices。prepare 绝不覆盖已有 bundle,只会复用完全等价的 bundle。私有发布是默认方式,只把确切的预签名链接写入权限为 0600 的链接产物。公开发布是另一条显式路径,使用 --access public --public-base-url;它假定匿名读取已配置完成,且从不更改存储策略。
适用场景与限制
适用于团队内部按渠道(如 pull-request-42)向已注册设备分发测试构建的私有安装链接,并需要发布、恢复与验证能力的情况。限制包括:仅支持单一主应用 target 的归档;不创建存储桶、不修改策略、不删除旧构建;不负责安装或启动应用;输入漂移、不可变对象冲突、签名材料或私有链接过期都要重新规划。其他未在资料中说明的功能、收费、平台或价格信息暂未提供。