使用 Android 开发者 ID 状态 API 检查应用注册状态

使用 Android 开发者状态 API 检查 Android 应用软件包名称是否已注册给经过验证的开发者。如果您构建软件开发工具、IDE 或自动化 CI/CD 工作流,则可以集成此服务器到服务器 API 来执行以下操作:

  • 检查应用包名称是否已注册给经过验证的开发者
  • 验证应用的签名证书 SHA-256 指纹是否与已注册软件包名称的已归档凭据相符
  • 在工具的界面中提示开发者在 Android 开发者验证程序中注册未识别的应用

此 API 旨在支持各种开发者工作流程:

使用场景 说明 API 端点
软件包名称资格要求 检查软件包名称是否已注册。如果软件包名称与任何经过验证的开发者相关联,则返回 REGISTERED;否则返回 NOT_REGISTERED CheckPackageRegistrationStatus
应用已注册 检查是否已注册特定的软件包名称和证书指纹对。如果软件包名称和证书指纹对已注册,则返回 REGISTERED;如果软件包名称和证书指纹对未注册,则返回 NOT_REGISTERED;如果软件包名称已注册,但使用的是其他证书指纹,则返回 REGISTERED_WITH_ANOTHER_CERTIFICATE_FINGERPRINT CheckPackageRegistrationStatus

本指南介绍了如何完成以下任务:

  1. 设置 Google Cloud API 访问权限和身份验证。
  2. 验证应用软件包名称和公共证书 SHA-256 指纹对是否已由经过验证的开发者通过所提供的公共证书 SHA-256 指纹或其他公共证书 SHA-256 指纹向 Android 开发者验证计划注册。
  3. 在 IDE 或开发者工具工作流程中处理 API 注册状态。

前提条件

本文档适用于 Android 应用开发者或软件开发工具开发者。在开始之前,您应该具备以下条件:

  • 对 Google Cloud 项目的管理员访问权限。
  • 对 RESTful API、JSON 和 SHA-256 证书指纹有基本的了解。

您还应熟悉以下术语:

术语 定义
Android 开发者验证 Android 开发者验证是一项新要求,旨在将现实世界中的实体(个人和组织)与其 Android 应用相关联。Android 将要求所有应用都必须由经过验证的开发者注册,才可供用户在已获认证的 Android 设备上安装。
证书指纹 用于对应用进行签名的公共证书的 SHA-256 哈希。
注册状态 API 针对应用的软件包名称或应用的软件包名称与公钥证书 SHA-256 指纹对返回的状态。此状态决定了您必须采取的操作(例如,REGISTEREDNOT_REGISTERED)。

服务端点

服务端点是一个基础网址,指定了 API 服务的网络地址。此服务具有以下服务端点,所有 URI 都与此服务端点相关:

https://androiddeveloperidstatus.googleapis.com

启用 API

如需使用 Android 开发者 ID 状态 API,您必须完成设置步骤,以创建项目并启用该 API。

创建 Google Cloud 项目

  1. 如果您还没有 Google Cloud 账号,请创建一个。
  2. 打开 Google Cloud Console
  3. 创建 Google Cloud 项目

在项目中启用 API

  1. 在 Google Cloud 控制台中,前往 API 和服务 > 库
  2. 从下拉菜单中选择您的项目。
  3. 搜索 Android Developer ID Status API
  4. 点击启用

身份验证

该 API 支持 API 密钥凭据。要获取 API 密钥,请执行以下操作:

  1. 在 Google Cloud 控制台中,依次前往 API 和服务 > 凭据
  2. 点击 + 创建凭据,然后选择 API 密钥
  3. 配置密钥并复制。在请求标头中使用此密钥。

查看应用注册状态

您可以查询 PackageRegistrationStatus 资源来单独验证软件包名称,也可以检查与特定证书指纹配对的软件包名称。

检查软件包名称

如需检查某个应用软件包名称是否已由任何经过验证的开发者注册,请向 packageRegistrationStatus:check 端点发出经过身份验证的 GET 请求,其中包含 Android 应用的软件包名称(例如 com.example.app),但不包含可选参数:

请求

curl -X GET "https://androiddeveloperidstatus.googleapis.com/v1/packages/com.example.app/packageRegistrationStatus:check" \
  -H "X-Goog-Api-Key: [key]"

结果

回答(已注册)

如果软件包名称已注册,您将收到以下 HTTP 响应正文,其中包含 HTTP 响应代码 200

{
  "name": "packages/com.example.app/packageRegistrationStatus",
  "state": "REGISTERED"
}

推荐措施:告知开发者该软件包名称已被注册。

回答(未注册)

如果未注册软件包名称,您将收到以下 HTTP 响应正文,其中包含 HTTP 响应代码 200

{
  "name": "packages/com.example.app/packageRegistrationStatus",
  "state": "NOT_REGISTERED"
}

验证软件包名称和证书指纹对

如需检查应用软件包名称是否已注册为具有特定的公开证书 SHA-256 指纹,请传递 certificateFingerprint 查询参数:

请求

curl -X GET "https://androiddeveloperidstatus.googleapis.com/v1/packages/com.example.app/packageRegistrationStatus:check?certificateFingerprint=d6ac89ed1d0a805aad4b087d06d5f41645b814480b133fbc867ef7498d069e06" \
  -H "X-Goog-Api-Key: [key]"

结果

响应(已注册,且证书指纹匹配)

如果软件包名称已注册,并使用了提供的公钥证书 SHA-256 指纹,您将收到以下 HTTP 响应正文,其中包含 HTTP 响应代码 200

{
  "name": "packages/com.example.app/packageRegistrationStatus",
  "state": "REGISTERED"
}

