Android 开发者管理中心 API

Android Developer Console API 是一项 RESTful 服务,可让经过验证的开发者在 Android 开发者管理中心内自动执行 Android 开发者验证工作流,包括检索开发者账号、检查关键资格要求、注册 Android 软件包名称、注册应用签名密钥以及验证密钥所有权。

概览、应用场景和实现背景

主要应用场景和功能

  • 自动化 CI/CD 软件包名称注册:以编程方式注册数十或数百个 Android 软件包名称 (CreateAndroidPackage)。
  • 预检历史密钥政策检查:以编程方式检查 Google 之前是否在生态系统中观察到某个软件包名称,以及注册特定签名证书是否需要进行密钥所有权验证 (GetAndroidPackageRegistrationPolicy)。
  • 自动注册应用签名密钥和验证所有权:注册公开签名证书 SHA-256 指纹 (CreateAndroidPackageKey),检索唯一的验证质询令牌 (verificationToken),并使用单请求或可续传的已签名 APK 上传 (VerifyAndroidPackageKeyOwnership) 自动证明私钥所有权。
  • 以编程方式提交理由:提交所有权理由 (JustifyAndroidPackageKeyRegistration)。
  • 状态监控:监控各个开发者账号、软件包名称和应用签名密钥(GetDeveloperAccount、ListDeveloperAccounts、GetAndroidPackage、ListAndroidPackages、GetAndroidPackageKey、ListAndroidPackageKeys)的注册状态。

端到端实现工作流程

  1. 在界面中验证开发者身份一次:在 Android 开发者管理中心内完成开发者身份验证(INDIVIDUAL 或 ORGANIZATION),以便 verificationState 为 VERIFIED。
  2. 启用 API 并进行身份验证:在 Google Cloud 云项目中启用 androiddeveloperconsole.googleapis.com,并获取范围为 https://www.googleapis.com/auth/androiddeveloperconsole 的用户委托 OAuth 2.0 Bearer 访问令牌。
  3. 查找您的开发者账号资源名称:调用 GET /v1/developerAccounts (ListDeveloperAccounts) 以检索 developerAccounts/{developer_account} 并验证 verificationState 是否为 VERIFIED。
  4. 检查软件包名称的注册政策:调用 GET /v1/developerAccounts/{id}/androidPackages/{pkg}/registrationPolicy (GetAndroidPackageRegistrationPolicy) 以检查 keySelectionStrategy(SELECT_KEY_FROM_LIST 或 USE_ANY_KEY)和任何已知的历史签名密钥 (knownKeys)。
  5. 创建 Android 软件包资源:调用 POST /v1/developerAccounts/{id}/androidPackages?androidPackageId={pkg} (CreateAndroidPackage),正文为 {"name": ""}(在 DRAFT 状态下创建资源)。
  6. 注册应用签名密钥指纹:使用 JSON 正文 {"certificateFingerprintSha256": "..."} 调用 POST /v1/developerAccounts/{id}/androidPackages/{pkg}/keys (CreateAndroidPackageKey)。检查返回的状态:
    • DRAFT:需要提供私钥所有权证明,并且响应中包含第 7 步所需的唯一 verificationToken。
    • IN_REVIEW:系统会自动跳过所有权证明和理由说明(例如,注册从未在 Android 上出现过的新软件包名称时,或者您已针对同一 DeveloperAccount 中的其他软件包名称验证了此签名密钥的所有权时)。跳过第 7 步和第 8 步中的理由说明调用,直接轮询 GetAndroidPackage 和 GetAndroidPackageKey。
  7. 构建并上传验证 APK(如果状态为 DRAFT):将返回的 verificationToken 字符串嵌入到与 packageName 匹配的最小 APK 内的 assets/adi-registration.properties 中,使用您的私有应用签名密钥为其签名,然后使用 POST /upload/v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:verify (VerifyAndroidPackageKeyOwnership) 将其上传。
  8. 提交理由(如果需要)并轮询注册状态:如果密钥处于 OWNERSHIP_VERIFIED 状态且 registrationJustificationRequired 为 true,请调用 POST /v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:justifyAndroidPackageKeyRegistration (JustifyAndroidPackageKeyRegistration)。轮询 GetAndroidPackage 和 GetAndroidPackageKey,直到 state 达到 REGISTERED。

