I have been searching everywhere on the Internet for Google Translate API usage but I wasn't able find descent tutorial or explanation. So, here is what I have done:
In my Google API Console I have generated a key under Public API access with my SHA1 Fingerprint using this answer. Here is how my API console looks like:
In Android studio I build and send my request using OkHttp library with this code:
OkHttpClient client = new OkHttpClient();
String apiKey = "My API key";
String apiLangSource = "en";
String apiLangTarget = "de";
String apiWord = "Hello";
String googleApiUrl = "https://www.googleapis.com/language/translate/v2?key=" + apiKey + "&source=" + apiLangSource + "&target=" + apiLangTarget + "&q=" + apiWord;
Request request = new Request.Builder().url(googleApiUrl).build();
Log.d(TAG, "API STRING" + googleApiUrl);
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.d(TAG , "HTTP CALL FAIL");
}
#Override
public void onResponse(Response response) throws IOException {
Log.d(TAG , response.body().string());
}
});
It runs fine but on response I get:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
What is the problem here? Is my API set up correctly? Am I making the call correctly (I've seen some libraries but with guide)? Is this reasonable way of using this library? What exacty does this mean?
"There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
I think there are some demo calls available for free and this isn't the problem here.
Problem is when setting up your API key restriction for android app, you specified the package name and SHA-1 certificate fingerprint. Therefore your API key will only accept request from your app with package name and SHA-1 certificate fingerprint specified.
So how google know that request's sent FROM YOUR ANDROID APP? You MUST add your app's package name and SHA-1 in the header of each request with following keys:
Key: "X-Android-Package", value: your app package name
Key: "X-Android-Cert", value: SHA-1 certificate of your apk
FIRST, get your app SHA signature (you will need Guava library):
/**
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
*
* #param packageName Identifies the APK whose signature should be extracted.
* #return a lowercase, hex-encoded
*/
public static String getSignature(#NonNull PackageManager pm, #NonNull String packageName) {
try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures[0]);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
Then, add package name and SHA certificate signature to request header:
java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// add package name to request header
String packageName = mActivity.getPackageName();
connection.setRequestProperty("X-Android-Package", packageName);
// add SHA certificate to request header
String sig = getSignature(mActivity.getPackageManager(), packageName);
connection.setRequestProperty("X-Android-Cert", sig);
connection.setRequestMethod("POST");
// ADD YOUR REQUEST BODY HERE
// ....................
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
Hope this help! :)
Related
So I'm trying to use Google URL Shortener API in my app. Here's the class I wrote to make the HTTP call and retrieve the shortened URL.
public class GoogleUrlShortnerApi
{
//API Key from Google
private const string key = "-----------MY_KEY-----------";
public static string Shorten(string url)
{
string post = "{\"longUrl\": \"" + url + "\"}";
string shortUrl = url;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + key);
try {
request.ServicePoint.Expect100Continue = false;
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = post.Length;
request.ContentType = "application/json";
request.Headers.Add("Cache-Control", "no-cache");
using (Stream requestStream = request.GetRequestStream())
{
byte[] postBuffer = Encoding.ASCII.GetBytes(post);
requestStream.Write(postBuffer, 0, postBuffer.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader responseReader = new StreamReader(responseStream))
{
string json = responseReader.ReadToEnd();
shortUrl = Regex.Match(json, #"""id"": ?""(?<id>.+)""").Groups["id"].Value;
}
}
}
} catch (WebException webEx) {
System.Diagnostics.Debug.WriteLine (webEx.Message);
string responseText;
using(var reader = new StreamReader(webEx.Response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
}
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (ex.Message);
}
return shortUrl;
}
}
But I keep getting the "The remote server returned an error: (403) Forbidden." error.
I tried to debug and put a breakpoint on the 2nd using in the class..
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
It never goes inside that using and catches a WebException.
Can anyone give me an idea on what I'm doing wrong here?
Thank you for your time.
========================= UPDATE =========================
This is the value of the responseText from the WebException. I'm allowed to make 1,000,000 request per day. Why am I getting this error?
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
I figured it out!!
The key I created was for an Android device and it kept giving me that error.
So after realizing that it is IP issue, I created a SERVER KEY because no other key has IP option. I put the server key in my app and BOOM! it worked!
There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.
I read that as your API key is setup to be restricted by IP and your request is coming from an IP that is not registered to use that API key. Keep in mind that requests from the emulator will (most likely) have a different IP than the machine they are running on, because the Android emulator is a separate VM.
Either figure out the IP that the request is originating from and register it with your API key, or (if possible) switch the restriction to be per-Referer and handle that in your code.
I want to use Google Translate API (v2) in my android application.
What I did:
created project in Google Developers Console
set up billing for this project
generated 2 public api access keys for android applications:
a. First one that accepts request from any application
b. Second one that accepts requests from my application only
I tried to translate text from the application via
https://www.googleapis.com/language/translate/v2?key=MY-KEY&target=de&q=Hello%20world
It works fine with the key from 3a) but does not work with the key from 3b). For 3b) server sends
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
I guess this is because google server does not receive any info about my application with this request, so it cannot acquire key 3b). If so, how to send this request correctly? Or, alternatively, what I did wrong somewhere else?
If so, how to send this request correctly?
When setting up your API key restriction for android app, you specified the package name and SHA-1 certificate fingerprint. So when you send an request to Google, you MUST add these information in the header of each request.
HOW?
As answered here, you need to get your package name and SHA certificate from your code, and then adding to request header.
Get SHA certificate:
/**
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
*
* #param packageName Identifies the APK whose signature should be extracted.
* #return a lowercase, hex-encoded
*/
public static String getSignature(#NonNull PackageManager pm, #NonNull String packageName) {
try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures[0]);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
Adding to request header:
java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// add package name to request header
String packageName = mActivity.getPackageName();
connection.setRequestProperty("X-Android-Package", packageName);
// add SHA certificate to request header
String sig = getSignature(mActivity.getPackageManager(), packageName);
connection.setRequestProperty("X-Android-Cert", sig);
connection.setRequestMethod("POST");
// ADD YOUR REQUEST BODY HERE
// ....................
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
You can see full answer here.
Enjoy coding :)
I'm trying to contact the Google Books API and perform a title search, which only requires a public API key and no OAUTH2. All I get is the following error:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured"
}
],
"code": 403,
"message": "Access Not Configured"
}
}
After having googled around for hours, it seems many others have the same problem but with other Google APIs. What I've done so far:
Registered a project in my Developer Console
Enabled the Books API
Signed my application to get the SHA1 certificate number
Chosen to get a public API key for Android in my Developer Console
Pasted the following string into the public API key form, in order to get the key: "SHA1 number;com.package", without quotes
Copy pasted the generated key into my code.
The code looks as follows:
private void callGoogleBooks(){
String key = MY_KEY;
String query = "https://www.googleapis.com/books/v1/volumes?q=flowers+inauthor:keyes&key=" + key;
Log.d("google books", callApi(query));
}
public String callApi(String query){
HttpClient httpClient = new DefaultHttpClient();
HttpGet getRequest = new HttpGet(query);
HttpResponse httpResponse = null;
try{
httpResponse = httpClient.execute(getRequest);
} catch(UnsupportedEncodingException e){
Log.d("ERROR", e.getMessage());
} catch(ClientProtocolException e){
Log.d("ERROR", e.getMessage());
} catch (IOException e){
Log.d("ERROR", e.getMessage());
}
if(httpResponse != null){
try{
HttpEntity httpEntity = httpResponse.getEntity();
InputStream is = httpEntity.getContent();
BufferedReader br = new BufferedReader(
new InputStreamReader(is, "utf-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while((line = br.readLine()) != null){
sb.append(line + "\n");
}
is.close();
String responseString = sb.toString();
return responseString;
} catch (Exception e){
Log.d("ERROR", e.getMessage());
}
}
return null;
}
Are there any obvious errors? Do I need to format or package my request differently?
Do I need to add anything to the manifest file?
When specifying the package when generating the public API key, do I need to specify the same package name as in my app structure? I read somewhere that it has to be unique, but changing it to something less likely to be a duplication resulted in the same error.
The error apparently has to do with "usageLimits", but I'm not even close to 1% of the 1000 calls allowed per day in my test project.
I've also tried to implement the Google Books Java Sample without using the code above, getting the same error message. I've also tried disabling and re-enabling the Books API, without any luck.
Thanks in advance.
This worked for me
String link = "https://www.googleapis.com/books/v1/volumes?q="+params;
InputStream is = null;
try
{
int timeoutConnection = 10000;
URL url = new URL(link);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(timeoutConnection);
con.setReadTimeout(timeoutConnection);
con.setRequestProperty("key", "API_KEY");
if(con.getResponseCode() != HttpURLConnection.HTTP_OK){
publishProgress("Error conneting.");
}
is=con.getInputStream();
}
from this thread: Google Books API for Android - Access Not Configured
Problem is when setting up your API key restriction for android app, you specified the package name and SHA-1 certificate fingerprint. Therefore your API key will only accept request from your app with package name and SHA-1 certificate fingerprint specified.
So how google know that request's sent FROM YOUR ANDROID APP? You MUST add your app's package name and SHA certificate in the header of each request with following keys:
Key: "X-Android-Package", value: your app package name
Key: "X-Android-Cert", value: SHA-1 certificate of your apk
FIRST, get your app SHA signature (you will need Guava library):
/**
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
*
* #param packageName Identifies the APK whose signature should be extracted.
* #return a lowercase, hex-encoded
*/
public static String getSignature(#NonNull PackageManager pm, #NonNull String packageName) {
try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures[0]);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
Then, add package name and SHA certificate signature to request header:
java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// add package name to request header
String packageName = mActivity.getPackageName();
connection.setRequestProperty("X-Android-Package", packageName);
// add SHA certificate to request header
String sig = getSignature(mActivity.getPackageManager(), packageName);
connection.setRequestProperty("X-Android-Cert", sig);
connection.setRequestMethod("POST");
// ADD YOUR REQUEST BODY HERE
// ....................
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
Hope this help! :)
I am using google books API KEY for android to load book data via my android application. But I am getting error listed below.
However,
- The query works if I delete certificates from my API CONSOLE (e.g. make API KEY acceptable for all Applications). Though my {SHA1};{package name} information that I put is correct.
- This works if I use API KEY for browser instead.
Hence, what I can understand, I can't send KEY as a part of url in httpclient method. May be I need to send via header or something. But I can't find how.
Anybody can help please?
CODE:
String link = "https://www.googleapis.com/books/v1/volumes?key=MY_KEY&q="+query+"&projection=full&langRestrict=en&maxResults=1";
HttpGet get = new HttpGet(link);
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutConnection);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpResponse response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
Query:
https://www.googleapis.com/books/v1/volumes?key=MY_API_KEY&q=intitle:'The+Old+Man+And+The+Sea'+inauthor:'Ernest+Hemingway'&projection=full&langRestrict=en&maxResults=1
Result:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured"
}
],
"code": 403,
"message": "Access Not Configured"
}
}
For whom it may concern ... I send my API key in header, and it is now working.. I am not sure whether this is the proper way to it though ...
String link = "https://www.googleapis.com/books/v1/volumes?q="+params;
InputStream is = null;
try
{
int timeoutConnection = 10000;
URL url = new URL(link);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(timeoutConnection);
con.setReadTimeout(timeoutConnection);
con.setRequestProperty("key", "API_KEY");
if(con.getResponseCode() != HttpURLConnection.HTTP_OK){
publishProgress("Error conneting.");
}
is=con.getInputStream();
}
Supplying the key in the header is the same as not supplying a key at all. Check your developer api console and you will see no successful queries with that api key. So in short the API key in header does not solve the problem. If you don't want to play by google's rules just do the query without the key at all.
You can achieve the same result of the accepted answer using HttpGet:
String API_KEY = "..."; // Google Books API Public key
String ISBN = "...";
String bookSearchString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + ISBN;
HttpClient bookClient = new DefaultHttpClient();
try
{
//get the data
HttpGet bookGet = new HttpGet(bookSearchURL);
bookGet.addHeader("key", API_KEY);
HttpResponse bookResponse = bookClient.execute(bookGet);
StatusLine bookSearchStatus = bookResponse.getStatusLine();
if (bookSearchStatus.getStatusCode() == 200)
{
//we have a result
HttpEntity bookEntity = bookResponse.getEntity();
...
}
} catch (Exception e)
{
e.printStackTrace();
}
Note that using Google API key without restrictions is insecure way to do!
Obviously if you’re being charged for access to the API data then you don’t want someone to decompile your APK, find your API key, and then start using it in their own apps.
How to hide your API Key in Android?
But It's not enough. You can store your API key somewhere, so someone can find it too.
To secure Google cloud API key for your android app, you must restrict it to use from your app only. See here for more.
After restrict key, you must include your android app package name and SHA-1 certificate fingerprint in the header of each request you are sending to Google. How to do?
That's all you need ! :D
Running the code below I get "error" : "unauthorized_client". Need help pinpoint what I have done wrong.
I Want to use this in an Android app to enable Google Talk (xmpp is there already XABBER fork)
Reading much about how to do this and now come the Google Api Console setup.
I have chosen
- Client ID for installed applications
- Installed application type = Other
- Enabled only the Google Play Android Developer API (green switch)
I get the authentication token from oauth2:https://www.googleapis.com/auth/googletalk. (user approval screen)
What bugs me I dont enter the SHA1 fingerprint or package name for "Other" so maybe that's the problem
code:
HttpClient client1 = new DefaultHttpClient();
HttpPost request1 = new HttpPost("https://accounts.google.com/o/oauth2/token" );
request1.setHeader("Content-type", "application/x-www-form-urlencoded");
//Please make this custom with you're credentials
String requestBody1 =
"code="+authToken+
"&client_id=749825062016ia.apps.googleusercontent.com"+
"&client_secret=jQ1nUrAYUIBUf6hN5pwPE" +
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob" +
"&grant_type=authorization_code";
try {
request1.setEntity(new StringEntity(requestBody1));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
/* Checking response */
try {
HttpResponse response = client1.execute(request1);
String results = "ERROR";
results = EntityUtils.toString(response.getEntity());
LogManager.i("STACK", "Response::" + results);
} catch (IOException e) {
e.printStackTrace();
}
I think you should have registered your application with type 'Android'. Then you will be asked to provide information (such as package name and certificate) that will allow the Android platform to recognize your application.