asc-ad-hoc-distribution

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ASC ad hoc distribution

ASC 临时分发

Use the experimental
asc distribute
workflow to turn an existing iOS archive into a private, verified install link for registered devices. Use TestFlight or the App Store release skills instead when the build should go through Apple-hosted distribution.
Confirm the installed contract before acting:
bash
asc distribute --help
asc distribute plan --help
asc distribute apply --help
asc distribute resume --help
asc distribute status --help
asc distribute verify --help
使用实验性的
asc distribute
工作流,将现有的iOS归档文件转换为供已注册设备使用的私有验证安装链接。如果构建需要通过Apple托管的分发渠道,请改用TestFlight或App Store发布工具。
执行操作前请确认已安装的合约:
bash
asc distribute --help
asc distribute plan --help
asc distribute apply --help
asc distribute resume --help
asc distribute status --help
asc distribute verify --help

Choose the workflow

选择工作流

  • Use
    plan
    ->
    apply
    ->
    resume
    /
    status
    ->
    verify
    for an end-to-end, hash-authorized run starting from an
    .xcarchive
    .
  • Use
    inspect
    ->
    prepare
    ->
    publish
    only when the caller already owns the ad hoc IPA and wants to operate the lower-level boundaries separately.
  • 若要从
    .xcarchive
    开始执行端到端的哈希授权流程,请使用
    plan
    ->
    apply
    ->
    resume
    /
    status
    ->
    verify
    流程。
  • 当调用方已拥有临时IPA,并希望单独操作底层环节时,仅使用
    inspect
    ->
    prepare
    ->
    publish
    流程。

Guardrails

操作规范与防护

  • Treat the distribution spec, devices file, PKCS#12 identity, password file, run state, and exact install-link artifact as private. Keep them out of Git and require owner-only permissions.
  • Never put S3 credentials or presigned URLs in the distribution spec, command output, logs, issues, or chat. Use
    ASC_S3_ACCESS_KEY_ID
    ,
    ASC_S3_SECRET_ACCESS_KEY
    , and optional
    ASC_S3_SESSION_TOKEN
    , or the standard AWS SDK credential chain.
  • plan
    is read-only and may exit successfully with
    ready: false
    . Inspect the typed blockers and effects before continuing.
  • apply
    can register missing devices, create safe App IDs and successor ad hoc profiles, write local artifacts, and publish immutable objects. Run it only after the user authorizes the exact plan hash and effect inventory.
  • The orchestrated workflow supports private access to an existing S3-compatible bucket. It does not create buckets, change policies, delete old builds, install the app, or launch it.
  • Input drift, an immutable-object conflict, expired signing material, or an expired private link requires a new plan. Do not force the old run forward.
  • 请将分发配置文件、设备文件、PKCS#12身份证书、密码文件、运行状态以及确切的安装链接产物视为私有信息。请勿将其存入Git,且仅允许所有者拥有访问权限。
  • 切勿将S3凭证或预签名URL放入分发配置文件、命令输出、日志、问题工单或聊天内容中。请使用
    ASC_S3_ACCESS_KEY_ID
    ASC_S3_SECRET_ACCESS_KEY
    以及可选的
    ASC_S3_SESSION_TOKEN
    ,或标准AWS SDK凭证链。
  • plan
    是只读操作,即使返回
    ready: false
    也可能成功退出。请在继续操作前检查明确的阻塞项和影响。
  • apply
    可以注册缺失的设备、创建安全的App ID和后续临时配置文件、写入本地产物并发布不可变对象。仅在用户授权确切的计划哈希和影响清单后再执行该操作。
  • 编排后的工作流支持对现有S3兼容存储桶的私有访问,但不会创建存储桶、修改策略、删除旧构建、安装应用或启动应用。
  • 输入漂移、不可变对象冲突、签名材料过期或私有链接过期时,需要创建新计划。请勿强行推进旧流程。

Preconditions

前置条件

  • An existing iOS
    .xcarchive
    with one main app target. Embedded apps, extensions, Watch apps, and App Clips make the v1 plan not ready.
  • A local iOS distribution PKCS#12 identity and optional protected password file.
  • A protected strict-v1 devices file. For example:
json
{"schemaVersion":1,"devices":[{"name":"Test iPhone","udid":"DEVICE_UDID","platform":"IOS"}]}
  • App Store Connect authentication with access to devices, Bundle IDs, certificates, and profiles.
  • An existing S3-compatible bucket and valid credentials.
  • 存在包含一个主应用目标的iOS
    .xcarchive
    文件。嵌入式应用、扩展、Watch应用和App Clips会导致v1计划无法就绪。
  • 本地iOS分发PKCS#12身份证书和可选的受保护密码文件。
  • 受保护的strict-v1设备文件。例如:
