8

I am trying to access Basecamp API from my Android/Java source code following way ....

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class BCActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        DefaultHttpClient httpClient = new DefaultHttpClient();

        //final String url = "https://encrypted.google.com/webhp?hl=en"; //This url works
        final String url = "https://username:password@projectsource.basecamphq.com/people.xml"; //This don't
        HttpGet http = new HttpGet(url);
        http.addHeader("Accept", "application/xml");
        http.addHeader("Content-Type", "application/xml"); 

        try {

            //  HttpResponse response = httpClient.execute(httpPost);
            HttpResponse response = httpClient.execute(http);

            StatusLine statusLine = response.getStatusLine();
            System.out.println("statusLine : "+ statusLine.toString()); 

            ResponseHandler <String> res = new BasicResponseHandler();  

            String strResponse = httpClient.execute(http, res);
            System.out.println("________**_________________________\n"+strResponse);
            System.out.println("\n________**_________________________\n");

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

        WebView myWebView = (WebView) this.findViewById(R.id.webView);
        myWebView.loadUrl(url);//Here it works and displays XML response

    }
}

This URL displays the response in WebView, but shows Unauthorized exception when I try to access through HttpClient as shown above.

Is this is right way to access Basecamp API through Android/Java? or Please provide me a right way to do so.

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Vaibhav Jani
  • 12,428
  • 10
  • 61
  • 73

4 Answers4

11

The HttpClient can't take the login creditals from the URI.
You have to give them with specified methods.

If you use HttpClient 4.x have a look on this:
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html

But notice if you don't want to use the new version on the HttpClient (Android uses version 3.x), you should look here:
http://hc.apache.org/httpclient-3.x/authentication.html

That was the theory, now we use them:
Basically we use HTTP, but if you want to use HTTPS, you have to edit the following assignment new HttpHost("www.google.com", 80, "http") into new HttpHost("www.google.com", 443, "https").

Furthermore you have to edit the host (www.google.com) for your concerns.
Notice: Only the full qualified domain name (FQDN) is needed not the full URI.

HttpClient 3.x:

package com.test;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.os.Bundle;

public class Test2aActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            HttpHost targetHost = new HttpHost("www.google.com", 80, "http");

            DefaultHttpClient httpclient = new DefaultHttpClient();
            try {
                // Store the user login
                httpclient.getCredentialsProvider().setCredentials(
                        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                        new UsernamePasswordCredentials("user", "password"));

                // Create request
                // You can also use the full URI http://www.google.com/
                HttpGet httpget = new HttpGet("/");
                // Execute request
                HttpResponse response = httpclient.execute(targetHost, httpget);

                HttpEntity entity = response.getEntity();
                System.out.println(EntityUtils.toString(entity));
            } finally {
                httpclient.getConnectionManager().shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

HttpClient 4.x:

Attention: You will need the new HttpClient from Apache and additionally you must rearrange the order, that the jar-file is before the Android library.

package com.test;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.os.Bundle;

public class TestActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            HttpHost targetHost = new HttpHost("www.google.com", 80, "http");

            DefaultHttpClient httpclient = new DefaultHttpClient();
            try {
                // Store the user login
                httpclient.getCredentialsProvider().setCredentials(
                        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                        new UsernamePasswordCredentials("user", "password"));

                // Create AuthCache instance
                AuthCache authCache = new BasicAuthCache();
                // Generate BASIC scheme object and add it to the local
                // auth cache
                BasicScheme basicAuth = new BasicScheme();
                authCache.put(targetHost, basicAuth);

                // Add AuthCache to the execution context
                BasicHttpContext localcontext = new BasicHttpContext();
                localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

                // Create request
                // You can also use the full URI http://www.google.com/
                HttpGet httpget = new HttpGet("/");
                // Execute request
                HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);

                HttpEntity entity = response.getEntity();
                System.out.println(EntityUtils.toString(entity));
            } finally {
                httpclient.getConnectionManager().shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
CSchulz
  • 10,882
  • 11
  • 60
  • 114
  • Have you read my comments? You are trying to use the *HttpClient* version 4.x and need the libraries and **change the order of the libraries**! – CSchulz Aug 19 '11 at 07:59
  • The *HttpClient* library must be before the android libraries. I don't know which IDE you are using. In eclipse you can make that in the *project properties* -> *java build path* -> *order and export* – CSchulz Aug 19 '11 at 09:18
  • Have you changed the *HttpHost* to **443** and **https**? – CSchulz Aug 19 '11 at 10:38
  • Always look into the java doc of the class, there are a lot of information available and use search engines to find special cases of application. That https uses the port 443 and http uses the port 80 is basic web knowledge . – CSchulz Aug 19 '11 at 10:46
  • Does this work without adding an additional library on stock Android? I'm getting a class not found for org.apache.http.auth.Credentials. – Tal Weiss Jun 25 '12 at 20:57
  • The HttpClient 3.x was included in the default Android. I don't know if they have removed it now. – CSchulz Jun 28 '12 at 18:58
  • But after you compile the android app, will it work? I mean the compilation path change for the IDE will not affect the compiled apk. Is there something need to change on the android app compilation to make this work? – dongshengcn May 27 '13 at 19:53
  • Did you adjust the libraries order? Perhaps you should use the suggested library http://code.google.com/p/httpclientandroidlib/. – CSchulz Jun 03 '13 at 09:11
  • Important think to note is that Android included 3.x library issues two requests for each Basic Auth protected location (the first request is sent without the auth header and only after the server returns 401, the request is resent with the auth header). This question lists few ways to force headers to be sent with each request: http://stackoverflow.com/a/4328694/1031601 – Jan Wrobel Jul 15 '13 at 19:34
4

Appendix on the brilliant and very helpfull answer of CSchulz:

in http client 4.3 this:

localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

does not work anymore (ClientContext.AUTH_CACHE is deprecated)

use:

import org.apache.http.client.protocol.HttpClientContext;

and

localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache);

