You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

限制YouTube API_KEY仅用于Android应用时遇403错误求助

YouTube API密钥限制Android应用后触发403错误的排查与解决

已执行操作

  • 配置API密钥限制:在API密钥编辑页面选择「Android应用」,设置包名与调试指纹
    • 包名与AndroidManifest.xml完全一致:
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      package="com.xxxxxx.yyyyyy">
      
    • 代码中指定应用名称:
      public YouTube getYouTubeService() throws GeneralSecurityException, IOException {
          return new YouTube.Builder(GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, null)
                  .setApplicationName("com.xxxxxx.yyyyyy")
                  .build();
      }
      
  • 获取调试指纹:通过命令提取调试密钥库的SHA-1指纹
    keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
    
  • 验证指纹一致性:编写方法获取当前应用签名的SHA-1指纹,确认与API控制台配置一致
    public String getSHA1Fingerprint() {
        try {
            PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
            for (Signature signature : info.signatures) {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                md.update(signature.toByteArray());
                byte[] digest = md.digest();
    
                // 转换为带冒号的十六进制格式
                StringBuilder hexString = new StringBuilder();
                for (int i = 0; i < digest.length; i++) {
                    if (i > 0) {
                        hexString.append(":");
                    }
                    String hex = Integer.toHexString(0xFF & digest[i]);
                    if (hex.length() == 1) {
                        hexString.append("0"); // 补前导零
                    }
                    hexString.append(hex);
                }
                return hexString.toString().toUpperCase();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

问题现象

确认API控制台的包名、指纹与应用完全匹配,但设置限制后调用YouTube接口触发403错误,移除限制则正常调用。错误详情:

GET https://youtube.googleapis.com/youtube/v3/channels?id=xxxxxxxxxxxxx&key=yyyyyyyyyyyyyyyyyyyyyy&part=contentDetails
{
  "code": 403,
  "details": [
    {
      "@type": "type.googleapis.com/google.rpc.ErrorInfo",
      "reason": "API_KEY_ANDROID_APP_BLOCKED",
      "domain": "googleapis.com",
      "metadata": {
        "service": "youtube.googleapis.com",
        "consumer": "projects/1063253415806"
      }
    }
  ],
  "errors": [
    {
      "domain": "global",
      "message": "Requests from this Android client application <empty> are blocked.",
      "reason": "forbidden"
    }
  ],
  "message": "Requests from this Android client application <empty> are blocked.",
  "status": "PERMISSION_DENIED"
}

解决方案

错误信息中Android client application <empty>表明请求未携带应用的包名与签名验证信息——YouTube Data API的Java客户端库不会自动添加Android应用的验证头,需手动在请求中加入X-Android-Package和X-Android-Cert头:

修改后的代码

public YouTube getYouTubeService() throws GeneralSecurityException, IOException {
    String sha1Fingerprint = getSHA1Fingerprint();
    String packageName = getPackageName();

    return new YouTube.Builder(GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, new HttpRequestInitializer() {
        @Override
        public void initialize(HttpRequest request) throws IOException {
            // 添加Android验证头
            request.getHeaders().set("X-Android-Package", packageName);
            request.getHeaders().set("X-Android-Cert", sha1Fingerprint.replace(":", "")); // 必须去掉指纹中的冒号
        }
    })
            .setApplicationName(packageName)
            .build();
}

关键注意事项

  • X-Android-Cert的值需为去掉冒号的SHA-1指纹,大小写与API控制台配置一致即可
  • 测试release包时,需在API控制台添加正式签名密钥库的SHA-1指纹
  • 确保getSHA1Fingerprint()获取的是当前运行应用的签名指纹(debug包用debug密钥库,release包用正式密钥库)

内容的提问来源于stack exchange,提问作者Fabio R Lopes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:57:32