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.
Related
I know how it can be done for Google Play Store (answer here), but i didn't manage to find a way for AppGallery.
Thank you!
UPDATE #1
Using the answer below i partially solve this with this steps:
Make an API Client with Administrator role, it also works with App Administrator and Operations. (documentaion here: API Client)
Get the access token. (documentaion here: Obtaining a Token)
Get app info. (documentaion here: Querying App Information)
The response from the Querying App Information, have a lot of informations about the app including "versionNumber", but for me it doesn't provide the "versionNumber" (the single info i needed), because this parameter is optional. And now i am stuck again, because i don't understand what i need to change in order to receive this one.
If anyone knows how I can solve this, thank you very much for your help.
UPDATE #2
#shirley's comment was right.
The issue has been fixed in their latest release, and it has been released this month.
You can call the Querying App Information API (GET mode) to query the app details:
public static void getAppInfo(String domain, String clientId, String token, String appId, String lang) {
HttpGet get = new HttpGet(domain + "/publish/v2/app-info?appid=" + appId + "&lang=" + lang);
get.setHeader("Authorization", "Bearer " + token);
get.setHeader("client_id", clientId);
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse httpResponse = httpClient.execute(get);
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
BufferedReader br =
new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), Consts.UTF_8));
String result = br.readLine();
// Object returned by the app information query API, which can be received using the AppInfo object. For details, please refer to the API reference.
JSONObject object = JSON.parseObject(result);
System.out.println(object.get("ret"));
}
} catch (Exception e) {
}
}
They are mentioned here: Completing App Information, Querying App Information.
I am trying to create a image upload module Using Imgur API
I have just got Client ID and Client Secret after registration. When it comes to the implementation and testing, it fails and gives the following response in the logcat
The Logcat response
{"data":{"error":"We're really sorry, but
anonymous uploading in your country has
been disabled. Please <a href=\"\/register\">register
for an account<\/a> and try uploading again.","request":"\/3\/upload.json","method":"POST"}
,"success":false,"status":400}
The below is my code
public String uploadToImgur(File uploadFile) {
DefaultHttpClient defaulthttpclient;
HttpPost httppost;
MultipartEntity multipartentity;
String path = uploadFile.getAbsolutePath().toString();
String s;
defaulthttpclient = new DefaultHttpClient();
String targetURL = "https://api.imgur.com/3/upload.json";
String apikey = "client_secret";
httppost = new HttpPost(targetURL);
httppost.setHeader("User-Agent", USER_AGENT);
httppost.addHeader("Authorization", "Client-ID {client)_id}");
multipartentity = new MultipartEntity();
s = path.substring(1 + path.lastIndexOf("."));
if (s.lastIndexOf("jpg") >= 0)
{
s = "jpeg";
}
try
{
multipartentity.addPart("image", new FileBody(new File(path), (new StringBuilder("image/")).append(s).toString()));
multipartentity.addPart("key", new StringBody(apikey));
httppost.setEntity(multipartentity);
String s1 = EntityUtils.toString(defaulthttpclient.execute(httppost).getEntity());
Log.d("outpur" , s1);
if (s1.lastIndexOf("<original>") >= 0 && s1.indexOf("</original>") >= 0)
{
return (new StringBuilder("[img]")).append(s1.substring(10 + s1.lastIndexOf("<original>"), s1.indexOf("</original>"))).append("[/img]").toString();
}
}
catch (Exception exception)
{
return "ERRor";
}
return "Error";
}
Would you please tell me what is the better way to enhance the upload module ?
Registration and sending client id is not good enough for non anonymous uploads. The documentation tells you to use oAuth and get a token that needs to be passed for such requests.
Authentication
The API requires each client to use OAuth 2 authentication. This means you'll have to register your application, and generate an access_code if you'd like to log in as a user.
For public read-only and anonymous resources, such as getting image info, looking up user comments, etc. all you need to do is send an authorization header with your client_id in your requests. This also works if you'd like to upload images anonymously (without the image being tied to an account), or if you'd like to create an anonymous album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
For accessing a user's account, please visit the OAuth2 section of the docs
I am working on an android application that needs to print to a printer. I decided on using the Google Cloud Print, as it seemed easy to set up. Initially, I followed the steps found here for integrating into Android. This works, as in it will print to my desired printer. However, this process is a bit involved for the user. In my case, the process is as follows:
The user selects the print button that I have displayed next to some information.
A Dialog is shown with a preview of what will be printed. There is a button in the ActionBar that says "Print". This begins the process.
A new Activity is displayed showing a list of printers that are connected to that users Google Account. The user must select one.
A new page is shown giving a description of the print job.
The user has to select "Print" in the upper right hand corner.
The print job is started and the printer prints out the picture.
Unfortunately, my client does not want this process. They want the user to click "Print" in step two, and then have the picture printed (steps 1, 2 and 6). Thus, I cannot use Intent provided by Google, I must use the actual API. This requires me to get a Google Auth token, get the desired printer, and submit a print job that way. I do the following:
Use the Google Play Services to retrieve an OAuth token for the users Gmail account.
Get a list of printers using the /search API call.
Submit a print job using the /submit API call.
I have the first two finished. I am just having trouble with the actual printing of the picture. Instead of printing the picture, the byte data of the picture is being printed (Base64 encoded). Here is some code as to how I am sending up the request:
ContentResolver contentResolver = context.getContentResolver();
try {
InputStream is = contentResolver.openInputStream(uri);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = is.read(buffer);
while (n >= 0) {
baos.write(buffer, 0, n);
n = is.read(buffer);
}
is.close();
baos.flush();
content = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + uri.toString(), e);
} catch (IOException e) {
e.printStackTrace();
}
This code retrieves the picture (the variable "uri" is the URI of that file), and turns it into a Base64 encoded string. This is the same method used in the PrintDialogActivity that is provided on the Google Cloud Print page (linked to above). The following is how I send that up:
URL: http://www.google.com/cloudprint/submit?access_token=[AUTH_TOKEN_GOES_HERE]&cookies=false&printerid=[PRINTER_ID_HERE]
HTTP Method: POST
POST Parameters: [printerId=PRINTER_ID_HERE, title=TestPrint, contentType=image/jpeg, capabilities={"capabilities":[{}]}, content=[Base64 Encoded data string is placed here]]
As far as I can tell, this is how it is supposed to be. I am getting a response of {"success":true} when printing. But, as I said above, it prints out the actual Base64 data string. Any help would be appreciated.
EDIT: Using what powerje said below, I managed to fix this. Rather than using the code above, I used the following:
public void submitPrintJobWithFile(String printerId, String title, String token, String filePath, String contentType){
File file = new File(filePath);
// Method that gets the correct headers
List<Header> headers = getHeaders(contentType, token);
// Method that gets the correct post parameters
String url = CLOUDPRINT_URL + PATH_SUBMIT;
List<NameValuePair> postParams = getParams(title, contentType);
String params = "access_token=" + token + "&cookies=false" + "&printerid=" + printerId;
url += params;
response = sendMultipartData(url, file, postParams, headers);
}
private String sendMultipartData(String url, File file, List<NameValuePair> fields, List<Header> headers){
HttpPost post = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
for(NameValuePair pair : fields){
String name = pair.getName();
String value = pair.getValue();
try{
entity.addPart(name, new StringBody(value));
}catch (UnsupportedEncodingException e){
Log.d(TAG, "Error turning pair (name=" + name + ", value=" + value + ") into StringBody.");
}
entity.addPart("content", new FileBody(file));
post.setEntity(entity);
// Finish HttpClient request here...
}
It looks like you need to use multipart encoding, example here:
http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/
FTA:
The files needed are apache-mime4j, httpclient, httpcore and httpmime. All are opensource projects built by the Apache foundation.
Download the 4 files and add them to your project then you should be able to use the following code to post strings and files to pages.
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.tumblr.com/api/write");
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("type", new StringBody("photo"));
entity.addPart("data", new FileBody(image));
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
The image variable in this case is a File that contains an image captured by the camera on the phone.
Looking at the Python Sample Code SubmitJob method it seems that only the PDF typs needs to be encoded in Base64.
Answering the question with a bit of an update. As of October 2013, in 4.4 and the support library, there are built in methods to handle printing. See the following documentation for how to do it properly:
PrintHelper - The support Library class to help with printing Bitmaps.
DevBytes: Android 4.4 Printing API - An Android Developers video detailing the APIs
Printing Content - An Android Training guide on how to use these APIs.
I am new to Facebook API. Trying the FQL Query from the Graph API for the first time using this link.
I am trying to get photos from the album with the album id. When I request using Facebook object with https://graph.facebook.com/10150146071791729/photos&access_token=ACCESS_TOKEN URL, I am getting the following response (before parsing to JSON object). {"id":"https://graph.facebook.com/10150146071791729/photos","shares":2}. And I confirmed it by printing the length of the JSON object after parsing, which is 2. When I copy and paste the same URL in the web browser, I am getting the expected response (the response in FQL Query I got). Here is my code.
public void onComplete(Bundle values) {
String token = facebook.getAccessToken();
System.out.println("Token: " + token);
try {
String response = facebook.request("https://graph.facebook.com/10150146071791729/photos&access_token=ACCESS_TOKEN");
System.out.println("response :"+response);
JSONObject obj = Util.parseJson(response);
System.out.println("obj length : " + obj.length());
Iterator iterator = obj.keys();
while(iterator.hasNext()){
String s = (String)iterator.next();
System.out.println(""+s+" : "+obj.getString(s));
}
} catch (Throwable e) {
e.printStackTrace();
}
}
Note: I got access token from the FQL Query which is used in the URL. And I did not wrote any session (login/logout) logic as it is a test project.
Your request is wrong. It should be
"https://graph.facebook.com/10150146071791729/photos?access_token=ACCESS_TOKEN"
Replace the '&' after the photos with a '?'.
Two more things, you're making a Graph API query, not an FQL one.
Second, NEVER post your access tokens publicly. If I wanted to, I can now use your access token to edit your facebook information.
EDIT: When you use the Android Facebook SDK, you do not need to use the full graph path. Instead, use
facebook.request("10150146071791729/photos")
You do not need to add the access token as the Facebook object already has it. Hope this helps.
Because not much code has been provided except for the most relevant one, let me give you a couple of ways you can access Photos from an Album
FIRST METHOD (IF your wish to use the complete URL to make the request)
String URL = "https://graph.facebook.com/" + YOUR_ALBUM_ID
+ "/photos&access_token="
+ Utility.mFacebook.getAccessToken() + "?limit=10";
try {
HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet(URL);
HttpResponse rp = hc.execute(get);
if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String queryPhotos = EntityUtils.toString(rp.getEntity());
Log.e("PHOTOS RESULT", queryPhotos);
}
} catch (Exception e) {
e.printStackTrace();
}
SECOND METHOD (Without using the complete URL as #Vinay Shenoy mentioned earlier)
try {
Bundle paramUserInfo = new Bundle();
paramUserInfo.putString(Facebook.TOKEN, Utility.mFacebook.getAccessToken());
String resultPhotos = Utility.mFacebook.request("YOUR_ALBUM_ID/photos", paramUserInfo, "GET");
Log.e("PHOTOS", resultPhotos);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
On a personal note, I follow the first method almost entirely through my application. It lets me using the Paging for endless ListViews
That being said, when I need some quick data in between somewhere, I do rely on the second method. Both of them work and I hope either (or both) of them helps you.
I'm trying to write application for Android to access Google Tasks. I decided to use ClientLogin authorization method.
I'm getting ClientLogin "Auth" marker from first POST request. Then i try to retrieve a user's task lists with GET request. I wrote the following code for this:
String requestString = "https://www.googleapis.com/tasks/v1/users/#me/lists";
String resultString = "";
try {
URLConnection connection1 = null;
URL url = new URL(requestString);
connection1 = url.openConnection( );
HttpURLConnection httpsConnection1 = (HttpURLConnection)connection1;
httpsConnection1.setRequestMethod("GET");
httpsConnection1.setRequestProperty("Authorization", "GoogleLogin auth="+authkeyString);
httpsConnection1.setDoInput(true);
httpsConnection1.connect();
int responseCode = httpsConnection1.getResponseCode();
System.out.println(responseCode);
if (responseCode == HttpsURLConnection.HTTP_OK) {
InputStream in = httpsConnection1.getInputStream();
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
StringBuffer data = new StringBuffer();
int c;
while ((c = isr.read()) != -1){
data.append((char) c);
}
resultString = new String (data.toString());
}
else{
resultString = "Errror - connection problem";
}
}
httpsConnection1.disconnect();
}
catch (MalformedURLException e) {
resultString = "MalformedURLException1:" + e.getMessage();
}
catch (IOException e) {
resultString = "IOException1:" + e.getMessage();
}
Here is "authkeyString" - string variable with authorization marker.
When i run application under real Android device i receive: "IOException:SSL handshake failure: Failure is ssl library, usually a protocol error ..... "
Also i tried to run this code from simple java application from desktop:
Exception in thread "main" java.lang.IllegalArgumentException: Illegal character(s) in message header value: GoogleLogin auth=DQ ..... UT
at sun.net.www.protocol.http.HttpURLConnection.checkMessageHeader(HttpURLConnection.java:428)
at sun.net.www.protocol.http.HttpURLConnection.isExternalMessageHeaderAllowed(HttpURLConnection.java:394)
at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:2378)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:296)
at Tasks.main(Tasks.java:81)
ClientLogin with username / password
If you want to use ClientLogin with the Google APIs Client Library for Java , you'll need to setup a HttpRequestFactory that supports authentication.
private static HttpTransport transport = new ApacheHttpTransport();
public static HttpRequestFactory createRequestFactory(
final HttpTransport transport) {
return transport.createRequestFactory(new HttpRequestInitializer() {
public void initialize(HttpRequest request) {
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName("MyApp/1.0");
request.headers=headers;
try {
authorizeTransport(request);
} catch (Exception e) {
e.printStackTrace();
}
}
});
Notice the authorizeTransport method, that will basically authorize the request. The authorizeTransport looks like this:
private void authorizeTransport(HttpRequest request) throws HttpResponseException, IOException {
// authenticate with ClientLogin
ClientLogin authenticator = new ClientLogin();
authenticator.authTokenType = Constants.AUTH_TOKEN_TYPE;
authenticator.username = Constants.USERNAME;
authenticator.password = Constants.PASSWORD;
authenticator.transport = transport;
try {
Response response = authenticator.authenticate();
request.headers.authorization=response.getAuthorizationHeaderValue();
} catch (HttpResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
You basically setup a ClientLogin authentication method by providing a username/passsword. The authenticate method will authenticate based on the provided values and returns a response object that can be added to the HTTP header to provide ClientLogin authentication.
Android AccountManager
In order to integrate with the Android AccountManager (avoiding the android user to type in his username / password) , you can find some sample code here http://code.google.com/p/google-api-java-client/wiki/AndroidAccountManager
The fact that the user doesn't need to key in his username/passwords adds to the users comfort level, but the solution remains relatively insecure.
I would strongly suggest doing the following :
Use a client library
I would suggest moving to Google APIs Client Library for Java for this type of interaction. It's Android compatible java client library for all kinds of Google APIs.
You don't want to be bothered with implementing low level HTTP, security and JSON plumbing.
The Google Task API Developers guide also mentions the same library. The library will take care of the authentication for you. If you want to use ClientLogin, all you'll have to do is specify a username/password, or integrate with the Android AccountManager.
Avoid using ClientLogin
ClientLogin is considered insecure, and a number of security holes have been found regarding this authentication mechanism. Google also doesn't recommend it. However, should you decide to continue using ClientLogin, the Google APIs Client Library for Java does support it.