iOS 证书与描述文件检测接口用于解析.p12证书与.mobileprovision描述文件,输出有效期、吊销状态、Team ID、证书类型、设备列表、entitlements 权限,以及证书与描述文件是否匹配的验证结果。对于需要管理多个开发者账号、批量检查证书状态的团队,这类检测能省下大量手工核对。本文从零开始,说明第一次调用需要准备什么、最小请求怎么发、返回值怎么看。
适用场景与能力边界
典型用途包括:上架前检查分发证书是否即将过期;排查「描述文件与证书不匹配」这类构建报错;定期巡检团队账号下所有证书的吊销状态;在 CI 流程中自动校验签名材料是否可用。
接口输出包含:证书有效期、吊销状态、Team ID、证书类型(开发 / 分发 / 企业)、设备列表、25 项 entitlements 权限,以及证书与描述文件的匹配性验证。
能力边界需要明确:接口做的是解析与比对,不修改证书、不重签、不生成新的描述文件。吊销状态依赖上游查询结果,反映查询时刻的状态,不适合作为秒级轮询依据。entitlements 返回的是描述文件中声明的权限项,接口不做权限合法性裁决。
请求参数与准备
接口方法为POST,地址为https://v1.apizero.cn/api/ios-cert。参数如下:
| 参数 | 说明 |
|---|---|
cert | .p12证书内容 |
provision | .mobileprovision描述文件内容 |
password | .p12证书的导出密码,未设密码时可不传或留空 |
cert与provision通常以 base64 编码后放入请求体,具体编码与传参格式以文档为准。password是导出.p12时设置的密码,不是 Apple ID 密码;若导出时未设置密码,可以留空。三个参数的组合方式(能否只传其一做单文件解析)以文档为准。
鉴权方面,实践中最常用的是在请求头中携带Authorization: Bearer <API_KEY>。
最小请求:curl 示例
先准备两个文件并转成 base64 单行字符串:
CERT_B64=$(base64 -w 0 dev.p12) PROV_B64=$(base64 -w 0 dev.mobileprovision)然后发起请求:
curl -X POST "https://v1.apizero.cn/api/ios-cert" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"cert\": \"${CERT_B64}\", \"provision\": \"${PROV_B64}\", \"password\": \"YOUR_P12_PASSWORD\"}"base64 -w 0用于去掉换行符,否则 JSON 字符串里会出现非法字符。Windows 环境可用 PowerShell 的[Convert]::ToBase64String([IO.File]::ReadAllBytes("dev.p12"))。
Python 接入示例
下面封装一个带文件读取、base64 编码与业务码判断的调用函数:
import base64 import os import requests def check_ios_cert(p12_path: str, prov_path: str, p12_password: str = "", api_key: str | None = None) -> dict: with open(p12_path, "rb") as f: cert_b64 = base64.b64encode(f.read()).decode("utf-8") with open(prov_path, "rb") as f: prov_b64 = base64.b64encode(f.read()).decode("utf-8") url = "https://v1.apizero.cn/api/ios-cert" body = {"cert": cert_b64, "provision": prov_b64} if p12_password: body["password"] = p12_password headers = {"Content-Type": "application/json"} key = api_key or os.environ.get("APIZERO_KEY") if key: headers["Authorization"] = f"Bearer {key}" resp = requests.post(url, json=body, headers=headers, timeout=30) resp.raise_for_status() payload = resp.json() if payload.get("code") != 0: raise RuntimeError(f"检测失败: code={payload.get('code')}, msg={payload.get('msg')}") return payload["data"] data = check_ios_cert("dev.p12", "dev.mobileprovision", "YOUR_P12_PASSWORD") print("证书类型:", data.get("cert_type")) print("是否匹配:", data.get("matched"))注意.p12与描述文件属于敏感材料,不要在本地或 CI 日志中明文打印,读取路径也应做访问控制。
返回字段解读
成功响应的code == 0,检测结果在data内。字段含义如下(名称与结构以文档为准):
| 字段 | 含义 |
|---|---|
cert_type | 证书类型:开发 / 分发 / 企业 |
team_id | Team ID |
not_before/not_after | 证书有效期起止时间 |
revoked | 是否已被吊销 |
devices | 描述文件中包含的设备 UDID 列表 |
entitlements | 25 项权限声明 |
matched | 证书与描述文件是否匹配 |
建议的读取顺序:先看revoked与not_after,这两项决定证书能否继续使用;再看matched,这是构建报错最常见的原因;cert_type与team_id用于确认拿的是不是正确的账号材料;devices与entitlements在需要核对覆盖范围或推送、Associated Domains 等权限时再展开。
需要提醒:devices仅对含设备 UDID 的描述文件类型(如开发或 Ad Hoc)有意义,分发类型的描述文件通常不含设备列表,读到空列表属正常。entitlements是一个包含 25 项权限的集合,各项是否存在取决于描述文件的配置,读取时按 key 判断,不要假设所有项都存在。
常见错误与排查
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
code非 0,提示解析失败 | base64 编码含换行,或文件损坏 | 确认使用-w 0去除换行 |
code非 0,提示密码错误 | password与导出密码不一致 | 重新确认导出时设置的密码 |
code非 0,提示鉴权失败 | Key 缺失或无效 | 检查Authorization请求头 |
matched为 false | 证书与描述文件来自不同账号或类型不配套 | 核对 Team ID 与证书类型是否一致 |
| HTTP 429 | 超出调用频率 | 控制并发,QPS 以文档为准 |
区分两类失败:解析失败是输入材料的问题,重试无效;鉴权与限流属于调用侧问题,应修正后重试。
工程化注意事项
证书材料加密存放。.p12与描述文件可直接用于签名,泄露风险高。存储时加密,访问时按最小权限授权,不要把密码与证书放在同一处。
CI 中做前置校验。在打包脚本开始前调用一次检测,revoked=true或not_after临近时直接中断流水线,比构建失败后再排查更省时间。
到期巡检用定时任务。按天级别周期检查团队账号下的证书,而不是在构建时才发现过期。证书有效期较长,无需高频轮询。
结果缓存。同一份证书与描述文件的解析结果稳定,可按文件哈希做缓存,减少重复请求。
不要把entitlements当合规裁决。它是声明内容的解析结果,权限是否被 Apple 接受仍需以实际签名与上架流程为准。
参考文档
- 接口文档
- 接口地址