Let's start with creating a simple layout containing two buttons and a text view. Call the buttons B1 and B2, and the text view T1. I will leave this part as an exercise.
Next create a new class called OAuthStageOne, extending AsyncTask. This class will provide the functionality required for authenticating the user and retrieving the initial authorization.
public class OAuthStageOne extends AsyncTask<Void, Void, Void> { [..] }This class will require access to an OAuth provider and consumer, and it also needs to know the context it is running in. Let's gather those details in the constructor:
public OAuthStageOne(Context context, CommonsHttpOAuthProvider provider, CommonsHttpOAuthConsumer consumer) { [..] }Note that we are using the CommonsHttpOAuth provider and consumer classes, rather than the DefaultOAuth classes. The later ones have issues when working with Google Apps.
Next, we need to override the doInBackground() method of AsyncTask and put our stage one code there. All this code does is create a token request URL and then start the default web browser to open the Google Apps authentication/authorization site. This could just as well be done from within the main controller activity, but using AsyncTask will safeguard the application from being force closed due to a slow network connection etc.
The token request URL is obtained using the retrieveRequestToken() method of the OAuth provider. We pass the consumer and the callback URL as parameters:
final String url = provider.retrieveRequestToken(consumer, C.OAuth.CALLBACK_URL);Now start the browser using this URL.
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.setFlags( Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_FROM_BACKGROUND); context.startActivity(intent);
That's stage one done. The browser will open with the standard Google login box and once the user has logged-in they will be offered to either grant or deny our application access to their account. Once the user grants access the browser will call our callback URL. What happens now is the OAuthMain activity will be called with a new intent, hence the onNewIntent() method will fire. In that method we check if the intent uri scheme is the one our callback is registered with, and if yes, we launch stage two.
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
final Uri uri = intent.getData();
if (uri != null && uri.getScheme().equals(C.OAuth.CALLBACK_SCHEME)) {
new OAuthStageTwo(this, provider, consumer).execute(uri);
finish();
}
}
Notice that we again pass the provider and consumer. You may be wondering where these came from, since there's no initialization code in that method. If you have a look at the AndroidManifext.xml file in the sample project you will notice the OAuthMain activity marked as "singleTask". This way we prevent multiple copies of the activity being started (which would happen with the callback!), and all previously initialized class variables are available as a result.
Next create a new class called OAuthStageTwo, again extending AsyncTask. This class will provide the functionality required for retrieving the long-term access token and storing it in application preferences. The process is very simple - retrieve the OAuth verifier string from callback URI, and pass it along with the consumer instance to the retrieveAccessToken() method of the provider. Then store the retrieved token and token secret in application preferences. This will fire the onSharedPreferencesChanged() listener in the controller activity and finish the process.
[..] provider.retrieveAccessToken(consumer, oauth_verifier); final Editor edit = prefs.edit(); edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken()); edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret()); edit.commit(); [..]
And that's about it for OAuth.
10 comments:
Thanks for the example. Was able to use it as the basis for getting OAuth working with my app engine app.
Incidentally, I think your code that sets the intents for the browser has a typo. You need to OR(|) the flags, not AND(&) them.
Thanks Martin, well spotted.
This works great, and I was able to get lists of docs and spreadsheets.
Is there any reason it always returns a 401 when calling POST?
My code is below. Thanks for any suggestions.
String url = consumer.sign("https://docs.google.com/feeds/default/private/full");
HttpPost post = new HttpPost(url);
post.addHeader("Host","docs.google.com");
post.addHeader("Accept","*/*");
post.addHeader("Content-Type","application/atom+xml");
post.addHeader("GData-Version","3.0");
String reqBody="...xml from google documentation...";
StringEntity se = new StringEntity(reqBody,"UTF-8");
post.setEntity(se);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
--->401 Unauthroized
Ramin, if I recall right you should be using PUT instead of POST and the ApacheHttpClient as opposed to DefaultHttpClient.
Not able to download sample project..
pls help
hi, thanks ...
any plans for part3
cheers,
nEosAg
There won't be part three as I have moved to Google libraries. The API has stabilized on Android and Google also published working samples for Docs and many other services.
You should be able to figure it all out from the sample project.
How can i upload, download, and show all file on my Google doc account?
thank you very much
Tried your project and was unable to get it to work. Really want to get access to google docs on android, however documentation and sample projects are not clear. Does this method still work? I'm getting a server error 400 (bad request) on stage 2 of Oauth.
Patrick, I can't say for sure as I haven't used this method for a long time.
However, the samples Google provide with their Google API Java Client library do work just fine: http://code.google.com/p/google-api-java-client/
I have an app in production that chats to Google Docs without issues using this library (it's "alpha" but surprisingly stable).
Post a Comment