响应(已注册,但证书指纹不同)

如果软件包名称注册时使用的证书 SHA-256 指纹与提供的指纹不同,您将收到以下 HTTP 响应正文,其中包含 HTTP 响应代码 200

{
  "name": "packages/com.example.app/packageRegistrationStatus",
  "state": "REGISTERED_WITH_ANOTHER_CERTIFICATE_FINGERPRINT"
}

回答(未注册)

如果软件包名称未注册到所提供的公钥证书 SHA-256 指纹,您将收到以下 HTTP 响应正文,其中包含 HTTP 响应代码 200

{
  "name": "packages/com.example.app/packageRegistrationStatus",
  "state": "NOT_REGISTERED"
}

Java 实现示例

以下 Java 类演示了如何使用 Java 11 的标准 HttpClient 调用 API。

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class DeveloperIdStatusClient {

  private static final String API_ENDPOINT = "https://androiddeveloperidstatus.googleapis.com";

  public static void main(String[] args) {
    String apiKey = "YOUR_API_KEY";
    String packageName = "com.example.app";
    String certificateFingerprint = "d6ac89ed1d0a805aad4b087d06d5f41645b814480b133fbc867ef7498d069e06";

    try {
      String response = checkPackageRegistrationStatus(apiKey, packageName, certificateFingerprint);
      System.out.println("Response: " + response);
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  /**
   *   Checks the registration status of an Android package.
   *
   *   @param apiKey The Google API key for authentication.
   *   @param packageName The fully-qualified Android package name (for example, "com.example.app").
   *   @param certificateFingerprint Optional SHA-256 certificate fingerprint. Pass null or empty to omit.
   *   @return The JSON response string from the API.
   */
  public static String checkPackageRegistrationStatus(
      String apiKey, String packageName, String certificateFingerprint)
      throws IOException, InterruptedException {

    // 1. Build the URL path (accepts dots directly)
    // Format: /v1/packages/{package}/packageRegistrationStatus:check
    String path = String.format("/v1/packages/%s/packageRegistrationStatus:check", packageName);

    // 2. Build query parameters (only certificateFingerprint if provided)
    StringBuilder queryBuilder = new StringBuilder();
    if (certificateFingerprint != null && !certificateFingerprint.isEmpty()) {
      queryBuilder.append("certificateFingerprint=")
          .append(URLEncoder.encode(certificateFingerprint, StandardCharsets.UTF_8));
    }

    String fullUrl = API_ENDPOINT + path;
    if (queryBuilder.length() > 0) {
      fullUrl += "?" + queryBuilder.toString();
    }

    // 3. Create and send the HTTP GET request with API Key header
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(fullUrl))
        .header("Accept", "application/json")
        .header("X-Goog-Api-Key", apiKey)
        .GET()
        .build();

    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

    if (response.statusCode() != 200) {
      throw new IOException("Unexpected response code: " + response.statusCode() + ", body: " + response.body());
    }

    return response.body();
  }
}

了解注册状态和错误处理

当 API 请求失败时,Android 开发者 ID 状态 API 会在响应正文中返回标准 Google Cloud JSON 错误对象。此对象提供了一致的结构,以便了解和处理错误。

错误响应示例:

{
  "error": {
    "code": 400,
    "message": "Request contains an invalid argument.",
    "status": "INVALID_ARGUMENT"
  }
}

错误对象包含以下关键字段:

  • code:HTTP 状态代码(例如 400403500)。
  • message:面向开发者的英文错误说明。此消息不稳定,可能会发生变化,因此请勿围绕此消息构建解析逻辑。
  • status:以程序化方式标识错误类型的规范错误代码(例如 INVALID_ARGUMENTPERMISSION_DENIED)。您的错误处理逻辑应基于此稳定标识符构建。

下表列出了 API 返回的最常见错误以及建议的应对措施。

HTTP 状态 规范错误代码 (status) 含义和常见原因 推荐措施 可以重试吗?
400 Bad Request INVALID_ARGUMENT 请求格式不正确。 不重试。检查错误响应中的“details”字段,以确定具体字段违规情况。更正请求载荷,然后重新发送。
401 Unauthorized UNAUTHENTICATED 访问令牌缺失、已过期或无效。 不立即重试。确保您使用的是正确的访问令牌或密钥。
403 Forbidden PERMISSION_DENIED 您已通过身份验证,但您的项目无权访问该 API。最常见的原因是您尚未在 Google Cloud 项目中启用该 API。 不重试。验证您使用的是正确的项目 ID,并且该 API 已启用。
429 请求过多 RESOURCE_EXHAUSTED 您已超出项目的 API 配额。 停止发送请求,并在延迟后重试。在 Google Cloud 控制台中查看项目的配额。
500 内部服务器错误 INTERNAL Google 服务器上发生了意外错误。 这很可能是暂时性问题。使用指数退避算法策略重试请求。如果错误仍然存在,请与支持团队联系。
503 Service Unavailable UNAVAILABLE 该服务暂不可用。 使用指数退避算法策略重试请求。

配额限制

为了确保服务可靠性,系统会按项目强制执行使用配额。

API 方法 默认限额(每个项目) 备注
CheckPackageRegistrationStatus 每天 1000 个请求 调用方需要管理内部速率限制,以防止滥用。

监控您的用量

您可以在 Google Cloud 控制台中直接监控项目的当前 API 用量,并了解剩余的配额。

  1. 前往 API 和服务 > 信息中心页面。
  2. 选择 Android 开发者 ID 状态 API。
  3. 点击配额标签。

此信息中心详细显示了您的请求量随时间的变化情况。