see http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/protocol/ClientContext.html

and:

http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/protocol/HttpClientContext.html

michel.iamit
  • 5,788
  • 9
  • 55
  • 74
4

Finally I got it How to glue the code shown in above answer ...

public static void performPost(String getUri, String xml) {

    String serverName = "*******";
    String username = "*******";
    String password = "********";
    String strResponse = null;

    try {
        HttpHost targetHost = new HttpHost(serverName, 443, "https");

        DefaultHttpClient httpclient = new DefaultHttpClient();
        try {
            // Store the user login
            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                    new UsernamePasswordCredentials(username, password));

            // Create AuthCache instance
            AuthCache authCache = new BasicAuthCache();
            // Generate BASIC scheme object and add it to the local
            // auth cache
            BasicScheme basicAuth = new BasicScheme();
            authCache.put(targetHost, basicAuth);

            // Add AuthCache to the execution context
            BasicHttpContext localcontext = new BasicHttpContext();
            localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

            // Create request
            // You can also use the full URI http://www.google.com/
            HttpPost httppost = new HttpPost(getUri);
            StringEntity se = new StringEntity(xml,HTTP.UTF_8);
            se.setContentType("text/xml");
            httppost.setEntity(se); 
            // Execute request
            HttpResponse response = httpclient.execute(targetHost, httppost, localcontext);

            HttpEntity entity = response.getEntity();
            strResponse = EntityUtils.toString(entity);

            StatusLine statusLine = response.getStatusLine();
            Log.i(TAG +": Post","statusLine : "+ statusLine.toString()); 
            Log.i(TAG +": Post","________**_________________________\n"+strResponse);
            Log.i(TAG +": Post","\n________**_________________________\n");

        } finally {
            httpclient.getConnectionManager().shutdown();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

One very important thing How your library should be arranged and which libraries you will required ...

enter image description here

From Here you will find this libraries.

To add them in eclipse (Below Android sdk < 16)...

Project properties -> java build path -> Libraries -> Add external JARs

To arrange them in order in eclipse ...

Project properties -> java build path -> order and export

For above Android sdk >= 16 you will have to put these libraries into "libs" folder.

Vaibhav Jani
  • 12,428
  • 10
  • 61
  • 73
1

If you like to use the HttpClient 4.x as mentioned in the other answers you could also use httpclientandroidlib. This is a converted stock HttpClient without apache.commons and with Android LogCat support.

dirkboye
  • 156
  • 1
  • 4