Reputation: 533
I've managed to get Google Cloud Speech working for my Android app using a service account in streaming mode via GRPC. However, according to what I've read, I shouldn't deploy an Android app with these credentials in them (currently stored as a JSON file in a resource) for security reasons. The correct thing is to create an API key, as described here: https://cloud.google.com/speech/docs/common/auth
This allows me to restrict access to my specific Android app. However, I have been unable to find out how to use the API Key from GRPC. I'm currently creating a GoogleCredentials
instance from the JSON file, and this works fine. How can I get a credentials object from the API Key?
Upvotes: 4
Views: 1772
Reputation: 1174
Here is how to do this in Kotlin. Including how to pass package and signature for a restricted key.
private fun signatureDigest(sig: android.content.pm.Signature): String? {
val signature: ByteArray = sig.toByteArray()
return try {
val md: MessageDigest = MessageDigest.getInstance("SHA1")
val digest: ByteArray = md.digest(signature)
BaseEncoding.base16().lowerCase().encode(digest)
} catch (e: NoSuchAlgorithmException) {
null
}
}
fun getSignature(pm: PackageManager, packageName: String?): String? {
return try {
val packageInfo: PackageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
if (packageInfo == null || packageInfo.signatures == null || packageInfo.signatures.size === 0 || packageInfo.signatures.get(0) == null) {
null
} else signatureDigest(packageInfo.signatures.get(0))
} catch (e: PackageManager.NameNotFoundException) {
null
}
}
private fun createConnection() {
val packageName: String = mActivity.packageName
val signature = getSignature(mActivity.packageManager, packageName)
val API_KEY = Metadata.Key.of("X-Goog-Api-Key", Metadata.ASCII_STRING_MARSHALLER)
val BUNDLE = Metadata.Key.of("X-Android-Package", Metadata.ASCII_STRING_MARSHALLER)
val SIGN = Metadata.Key.of("X-Android-Cert", Metadata.ASCII_STRING_MARSHALLER)
val apiKeyMetadata = Metadata()
apiKeyMetadata.put(API_KEY, "YOUR_API_KEY")
apiKeyMetadata.put(BUNDLE, packageName)
apiKeyMetadata.put(SIGN, signature)
val channel = OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(DnsNameResolverProvider())
.intercept(MetadataUtils.newAttachHeadersInterceptor(apiKeyMetadata))
.build()
mApi = SpeechGrpc.newStub(channel)
}
Upvotes: 1
Reputation: 81
you can try this with the API key
Metadata.Key<String> API_KEY = Metadata.Key.of("x-goog-api-key", Metadata.ASCII_STRING_MARSHALLER);
Metadata apiKeyMetadata = new Metadata();
apiKeyMetadata.put(API_KEY, yourApiKey);
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(MetadataUtils.newAttachHeadersInterceptor(apiKeyMetadata))
.build();
speechStub = SpeechGrpc.newStub(channel);
Upvotes: 8
Reputation: 11
I cannot find any Android example. However, the sample iOS client sets up a gRPC connection using the API key. It puts the key in the request header. You can try translating the iOS code into Android.
Upvotes: 1
Reputation: 6144
Once you have the access token, you can use this method:
final GoogleCredentials googleCredentials = new GoogleCredentials(accessToken) {
@Override
public AccessToken refreshAccessToken() throws IOException {
return accessToken;
}
}.createScoped(OAUTH2_SCOPES);
You need to override the refreshAccessToken()
as it's currently not supported.
Upvotes: 0