【问题标题】:How to point GOOGLE_APPLICATION_CREDENTIALS to my JSON file?如何将 GOOGLE_APPLICATION_CREDENTIALS 指向我的 JSON 文件?
【发布时间】:2020-11-29 13:33:56
【问题描述】:

我想在我的 Android 应用中使用 Google Text-to-Speech

根据documentation,我已经完成了所有这些步骤:

  1. 在 Cloud Console 中,转到创建服务帐号密钥页面。
  2. 从服务帐户列表中,选择新建服务帐户。
  3. 在服务帐户名称字段中,输入名称。
  4. 从角色列表中,选择项目 > 所有者。
  5. 单击创建。一个 JSON 文件,其中包含您下载到计算机的密钥。

我正在使用Google's code传递凭据,这是我下载的JSON文件:

public void main(String... args) throws Exception {
    // You can specify a credential file by providing a path to GoogleCredentials.
    // Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment variable.
    InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
    GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(String.valueOf(stream)))
            .createScoped(Lists.newArrayList(Collections.singleton("https://www.googleapis.com/auth/cloud-platform")));
    Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

    System.out.println("Buckets:");
    Page<Bucket> buckets = storage.list();
    for (Bucket bucket : buckets.iterateAll()) {
        System.out.println(bucket.toString());
    }
}

无论如何,我已经清理了 Gradle,重新启动了 Android Studio,但我仍然收到此日志:

java.io.IOException:应用程序默认凭据不是 可用的。如果在 Google Compute Engine 中运行,它们就可用。 否则,环境变量 GOOGLE_APPLICATION_CREDENTIALS 必须定义指向定义凭据的文件。看 https://developers.google.com/accounts/docs/application-default-credentials 了解更多信息。

我做错了什么?

更新

我意识到只有在单击按钮时才会收到此日志消息。如果我点击一个按钮,hello() 方法将运行。查看完整代码:

package ch.yourclick.kitt;

import android.os.Build;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import com.google.api.client.util.Lists;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.api.gax.paging.Page;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.texttospeech.v1.AudioConfig;
import com.google.cloud.texttospeech.v1.AudioEncoding;
import com.google.cloud.texttospeech.v1.SsmlVoiceGender;
import com.google.cloud.texttospeech.v1.SynthesisInput;
import com.google.cloud.texttospeech.v1.SynthesizeSpeechResponse;
import com.google.cloud.texttospeech.v1.TextToSpeechClient;
import com.google.cloud.texttospeech.v1.TextToSpeechSettings;
import com.google.cloud.texttospeech.v1.VoiceSelectionParams;
import com.google.protobuf.ByteString;
import androidx.annotation.RequiresApi;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
import android.os.StrictMode;
import android.view.View;

import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.BucketInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;

