How to: HTTP POST and Google’s ClientLogin using Objective-C and the iPhone SDK

By | May 18, 2009

PLEASE NOTE (2009-08-12): You probably do not want to use this method (though it’s great for learning). A much better solution is to use the gdata-objectivec-client. Example code on using that library can be found in one of my projects hosted on github.

I’ve been working on an iPhone app that uses one of Google’s APIs.  The following appears to work just fine in a non-jailbroke phone.

Creating the request

[objc]

NSURL *url = [NSURL URLWithString:@"https://www.google.com/accounts/ClientLogin"];

NSMutableURLRequest *loginRequest = [NSMutableURLRequest requestWithURL:url];

[loginRequest setHTTPMethod:@"POST"];</code>

//set headers

[loginRequest addValue:@"Content-Type" forHTTPHeaderField:@"application/x-www-form-urlencoded"];

[loginRequest addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

NSString *requestBody = [[NSString alloc]

initWithFormat:@"Email=%@&amp;Passwd=%@&amp;service=finance&amp;source=%@",

username, password, [NSString stringWithFormat:@"%@%d", @"ashlux-igFinance-1.0"]];

[loginRequest setHTTPBody:[requestBody dataUsingEncoding:NSASCIIStringEncoding]];

[/objc]

This part is fairly straight-forward. The service=finance should be changed to the Google service you are using.  Also ashlux-igFinance-1.0 should be changed to the format company-appname-version.

The default timeout interval for the request connection is 60 seconds.  To change this, use setTimeoutInterval:

[objc]

[loginRequest setTimeoutInterval:30]; // set timeout for 30 seconds

[loginRequest setTimeoutInterval:90]; // set timeout for 90 seconds

[/objc]

Sending the request

To send the request, I am sending a synchronous request (which will block) to Google:

[objc]

NSHTTPURLResponse *response = NULL;

NSData *responseData = [NSURLConnection sendSynchronousRequest:loginRequest returningResponse:&amp;response error:nil];

NSString *responseDataString = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];

NSLog(@"Response from Google: %@", responseDataString);

[/objc]

Objective-C does have asynchronous IO (non-blocking), but that’s for another time.  For most purposes, asynchronous is the way to go to avoid blocking the application.

Reading the response

For my purposes, I am storing the data in a struct called GoogleClientLogin to represent Google’s ClientLogin data (that’s simple enough, so I will not list it here).  For simplicity, I am not interpreting the response status beyond success (code=200) and failure (code=anything else).

[objc]

if ([response statusCode] == 200) {

NSLog(@"Login successful.");

GoogleClientLogin *aGoogleClientLogin = [GoogleClientLogin alloc];

aGoogleClientLogin.username = username;

aGoogleClientLogin.password = password;

NSString *authToken = [[responseDataString componentsSeparatedByString:@"Auth="] objectAtIndex:1];

NSLog(@"Google authToken=%@", authToken);

aGoogleClientLogin.authToken = authToken;

return [aGoogleClientLogin autorelease];

} else {

NSLog(@"Login failed.");

return nil;

}

[/objc]

That is more or less all there is to it. There is room for better error handling, but the effort would be better spent elsewhere on the applcation.

Next up, I’ve really need to figure out how to work in unit tests using Xcode.  My previous attempts at getting OCUnit working were full of fail special thanks to Apple’s out-of-date documentation.

Leave a Reply

Your email address will not be published. Required fields are marked *