json
{"schemaVersion":1,"devices":[{"name":"Test iPhone","udid":"DEVICE_UDID","platform":"IOS"}]}
  • 具备访问设备、Bundle ID、证书和配置文件权限的App Store Connect认证。
  • 已存在的S3兼容存储桶和有效凭证。

1. Create the private distribution spec

1. 创建私有分发配置文件

Relative paths resolve from the spec directory. The spec does not interpolate environment variables or accept credentials. A representative private config is:
json
{
  "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
, and every metadata field are optional. An omitted password file means the PKCS#12 must use an empty password. Protect the config and secret inputs before planning:
bash
chmod 600 ".asc/distribution/config.json" ".asc/distribution/devices.json"
chmod 600 ".asc/signing/distribution.p12" ".asc/secrets/distribution-p12-password"
相对路径从配置文件目录解析。配置文件不会插值环境变量或接受凭证。一个典型的私有配置如下:
json
{
  "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
以及所有元数据字段都是可选的。如果省略密码文件,则PKCS#12必须使用空密码。在执行计划前请保护好配置文件和保密输入:
bash
chmod 600 ".asc/distribution/config.json" ".asc/distribution/devices.json"
chmod 600 ".asc/signing/distribution.p12" ".asc/secrets/distribution-p12-password"

2. Plan without mutation

2. 执行无变更计划

bash
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
Inspect
ready
,
planHash
, signing validity, destination, and the complete ordered
effects
inventory. Resolve blockers and create a new plan when
ready
is false. Do not infer readiness from exit code alone.
bash
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
、签名有效性、目标地址以及完整的有序
effects
清单。当
ready
为false时,请解决阻塞项并创建新计划。请勿仅通过退出码推断就绪状态。

3. Apply the exact authorized plan

3. 应用已授权的确切计划

After approval of the exact effects, pass the full 64-character hash:
bash
PLAN_HASH="$(jq -er '.planHash' ".asc/distribution/plan.json")"
asc distribute apply \
  --plan ".asc/distribution/plan.json" \
  --confirm "$PLAN_HASH" \
  --output json
Missing, malformed, or unequal confirmation is rejected before side effects. Success means publication and live fetch verification completed; it does not mean a device installed or launched the app.
在确认确切影响后,传入完整的64位哈希值:
bash
PLAN_HASH="$(jq -er '.planHash' ".asc/distribution/plan.json")"
asc distribute apply \
  --plan ".asc/distribution/plan.json" \
  --confirm "$PLAN_HASH" \
  --output json
缺失、格式错误或不匹配的确认信息会在产生副作用前被拒绝。操作成功意味着发布和实时获取验证已完成,但不代表设备已安装或启动应用。

4. Inspect, resume, and verify

4. 检查、恢复和验证

Use the returned
runId
:
bash
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
is local-only and succeeds for
running
,
recoverable
, and
blocked
runs; branch on typed fields rather than prose.
resume
revalidates durable evidence before retrying and never blindly repeats a remote write.
verify
is read-only but performs live fetches. Add
--device "DEVICE_SELECTOR"
only when the user asks to observe the matching installed bundle, version, and build on a connected device; this observation does not prove IPA byte identity.
The exact private install URL is a bearer credential stored only in the owner-private link artifact reported by the completed run. Share it only with the intended tester through an approved private channel.
使用返回的
runId
bash
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
是只读操作,但会执行实时获取。仅当用户需要观察已连接设备上匹配的已安装包、版本和构建时,才添加
--device "DEVICE_SELECTOR"
参数;该观察无法证明IPA字节的一致性。
确切的私有安装URL是仅存储在已完成流程报告的所有者私有链接产物中的承载凭证。请仅通过经批准的私有渠道与指定测试人员分享。

Lower-level IPA workflow

底层IPA工作流

Use this lane when signing and export are already complete. Pass the exact
bundleDir
returned by
prepare
to
publish
:
bash
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
omits raw device UDIDs unless
--include-devices
is explicitly needed.
prepare
never overwrites a bundle and reuses only an exact equivalent. Private
publish
is the default and writes exact presigned links only to the mode-0600 link artifact. Public publication is a separate explicit lane using
--access public --public-base-url
; it assumes anonymous reads are already configured and never changes storage policy.
当签名和导出已完成时使用此流程。将
prepare
返回的确切
bundleDir
传入
publish
bash
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
绝不会覆盖包,仅会重用完全相同的包。默认使用私有
publish
,仅将确切的预签名链接写入权限为0600的链接产物。公开发布是一个单独的明确流程,需使用
--access public --public-base-url
参数;该流程假设匿名读取已配置完成,且绝不会修改存储策略。