Sunday 14 June 2009

XMLRPC on iPhone

My first iPhone application needed to call XMLRPC. Google search brought me to the site http://iphone.wordpress.org/development/. I tried its source code(the XML-RPC Client Framework was written by Eric Czarny), unfortunately it was not very promising in my case. At least I found a bug on its Base64 decoding, it hasn't been fixed yet when I tried to post this blog.

The bug appears at (note the difference of italic parts)
http://iphone.trac.wordpress.org/browser/trunk/Classes/XMLRPC/XMLRPCExtensions.m

+ (NSData *)base64DataFromString: (NSString *)string
52 {
53 unsigned long ixtext, lentext;
54 unsigned char ch, inbuf[3], outbuf[4];

It should be

+ (NSData *)base64DataFromString: (NSString *)string
52 {
53 unsigned long ixtext, lentext;
54 unsigned char ch, inbuf[4], outbuf[3];


I believe the author Eric Czarny must have an updated version. As matter of fact, it is hosted at http://github.com/eczarny/xmlrpc/tree/master. This new version is brilliant, it is very easy to integrate it into your own application. The link above also described how to invoke the XMLRPC request.
As supplement, I'd like to share my code with those people who,just like me, have little Obj-C knowledge and try to do iPhone development.

In your view controller header file(.h),

#import "eczarny-xmlrpc/XMLRPCResponse.h"
#import "eczarny-xmlrpc/XMLRPCRequest.h"
#import "eczarny-xmlrpc/XMLRPCConnection.h"
#import "eczarny-xmlrpc/XMLRPCConnectionManager.h"
#import "eczarny-xmlrpc/XMLRPCConnectionDelegate.h"

@interface ConfigViewController : UIViewController<XMLRPCConnectionDelegate> {

@end


In your view controller implementation file(.m),

Within some event handler, call

{

NSString strURL = @"http://x.x.x.x/xmlrpcserver";

XMLRPCRequest *request = [[XMLRPCRequest alloc] initWithURL:[NSURL URLWithString:strURL]];
XMLRPCConnectionManager *manager = [XMLRPCConnectionManager sharedManager];

[request setMethod:@"downloadBookDesc" withParameters:[NSArray arrayWithObjects:strUsername,PasswordHashCode,strISBN,nil]];

[manager spawnConnectionWithXMLRPCRequest:request delegate:self];

[request release];

}

You process the response in the following delegation functions,


- (void) request: (XMLRPCRequest *) request didReceiveResponse: (XMLRPCResponse *) response {

if([response isFault]) {
NSLog(@"Fault code: %@", [response faultCode]);
NSLog(@"Fault string: %@", [response faultString]);
NSString* strErrorMessage = [NSString stringWithFormat:@"%@%@", @"Error:", [response faultString]];
}
else
{
NSLog(@"Pased response: %@", [response object]);
NSArray *result = [response object];
// int counts = [result count];
NSData *str = [result objectAtIndex:1]; //index 0 = "OK"
NSLog(@"return = %@", str);
}

NSLog(@"response body: %@", [response body]);

}


- (void)request: (XMLRPCRequest *)request didFailWithError: (NSError *)error
{

NSEnumerator *enumerator = [[error userInfo] keyEnumerator];
id key;

NSString *strtest;
while ((key = [enumerator nextObject])) {
strtest = key;
}

enumerator = [[error userInfo] objectEnumerator];
id value;

while ((value = [enumerator nextObject])) {
strtest = value;
}

}

- (void)request: (XMLRPCRequest *)request didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
{
}

- (void)request: (XMLRPCRequest *)request didCancelAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
{
}

2 comments:

Peter Marks said...

Sincere thanks for posting this example. The framework looks great but there's not much to get us started.

ad said...

Nice tutorial, since there are no specific examples for the iPhone.

Do you know how could I differentiate between two or more responses that come from different calls in the same delegate?