You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android端Google Cloud Vision API授权方法及代码异常求助

Android端Google Cloud Vision API授权与代码异常排查

我来帮你梳理Android端Google Cloud Vision API的授权步骤,以及排查你代码里可能出现的问题:

一、先搞定API授权配置

1. 云项目与API启用

首先得在Google Cloud控制台创建项目,找到Cloud Vision API并启用它。然后生成服务账号密钥(JSON格式),把这个密钥文件放到你Android项目的app/src/main/res/raw目录下,文件名尽量简单,比如vision_cred.json

2. 依赖与编译配置

在app模块的build.gradle里添加必要的依赖:

implementation 'com.google.cloud:google-cloud-vision:2.3.2'
implementation 'com.google.auth:google-auth-library-oauth2-http:1.10.0'

同时要开启Java 8支持,不然会有编译错误:

android {
    // ...其他配置
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

3. 本地加载授权凭证

测试阶段可以这样加载密钥(注意:生产环境绝对不要这么做!客户端存密钥会被反编译窃取,生产建议用后端代理API):

private GoogleCredentials getVisionCredentials(Context context) throws IOException {
    InputStream credStream = context.getResources().openRawResource(R.raw.vision_cred);
    return GoogleCredentials.fromStream(credStream)
            .createScoped(Collections.singletonList("https://www.googleapis.com/auth/cloud-vision"));
}

二、你的代码异常排查

从你给出的截断代码来看,大概率是请求构建不完整、客户端初始化错误或者AsyncTask的使用问题,一步步来:

1. 补全请求构建逻辑

你代码里只写到了Bitmap转字节数组,完整的AnnotateImageRequest构建应该是这样:

// 你的现有代码
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
byte[] bitmapData = bos.toByteArray();

// 补全部分
Image image = Image.newBuilder()
        .setContent(ByteString.copyFrom(bitmapData))
        .build();
// 选择你需要的检测类型,比如标签检测、文字识别等
Feature feature = Feature.newBuilder()
        .setType(Feature.Type.LABEL_DETECTION)
        .build();
AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
        .addFeatures(feature)
        .setImage(image)
        .build();
requests.add(request);

如果这部分没写完,API调用肯定会失败。

2. 正确初始化Vision客户端

要用上我们前面加载的凭证,初始化客户端并调用API:

@Override
protected String doInBackground(Object... params) {
    try {
        // 前面的请求构建代码...
        
        // 初始化客户端
        ImageAnnotatorSettings settings = ImageAnnotatorSettings.newBuilder()
                .setCredentialsProvider(FixedCredentialsProvider.create(getVisionCredentials(getApplicationContext())))
                .build();
        
        try (ImageAnnotatorClient client = ImageAnnotatorClient.create(settings)) {
            BatchAnnotateImagesResponse response = client.batchAnnotateImages(requests);
            List<AnnotateImageResponse> responses = response.getResponsesList();
            
            // 处理返回结果,这里以标签检测为例
            StringBuilder resultStr = new StringBuilder();
            for (AnnotateImageResponse res : responses) {
                if (res.hasError()) {
                    resultStr.append("API错误: ").append(res.getError().getMessage()).append("\n");
                    continue;
                }
                for (EntityAnnotation annotation : res.getLabelAnnotationsList()) {
                    resultStr.append(String.format("可信度%.2f: %s\n", annotation.getScore(), annotation.getDescription()));
                }
            }
            return resultStr.toString();
        }
    } catch (Exception e) {
        e.printStackTrace();
        return "请求失败: " + e.getMessage();
    }
}

3. AsyncTask的坑

注意AsyncTask在Android 11及以上已经被废弃了,而且你的内部类写法可能导致内存泄漏(持有Activity的强引用)。建议改用Coroutine或者ExecutorService,如果暂时要继续用,改成静态内部类+弱引用:

private static class VisionTask extends AsyncTask<Object, Void, String> {
    private WeakReference<Context> contextRef;
    
    public VisionTask(Context context) {
        contextRef = new WeakReference<>(context);
    }
    
    @Override
    protected String doInBackground(Object... params) {
        Context context = contextRef.get();
        if (context == null) return "上下文已失效";
        // 后面的逻辑...
    }
}

4. 其他必要检查

  • 确保AndroidManifest.xml添加了网络权限:
    <uses-permission android:name="android.permission.INTERNET" />
    
  • 如果开启了混淆,在proguard-rules.pro里添加规则,避免Google Cloud的类被混淆:
    -keep class com.google.cloud.** { *; }
    -keep class com.google.auth.** { *; }
    

最后提醒

生产环境绝对不要把服务账号密钥放在客户端!建议搭建自己的后端服务,客户端调用后端接口,后端再去调用Google Cloud Vision API,这样能避免密钥泄露。

内容的提问来源于stack exchange,提问作者Raja

火山引擎 最新活动