import ch.yourclick.kitt.ui.main.SectionsPagerAdapter;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
        ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(sectionsPagerAdapter);
        TabLayout tabs = findViewById(R.id.tabs);
        tabs.setupWithViewPager(viewPager);
        FloatingActionButton fab = findViewById(R.id.fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    public void main(String... args) throws Exception {
        // You can specify a credential file by providing a path to GoogleCredentials.
        // Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment variable.
        InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
        GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
                .createScoped(Lists.newArrayList(Collections.singleton("https://www.googleapis.com/auth/cloud-platform")));
        Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

        System.out.println("Buckets:");
        Page<Bucket> buckets = storage.list();
        for (Bucket bucket : buckets.iterateAll()) {
            System.out.println(bucket.toString());
        }
    }



    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onClick(View view) {
        int SDK_INT = android.os.Build.VERSION.SDK_INT;
        if (SDK_INT > 8)
        {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
                    .permitAll().build();
            StrictMode.setThreadPolicy(policy);

            try {
                hello();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    /** Demonstrates using the Text-to-Speech API. */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public void hello() throws Exception {
        InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
        GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
        TextToSpeechSettings textToSpeechSettings =
                TextToSpeechSettings.newBuilder()
                        .setCredentialsProvider(
                                FixedCredentialsProvider.create(credentials)
                        ).build()
                ;


        // Instantiates a client
        try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create(textToSpeechSettings)) {
            // Set the text input to be synthesized
            SynthesisInput input = SynthesisInput.newBuilder().setText("Hello, World!").build();

            // Build the voice request, select the language code ("en-US") and the ssml voice gender
            // ("neutral")
            VoiceSelectionParams voice =
                    VoiceSelectionParams.newBuilder()
                            .setLanguageCode("en-US")
                            .setSsmlGender(SsmlVoiceGender.NEUTRAL)
                            .build();

            // Select the type of audio file you want returned
            AudioConfig audioConfig =
                    AudioConfig.newBuilder().setAudioEncoding(AudioEncoding.MP3).build();

            // Perform the text-to-speech request on the text input with the selected voice parameters and
            // audio file type
            SynthesizeSpeechResponse response =
                    textToSpeechClient.synthesizeSpeech(input, voice, audioConfig);

            // Get the audio contents from the response
            ByteString audioContents = response.getAudioContent();

            // Write the response to the output file.
            try (OutputStream out = new FileOutputStream("output.mp3")) {
                out.write(audioContents.toByteArray());
                System.out.println("Audio content written to file \"output.mp3\"");
            }
        }
    }

}

依赖关系

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation group: 'io.grpc', name: 'grpc-okhttp', version: '1.0.1'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'com.google.cloud:google-cloud-storage:1.113.3'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.google.cloud:libraries-bom:4.3.0'
    implementation 'com.google.cloud:google-cloud-texttospeech:1.2.1'
    implementation 'com.google.android.gms:play-services:12.0.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

【问题讨论】:

    标签: java android google-api


    【解决方案1】:

    GoogleCredentials 类可能由于提供给它的方式而找不到有效的凭证 JSON 文件。

    请,而不是:

    InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
    GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(String.valueOf(stream)))
                .createScoped(Lists.newArrayList(Collections.singleton("https://www.googleapis.com/auth/cloud-platform")));
    

    试试:

    InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
    GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
                .createScoped(Lists.newArrayList(Collections.singleton("https://www.googleapis.com/auth/cloud-platform")));
    

    getResources().openRawResource 将为您提供所需的stream,您可以使用该stream 创建GoogleCredentials

    GoogleCredentials.fromStream(stream)
    

    关于您的更新,您似乎在创建 TextToSpeechClient 时没有提供任何明确的凭据,因此库正在环境中寻找它们。

    正如您在TechToSpeechClient javadocs 中看到的,您可以向客户端提供您的凭据。

    而不是这个:

    TextToSpeechClient textToSpeechClient = TextToSpeechClient.create()
    

    用与此类似的东西初始化您的客户端(请根据您的需要进行修改):

    import com.google.api.gax.core.FixedCredentialsProvider;
    
    // In your method...
    
    InputStream stream = getResources().openRawResource(R.raw.credential); // R.raw.credential is credential.json
    GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
    TextToSpeechSettings textToSpeechSettings =
      TextToSpeechSettings.newBuilder()
        .setCredentialsProvider(
          FixedCredentialsProvider.create(credentials)
        ).build()
    ;
    
    TextToSpeechClient textToSpeechClient =
      TextToSpeechClient.create(textToSpeechSettings);
    
    // The rest of your code
    

    请确保您的服务帐户凭据授予您访问所请求 API 的正确授权。

    事实上,正如我在您的问题中所意识到的那样,如果您将项目所有者角色授予服务帐户,则您已经拥有这些权限。在任何情况下,请小心,项目所有者角色使您可以完全控制项目中的每个资源:对于服务帐户,始终建议限制更多。理想情况下,它应该只被授予执行它所创建的操作所需的权限。

    【讨论】:

    • 我试过你的代码,但不幸的是,我得到了同样的信息。我刚刚更新了我的问题。请检查。
    • 非常感谢,该消息现已消失,但现在我收到消息 io.grpc.ManagedChannelProvider$ProviderNotFoundException: No functional channel service provider found. Try adding a dependency on the grpc-okhttp, grpc-netty, or grpc-netty-shaded artifact。这是否意味着我必须添加对 Gradle 的依赖?如果有,是哪一个?
    • 抱歉回复晚了。很好,我很高兴听到这个消息。是的,你是对的,你需要添加任何指定的依赖项。哪一个? netty 和 okhttp 都很棒,虽然我认为 netty 被广泛使用,更健壮。另一方面,okhttp 是轻量级的。在 netty 的情况下,您可以选择阴影版本、自动包含或库及其依赖项。使用另一种将取决于您的用例(请参阅例如this issue)。
    • 请注意所需的库版本,有时版本不兼容可能是导致问题的原因。请问,你可以试试吗?
    • 不客气,Reza。好的!我很高兴知道答案很有帮助!如果您需要进一步的帮助,请随时与我联系。
    猜你喜欢
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多