用于准备密钥指纹和验证 APK 的本地 CLI 命令

  • 从密钥库 (keytool) 中提取 SHA-256 证书指纹:

    keytool -list -v -keystore release-key.jks -alias my-key-alias
  • 验证已构建 APK (apksigner) 上的 SHA-256 签名证书摘要:

    apksigner verify --print-certs app-release.apk
  • 在上传之前检查 APK 软件包名称和嵌入式令牌文件(aapt2 和 unzip):

    aapt2 dump badging app-release.apk | head -n 1
    unzip -p app-release.apk assets/adi-registration.properties

Android 开发者管理中心界面和 API 功能

任务 Android 开发者管理中心 Web 界面 (android.google.com/developerconsole) Android 开发者管理中心 API
开发者身份验证 (KYC/KYB) 和费用支付 支持(需要一次性前提条件) 不支持使用 API(使用 GetDeveloperAccount 和 ListDeveloperAccounts 进行只读状态检查)
查看关联的开发者账号 控制台标题中的账号切换器 GET /v1/developerAccounts (ListDeveloperAccounts)
检查软件包名称的历史签名密钥和政策 在“注册软件包名称”向导中显示 GET /v1/.../registrationPolicy (GetAndroidPackageRegistrationPolicy)
注册新的 Android 软件包名称 软件包名称 > 注册软件包名称 POST /v1/{parent}/androidPackages?androidPackageId=... (CreateAndroidPackage)
查看或列出已注册和草稿状态的软件包名称 软件包名称信息中心表格 GET /v1/{name}(GetAndroidPackage),GET /v1/{parent}/androidPackages(ListAndroidPackages)
添加应用签名密钥并生成质询令牌 软件包详情 > 添加签名密钥 POST /v1/{parent}/keys (CreateAndroidPackageKey)
证明私钥所有权 (adi-registration.properties) 在控制台界面中上传已签名的代码段 APK POST /upload/v1/{name}:verify (VerifyAndroidPackageKeyOwnership)
在密钥需要人工审核时提交理由 密钥注册工作流期间的文本提示词 POST /v1/{name}:justifyAndroidPackageKeyRegistration (JustifyAndroidPackageKeyRegistration)

服务配置和身份验证

所有 API 请求都必须使用 HTTPS,并包含使用 OAuth 2.0 Web 服务器流程为已在 Android 开发者管理中心内完成开发者身份验证的 Google 账号获取的 Authorization: Bearer ACCESS_TOKEN 标头。

属性 值
基本 REST 端点 https://androiddeveloperconsole.googleapis.com
媒体上传端点 https://androiddeveloperconsole.googleapis.com/upload
API 版本 v1
所需的 OAuth 2.0 范围 https://www.googleapis.com/auth/androiddeveloperconsole
默认配额限制 每个 Google Cloud 项目每天每种方法 2,000 次请求

API 资源和端点

Android Developer Console API 按以下层次结构组织资源:

  • DeveloperAccount (developerAccounts/{developer_account})
    • AndroidPackage (developerAccounts/{developer_account}/androidPackages/{android_package})
      • AndroidPackageRegistrationPolicy (developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy)
      • AndroidPackageKey (developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key})

资源:DeveloperAccount

表示 Android 开发者管理中心内与开发者身份相关联的账号。

字段 类型 说明
name string 标识符。资源名称,格式为 developerAccounts/{developer_account}。
displayName string 仅限输出。与开发者账号关联的人类可读名称(个人名称或组织名称)。
verificationState enum (VerificationState) 仅限输出。账号的当前开发者身份验证状态。

枚举:DeveloperAccount.VerificationState

值 说明
VERIFIED 开发者身份验证已完成。该账号可以注册软件包名称和应用签名密钥。
NOT_VERIFIED 尚未在 Android 开发者管理中心内完成开发者身份验证。

方法:DeveloperAccount

