Android集成Google文本转语音遇凭据错误,如何配置GOOGLE_APPLICATION_CREDENTIALS?
首先,咱们来揪出导致你看到Application Default Credentials are not available错误的核心原因,再一步步修复其他潜在问题:
核心问题:缺少TTS API所需的权限作用域
你在hello()方法里加载凭据时,没有为GoogleCredentials添加Text-to-Speech API要求的权限作用域。虽然你加载了JSON密钥,但没有授权它访问TTS服务,系统就会 fallback 到寻找默认凭据,从而抛出这个误导性的错误。
修复代码:
在创建GoogleCredentials时添加作用域:
try (InputStream stream = getResources().openRawResource(R.raw.credential)) { // 添加TTS服务所需的作用域 GoogleCredentials credentials = GoogleCredentials.fromStream(stream) .createScoped(Collections.singletonList("https://www.googleapis.com/auth/cloud-platform")); // 后续的TextToSpeechSettings初始化逻辑... }
也可以用更精准的https://www.googleapis.com/auth/texttospeech作用域,效果是一样的。
其他必须修复的问题
1. 错误的文件写入路径
Android不允许直接写入根目录的output.mp3,你需要使用应用的私有存储目录:
// 获取应用私有文件目录路径 String outputPath = getFilesDir().getAbsolutePath() + "/output.mp3"; try (OutputStream out = new FileOutputStream(outputPath)) { out.write(audioContents.toByteArray()); System.out.println("音频已保存到:" + outputPath); }
如果需要写入外部存储,还要在AndroidManifest中申请WRITE_EXTERNAL_STORAGE权限(Android 10+需改用MediaStore或MANAGE_EXTERNAL_STORAGE权限)。
2. 依赖版本冲突与优化
你的依赖存在版本不兼容的问题,会导致潜在的运行时错误:
- 移除老旧的
grpc-okhttp:1.0.1,google-cloud-texttospeech会通过你已添加的libraries-bom自动引入适配的grpc版本 - 移除臃肿且过时的
com.google.android.gms:play-services:12.0.1,TTS服务不需要这个依赖 - 利用BOM统一管理依赖版本,简化gradle配置:
dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' // 用BOM管理谷歌云依赖版本 implementation platform('com.google.cloud:libraries-bom:4.3.0') implementation 'com.google.cloud:google-cloud-storage' implementation 'com.google.cloud:google-cloud-texttospeech' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' }
3. 资源流的正确关闭
用try-with-resources包裹InputStream,确保资源被正确释放,避免内存泄漏:
try (InputStream stream = getResources().openRawResource(R.raw.credential)) { // 加载凭据的逻辑 } catch (IOException e) { e.printStackTrace(); }
4. 避免在主线程执行网络操作
虽然你用StrictMode.permitAll()绕过了主线程限制,但这是不推荐的做法,会导致UI卡顿。建议把TTS调用放在异步任务中,比如用Java的AsyncTask:
private class TTSAsyncTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... voids) { try { String outputPath = getFilesDir().getAbsolutePath() + "/output.mp3"; try (InputStream stream = getResources().openRawResource(R.raw.credential)) { GoogleCredentials credentials = GoogleCredentials.fromStream(stream) .createScoped(Collections.singletonList("https://www.googleapis.com/auth/cloud-platform")); TextToSpeechSettings settings = TextToSpeechSettings.newBuilder() .setCredentialsProvider(FixedCredentialsProvider.create(credentials)).build(); try (TextToSpeechClient client = TextToSpeechClient.create(settings)) { SynthesisInput input = SynthesisInput.newBuilder().setText("Hello, World!").build(); VoiceSelectionParams voice = VoiceSelectionParams.newBuilder() .setLanguageCode("en-US") .setSsmlGender(SsmlVoiceGender.NEUTRAL) .build(); AudioConfig audioConfig = AudioConfig.newBuilder().setAudioEncoding(AudioEncoding.MP3).build(); SynthesizeSpeechResponse response = client.synthesizeSpeech(input, voice, audioConfig); try (OutputStream out = new FileOutputStream(outputPath)) { out.write(response.getAudioContent().toByteArray()); } } } return "音频生成成功:" + outputPath; } catch (Exception e) { e.printStackTrace(); return "生成失败:" + e.getMessage(); } } @Override protected void onPostExecute(String result) { // 在UI线程更新提示 Snackbar.make(findViewById(R.id.fab), result, Snackbar.LENGTH_LONG).show(); } }
然后在点击事件中调用:
@Override public void onClick(View view) { new TTSAsyncTask().execute(); }
先修复作用域的问题,这是你当前错误的根源,再逐步处理其他优化点,应该就能顺利运行Google Text-to-Speech服务了。
内容的提问来源于stack exchange,提问作者xRay




