14 Jun 2009

XML-RPC on the iPhone

Posted by kilbot | Filed under: News, Programming

This week I’ve been porting a simple J2ME mobile phone application to the iPhone. The J2ME application allows users to login and exchange data with a web application via XML-RPC, so naturally I was keen to use the same server-side scripts for the iPhone app. As far as I know, there is no no specific open source framework available for XML-RPC on the iPhone, but the folks at Wordpress for iPhone have rolled their own which is available under the GNU General Public License, and with a little fishing around I was able to get it up and running in my own app. Basic instructions after the jump…

The first step is to download the Wordpress for iPhone source code, either via SVN or directly through Trac (Link for v1.21: http://iphone.trac.wordpress.org/changeset/336/tags/1.21?old_path=%2F&format=zip).

When you extract that zip you will see a folder named Classes and inside that a folder named XMLRPC, drag the XMLRPC folder into your project. You will also need to grab NSString+XMLExtensions.h and NSString+XMLExtensions.m and drag them into your project.

That’s all the required files for the XML-RPC framework and now implementing is fairly straight forward. You need to put the following to your header file:

#import "XMLRPCResponse.h"
#import "XMLRPCRequest.h"
#import "XMLRPCConnection.h"

and to your .m file you need to add something like:

- (NSString *)loginToServer {
  NSArray *args = [NSArray arrayWithObjects:@"test",nil];   // the param(s)
  NSString *server = @"http://example.com/xmlrpc";         // the server
  NSString *method = @"loginUser";                        // the method
  XMLRPCRequest *request = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:server]];
  [request setMethod:method withObjects:args];
  id response = [self executeXMLRPCRequest:request];
  [request release];
  
  if( [response isKindOfClass:[NSError class]] ) {
    return nil;
  }
  else {
    return [response valueForKey:@"key"];          // the response key
  }
  return nil;
}

- (id)executeXMLRPCRequest:(XMLRPCRequest *)req {
  XMLRPCResponse *userInfoResponse = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
  return [userInfoResponse object];
}

You need to enter the appropriate values where I’ve commented, but this bare bones example should get you started. You can see more examples by sifting through BlogDataManager.m file in the Wordpress for iPhone project.

  • Leoganda
    Hi, it's really good article!
    I'm newbie in Iphone development, do you have complete article how to use this xml rpc and linked to the UI??

    Thanks
  • Hi Leoganda, I don't have a complete article but I probably help you put together some basic code.. what is the task you are trying to complete?
  • Cool, do these classes convert the array returned to an NSArray?
  • The returned object (*response in the case above) is a NSDictionary, that way you can access the data with key/value pairs.
  • Hi thanks kilbot, I have succeed make simple app with XMLRPC Wordpress now :)
  • Lex
    Hey Kilbot,

    thanks for the info. I need to use XMLRPC for my iPhone app, I tried implementing an example pretty much like what Leo has on his site (http://www.leoganda.net/xml-rpc-on-iphone/). Even if I define response as an id and not NSString, I get a “NSInvalidArgumentException, reason: *** [NSError object]: unrecognized selector sent to instance …” error when I return the response as an object. Have you encountered this as well?
  • Hi Lex, the response is returned as a NSDictionary, so depending on how you are trying to access data within that object you could be getting the NSInvalidArgumentException error.

    Try logging some notices in the app to see where it is failing, eg:
    if( [response isKindOfClass:[NSError class]] ) {
    NSLog(@"Something went wrong ... there was no readable response");
    return nil;
    }
    else {
    NSLog(@"key: %@",[response valueForKey:@"key"]);
    return [response valueForKey:@"key"]; // the response key
    }
    return nil;

    Where 'key' is some data you expect to get back from the server.
  • Lex
    Alrite, I can't figure how the returned data strucutre is composed. I tried looking for an NSDictionary strucutre in the debugger, but no success. My response in XML looks like this:

    <methodResponse>
    <params>
    <param>
    <value>
    <boolean>0</boolean>
    </value>
    </param>
    </params>
    </methodResponse>

    I tried using "boolean" and "value" as the key, but that didn't help, I get a "Terminating app due to uncaught expcetion NSUNknownKeyException, reason: NSCFBoolean 0x... valueForUndefineKey: this class is not key value coding-compliant for the key boolean/value/..."

    Does the key relate to the XML at all?
  • Jb
    Lex - check your comment on the WP iPhone app... The keys are dependent on what the XMLRPC service returns... I.E. you're making a method call for some data and what comes back depends on what you asked for and how that XMLRPC service creates the XML...
  • ad
    Hi, I'm trying to develop an application based on your post, and on Leoganda's one, but I'm doing something wrong. My app has an exception everytime.

    Terminating app due to uncaught exception 'NSInvalidArgument
    Exception', reason: '*** +[NSString decodeXMLCharactersIn:]: unrecognized selector sent to class 0x30692800'

    I debugged and found that it crashes on the first line of this function:

    - (id)decode
    {
    [_parser parse];

    NSError *parseError = [_parser parserError];
    if (parseError) {
    return parseError;
    }

    return decodedValue;
    }

    Even though, I still don't know what I'm doing wrong. Some advice would be very helpful.

    Thanks!
  • Lex
    It sounds to me like the argument that is passed to NSString's decodeXMLCharactersIn method is of the wrong type. Make sure that types of your variables support the methods you call on them. This can be tricky due to Objective-C being very dynamic. If you debug and step into the parse method and reach the point where [NSString decodeXMLCharactersIn] is called, you should be able to track down the error.
blog comments powered by Disqus