方法 HTTP 请求 说明
GetDeveloperAccount GET /v1/{name=developerAccounts/*} 检索单个 DeveloperAccount 的元数据和验证状态。
ListDeveloperAccounts GET /v1/developerAccounts 列出经过身份验证的 Google 账号可访问的所有 DeveloperAccount 对象(未分页)。

资源:AndroidPackage

表示在 DeveloperAccount 下注册或正在注册的 Android 软件包名称。

字段 类型 说明
name string 标识符。资源名称,格式为 developerAccounts/{developer_account}/androidPackages/{android_package},其中 {android_package} 是 Android 软件包名称(例如 com.example.myapp)。
packageName string 仅限输出。Android 软件包名称(例如 com.example.myapp)。
state enum (AndroidPackage.State) 仅限输出。软件包名称的当前注册生命周期状态。
registeredAppStore boolean 仅限输出。指示此软件包名称当前是否已作为注册的应用商店启用。

枚举:AndroidPackage.State

值 说明
DRAFT 软件包名称资源已创建,应用签名密钥注册或所有权验证仍在进行中。
IN_REVIEW 软件包名称注册信息和任何必要的密钥理由说明均已提交,Google 正在审核。软件包会在 CreateAndroidPackageKey 后立即从 DRAFT 转换为 IN_REVIEW(当跳过密钥所有权验证时,包括当密钥已针对同一 DeveloperAccount 中的其他软件包名称进行验证时),或者在完成 VerifyAndroidPackageKeyOwnership 以及(如果需要)JustifyAndroidPackageKeyRegistration 后转换。
REGISTERED 此软件包名称已在此开发者账号中注册,用于 Android 开发者验证。
PENDING_TRANSFER 此软件包名称正在等待完成向其他开发者账号的所有权转移。

资源:AndroidPackageRegistrationPolicy

GetAndroidPackageRegistrationPolicy 返回的单例资源,用于描述为软件包名称检测到的历史公开签名密钥,以及使用给定签名密钥注册软件包名称是否需要书面理由。

字段 类型 说明
name string 标识符。资源名称,格式为 developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy。
knownKeys[] object (KnownKey) 之前观察到用于分发具有此软件包名称的应用的历史应用签名密钥列表,按 certificateFingerprintSha256 的字典顺序排序。
knownKeys[].certificateFingerprintSha256 string 仅限输出。历史签名证书的标准化 64 字符小写十六进制 SHA-256 指纹(不含冒号)。
knownKeys[].justificationRequirement enum (JustificationRequirement) 仅限输出。指明注册此密钥是否需要调用 JustifyAndroidPackageKeyRegistration(REQUIRED 或 NOT_REQUIRED)。如果签名密钥之前已在同一 DeveloperAccount 下的另一个软件包名称上经过验证,则即使 justificationRequirement 为 REQUIRED,系统也会跳过 VerifyAndroidPackageKeyOwnership 和 JustifyAndroidPackageKeyRegistration。
keySelectionStrategy enum (KeySelectionStrategy) 仅限输出。注册此软件包名称的密钥选择政策:SELECT_KEY_FROM_LIST(必须注册 knownKeys 中的密钥)或 USE_ANY_KEY(可以注册开发者拥有的任何有效应用签名密钥)。

枚举:KnownKey.JustificationRequirement

值 说明
REQUIRED 如需注册此已知密钥,您需要在完成 VerifyAndroidPackageKeyOwnership 后使用 JustifyAndroidPackageKeyRegistration 提交书面理由(除非该密钥之前已在同一 DeveloperAccount 下的其他软件包名称上通过验证,在这种情况下,VerifyAndroidPackageKeyOwnership 和 JustifyAndroidPackageKeyRegistration 都会跳过)。
NOT_REQUIRED 注册此已知密钥无需提供理由。密钥会在 VerifyAndroidPackageKeyOwnership 后直接转换为 IN_REVIEW(如果密钥之前已在同一 DeveloperAccount 下的其他软件包名称上验证过,则会在 CreateAndroidPackageKey 后立即转换)。

枚举:AndroidPackageRegistrationPolicy.KeySelectionStrategy

值 说明
SELECT_KEY_FROM_LIST 调用方必须注册 knownKeys 中列出的某个历史密钥。
USE_ANY_KEY 除了 knownKeys 中的任何密钥之外,调用方还可以注册 Android 生态系统中之前未出现过的任何有效应用签名密钥。

方法:AndroidPackage

方法 HTTP 请求 说明
GetAndroidPackageRegistrationPolicy GET /v1/{name=developerAccounts/*/androidPackages/*/registrationPolicy} 检索软件包名称的密钥选择策略和已知历史签名密钥。
CreateAndroidPackage POST /v1/{parent=developerAccounts/*}/androidPackages?androidPackageId={package_name} 在 DRAFT 状态下创建新的 AndroidPackage 资源,以开始注册软件包名称。
GetAndroidPackage GET /v1/{name=developerAccounts/*/androidPackages/*} 检索现有 AndroidPackage 的详细信息和当前注册状态。
ListAndroidPackages GET /v1/{parent=developerAccounts/*}/androidPackages 列出 DeveloperAccount 下的 AndroidPackage 对象(pageSize 上限为 1000,pageToken)。

资源:AndroidPackageKey

表示与 AndroidPackage 关联的公开应用签名证书指纹,并跟踪所有权验证和注册审核状态。

字段 类型 说明
name string 标识符。服务器分配的资源名称,格式为 developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key},其中 {key} 是一个标准化的 64 字符小写十六进制 SHA-256 指纹,不含英文冒号。调用 CreateAndroidPackageKey 时必须省略或为空。
certificateFingerprintSha256 string 必需。不可变。应用签名证书的 SHA-256 哈希。在 CreateAndroidPackageKey 中输入时,接受纯 64 字符十六进制 (60e860e8...) 或以英文冒号分隔的十六进制 (60:E8:60:E8:...)。在输出时,始终标准化为不带英文冒号的 64 字符小写十六进制。
state enum (AndroidPackageKey.State) 仅限输出。密钥的当前验证和注册生命周期状态。
verificationToken string 仅限输出。Google 生成的唯一质询令牌。仅在状态为 DRAFT 时使用(当 CreateAndroidPackageKey 将密钥直接转换为 IN_REVIEW 时,可以忽略)。当状态为 DRAFT 时,请将此字符串嵌入到已签名 APK 中的 assets/adi-registration.properties 内,以完成 VerifyAndroidPackageKeyOwnership。
registrationJustificationRequired boolean 仅限输出。如果 true 且密钥处于 OWNERSHIP_VERIFIED 状态,您必须使用 JustifyAndroidPackageKeyRegistration 提交书面理由,然后注册才能继续进行到 IN_REVIEW。如果 CreateAndroidPackageKey 将密钥直接转换为 IN_REVIEW(因为该密钥之前已在同一 DeveloperAccount 中的另一个软件包名称上进行了验证),则会跳过理由说明。

枚举:AndroidPackageKey.State

值 说明
DRAFT 密钥资源已创建,但仍需通过上传已签名的 APK (VerifyAndroidPackageKeyOwnership) 来证明您拥有私钥,因为此密钥的所有权尚未在此 DeveloperAccount下的任何软件包名称上得到验证。
OWNERSHIP_VERIFIED 已通过上传已签名的 APK 验证私钥所有权。如果 registrationJustificationRequired 为 true,则在审核开始之前仍需要提供理由。
IN_REVIEW Google 正在审核密钥注册。密钥会在此处转换,转换时间为:CreateAndroidPackageKey 后立即转换(如果不需要所有权证明,例如,对于从未在 Android 上出现过的新软件包名称,或者密钥之前已在同一 DeveloperAccount 下的其他软件包名称上验证过,这也会跳过 JustifyAndroidPackageKeyRegistration);VerifyAndroidPackageKeyOwnership 后直接转换(如果 registrationJustificationRequired 为 false);或 JustifyAndroidPackageKeyRegistration 后转换(如果 registrationJustificationRequired 为 true)。
REGISTERED 此应用签名密钥已注册到此软件包名称,用于 Android 开发者验证。
PENDING_TRANSFER 应用签名密钥注册正在等待转移完成。

方法:AndroidPackageKey

方法 HTTP 请求 说明
CreateAndroidPackageKey POST /v1/{parent=developerAccounts/*/androidPackages/*}/keys 在 AndroidPackage 下注册新的应用签名证书 SHA-256 指纹。返回处于 DRAFT 状态的密钥(当需要使用 VerifyAndroidPackageKeyOwnership 证明所有权时),或直接返回处于 IN_REVIEW 状态的密钥(当跳过所有权验证时,例如对于从未在 Android 上出现过的新软件包名称,或已在同一 DeveloperAccount 中的其他软件包名称上验证过的密钥)。
GetAndroidPackageKey GET /v1/{name=developerAccounts/*/androidPackages/*/keys/*} 检索特定 AndroidPackageKey 的状态、指纹和验证元数据。
ListAndroidPackageKeys GET /v1/{parent=developerAccounts/*/androidPackages/*}/keys 列出在 AndroidPackage 下注册的所有 AndroidPackageKey 对象(pageSize 最多 1000,pageToken)。
VerifyAndroidPackageKeyOwnership POST /upload/v1/{name=developerAccounts/*/androidPackages/*/keys/*}:verify 上传一个已签名的最小 APK,其中包含 assets/adi-registration.properties 中的 verificationToken,以验证私钥所有权并提交准备就绪的密钥以供审核。
JustifyAndroidPackageKeyRegistration POST /v1/{name=developerAccounts/*/androidPackages/*/keys/*}:justifyAndroidPackageKeyRegistration 当 registrationJustificationRequired 为 true 时,提交额外的理由背景信息,并提交经过验证的密钥以供审核。

错误处理

当 API 请求失败时,Android 开发者管理中心 API 会返回 HTTP 4xx 或 5xx 状态代码以及标准 google.rpc.Status JSON 错误正文:

{
  "error": {
    "code": 400,
    "message": "Invalid certificate fingerprint SHA256 format.",
    "status": "INVALID_ARGUMENT",
    "details": []
  }
}

HTTP 状态代码和常见解决方法

HTTP 代码 gRPC 状态 常见原因 分辨率
400 Bad Request INVALID_ARGUMENT 缺少 Java 样式的 androidPackageId 或其无效;certificateFingerprintSha256 格式无效;CreateAndroidPackage 或 CreateAndroidPackageKey 上的 name 字段不为空;上传的 APK 未签名、已损坏、缺少 assets/adi-registration.properties、缺少匹配的 verificationToken 或使用不匹配的证书签名。 根据资源架构验证请求格式,在创建调用时省略或清空 name,并在上传前使用 apksigner verify --print-certs 和 unzip -p app-release.apk assets/adi-registration.properties 验证 APK 签名和嵌入式令牌。
400 Bad Request FAILED_PRECONDITION DeveloperAccount 具有 verificationState: NOT_VERIFIED;密钥选择违反了 AndroidPackageRegistrationPolicy (SELECT_KEY_FROM_LIST);在不符合条件的状态下调用 VerifyAndroidPackageKeyOwnership 或 JustifyAndroidPackageKeyRegistration。 在 Android 开发者管理中心内完成开发者身份验证,先检查 GetAndroidPackageRegistrationPolicy,然后检查资源的当前 state。
401 Unauthorized UNAUTHENTICATED OAuth 2.0 Bearer 访问令牌缺失、过期或无效,或者尝试使用 API 密钥或服务账号进行身份验证。 获取具有 https://www.googleapis.com/auth/androiddeveloperconsole 范围的全新用户委托 OAuth 2.0 Bearer 访问令牌。
403 Forbidden PERMISSION_DENIED 经过身份验证的用户对目标 DeveloperAccount 或 AndroidPackage 缺少权限,或者 Google Cloud 项目中未启用 Android Developer Console API。 使用 ListDeveloperAccounts 验证账号成员资格,并确保在 Google Cloud 控制台中启用了 androiddeveloperconsole.googleapis.com。
404 Not Found NOT_FOUND 指定的 DeveloperAccount、AndroidPackage 或 AndroidPackageKey 资源路径不存在。 使用 ListDeveloperAccounts、ListAndroidPackages 或 ListAndroidPackageKeys 确认资源路径。确保 {key} ID 使用不带英文冒号的小写十六进制。
409 Conflict ALREADY_EXISTS 软件包名称或 SHA-256 证书指纹已在此开发者账号或其他开发者账号下注册。 使用 GetAndroidPackage 或 GetAndroidPackageKey 检查现有注册,或使用 GetAndroidPackageRegistrationPolicy 查看历史所有权。
429 Too Many Requests RESOURCE_EXHAUSTED 超出了每个 Google Cloud 项目每天 2,000 次请求的方法级配额。 实现带抖动的指数退避算法,并避免高频轮询循环。
500/503 INTERNAL/UNAVAILABLE 暂时性后端错误或服务暂时不可用。 使用截断的指数退避算法重试幂等请求。

HTTP 请求和响应示例

将占位值(例如 ACCESS_TOKEN、1234567890、com.example.myapp 和 60e860e8...)替换为您自己的值。

1. GetDeveloperAccount

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890"

响应:

{
  "name": "developerAccounts/1234567890",
  "displayName": "Example Developer",
  "verificationState": "VERIFIED"
}

2. ListDeveloperAccounts

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts"

响应:

{
  "developerAccounts": [
    {
      "name": "developerAccounts/1234567890",
      "displayName": "Example Developer",
      "verificationState": "VERIFIED"
    }
  ]
}

3. GetAndroidPackageRegistrationPolicy

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy",
  "knownKeys": [
    {
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "justificationRequirement": "NOT_REQUIRED"
    }
  ],
  "keySelectionStrategy": "SELECT_KEY_FROM_LIST"
}

4. CreateAndroidPackage

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{"name": ""}' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?androidPackageId=com.example.myapp"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
  "packageName": "com.example.myapp",
  "state": "DRAFT",
  "registeredAppStore": false
}

5. GetAndroidPackage

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
  "packageName": "com.example.myapp",
  "state": "REGISTERED",
  "registeredAppStore": false
}

6. ListAndroidPackages

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?pageSize=100"

响应:

{
  "androidPackages": [
    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
      "packageName": "com.example.myapp",
      "state": "REGISTERED",
      "registeredAppStore": false
    }
  ],
  "nextPageToken": ""
}

7. CreateAndroidPackageKey

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{
    "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
  }' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "DRAFT",
  "verificationToken": "token_xyz987654321"
}

8. GetAndroidPackageKey

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "REGISTERED"
}

9. ListAndroidPackageKeys

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys?pageSize=100"

响应:

{
  "androidPackageKeys": [
    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "REGISTERED"
    }
  ],
  "nextPageToken": ""
}

10. VerifyAndroidPackageKeyOwnership

选项 A:单请求媒体上传

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @app-release.apk \
  "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify?uploadType=media"

选项 B:可续传上传协议(推荐用于大型 APK 或 CI/CD)

第 1 步:启动可续传上传会话并提取返回的 X-Goog-Upload-URL 标头:

curl -i -X POST \
  "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-Goog-Upload-Protocol: resumable" \
  -H "X-Goog-Upload-Command: start" \
  -H "X-Goog-Upload-Header-Content-Length: FILE_SIZE_IN_BYTES" \
  -H "X-Goog-Upload-Header-Content-Type: application/vnd.android.package-archive" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
  }'

第 2 步:将已签名的 APK 二进制文件上传到 UPLOAD_SESSION_URI 并完成会话:

curl -X PUT \
  "UPLOAD_SESSION_URI" \
  -H "Content-Length: FILE_SIZE_IN_BYTES" \
  -H "X-Goog-Upload-Offset: 0" \
  -H "X-Goog-Upload-Command: upload, finalize" \
  --data-binary "@app-release.apk"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "IN_REVIEW"
}

11. JustifyAndroidPackageKeyRegistration

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{
    "justification": "We previously distributed com.example.myapp directly from https://downloads.example.com and are migrating to our rotated production key."
  }' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:justifyAndroidPackageKeyRegistration"

响应:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "IN_REVIEW",
  "registrationJustificationRequired": true
}

其他资源