In this article I will show how to build PHP XML RPC server and how to consume provided services with PHP and an Android application as a client. PHP side of things will be built on top of Zend Framework and for Android will be using very thin XML RPC library android-xmlrpc ( http://code.google.com/p/android-xmlrpc/ ).
Assumption is that you already have downloaded Zend Framework and have Android SDK set up (as well as Android emulator). I’ll be using Eclipse both for PHP and Android development. Also, I’ll be using ZF tool for creating project, controllers and models.
We’ll start with building XMLRPC server component.
XMLRPC server component
In your web server’s document root run zf tool with this command: zf create project xmlrpc-test. Afterwards step into this newly created directory xmlrpc-test.
Now we’ll create needed controllers and models.
First run zf create controller Server (which creates our ServerController), then we’ll create our model zf create model Data. Because we’ll also create client side of XMLRPC lets create this controller now to finish out work with zf tool: zf create controller Client.
We should test if our website is running properly, go to http://localhost/xmlrpc-test/public with your browser and you should see image similar to the one below.
Now we’re ready to create our project in Eclipse, open PHP workspace, and go to File->New->PHP project, enter xmlrpc-test as a project name and click Finish. Our project is ready and all files created earlier are in it.
Lets open our Server controller (application/controllers/Server.php) and start building XMLRPC server.
[code lang=”php”]
class ServerController extends Zend_Controller_Action
{
public function indexAction()
{
$this->_helper->viewRenderer->setNoRender();
$server = new Zend_XmlRpc_Server();
$server->setClass(‘Application_Model_Data’, ‘cf’);
echo $server->handle();
}
}
[/code]
First, we disable our view. We instantiate Zend_XmlRpc_Server and add class which will respond to calls from client, this will be our Application_Model_Data class and we will set its namespace as cf.
We echo the servers handle method, and voila, our very simple and basic XMLRPC server is done.
Now let’s open our model (application/models/Data.php) and create some test method for returning dummy data.
[code lang=”php”]
class Application_Model_Data
{
/**
* Test method
*
* @return string
*/
public function test()
{
return ‘Hello XMLRPC!’;
}
}
[/code]
This class, Application_Model_Data is classic PHP class, the most important thing here is to notice the comments. They are mandatory, because when call occurs, Zend_XmlRpc_Server will be doing reflection of this class before running it, checking if called method exists and if its arguments are matching defined ones and are correct type. So, we have to define types of all input parameters (none in this test method) as well as method return type.
Let’s write XML RPC client to check if everything is OK so far.
XMLRPC PHP client
Earlier we created ClientController class (located in application/controller/Client.php) with default indexAction method and now we’ll add our code in it.
[code lang=”php”]
class ClientController extends Zend_Controller_Action
{
public function indexAction()
{
$client = new Zend_XmlRpc_Client(‘http://localhost/xmlrpc-test/public/server/’);
try {
$data = $client->call(‘cf.test’);
$this->view->data = $data;
} catch (Zend_XmlRpc_Client_HttpException $e) {
require_once ‘Zend/Exception.php’;
throw new Zend_Exception($e);
} catch (Zend_XmlRpc_Client_FaultException $e) {
require_once ‘Zend/Exception.php’;
throw new Zend_Exception($e);
}
}
}
[/code]
First we instantiate Zend_XmlRpc_Client and provide its constructor URI of our XML RPC server. Then we try to make a call to a test method (‘cf’ is a namespace defined for our Application_Model_Data class). We’ll forward returned data to our view.
Our view is located in application/views/scripts/client/index.phtml. In it we are only echoing data returned from our test method.
[code lang=”php”]
Via XMLRPC
escape($this->data); ?>
[/code]
If we run http://localhost/xmlrpc-test/public/client in our browser we should get something like this:
Let’s add another method to our Application_Model_Data class which will be expecting single Integer parameter and it will be returning an associative array.
[code lang=”php”]
/**
* Fetches data
*
* @param integer $num
* @return array
*/
public function getData($num)
{
$data = array();
for ($a = 0; $a < $num; $a++) {
$data[] = array(
'title' => ‘Codeforest.net’,
‘number’ => $a + 1,
‘datetime’ => date(‘Y-m-d H:i:s’)
);
}
return $data;
}
[/code]
Method is called getData (yes, very creative) and it’s pretty simple. Again, notice the comments with defined @param and @return lines.
We also have to upgrade our ClientController class and instead of calling cf.test method will be calling cf.getData method. We only have to supstitute one line (7th):
[code lang=”php”]
$data = $client->call(‘cf.test’);
[/code]
with this one:
[code lang=”php”]
$data = $client->call(‘cf.getData’, 15);
[/code]
Everything else in the ClientController class stays the same.
We have to update our view script with something like this:
[code lang=”php”]
Via XMLRPC
data) > 0):?>
-
data as $row):?>
- escape($row[‘number’])?> – escape($row[‘title’])?>, escape($row[‘datetime’])?>
[/code]
Again, we go to our browser to test http://localhost/xmlrpc-test/public/client. Result is similar to:
This concludes our PHP and Zend Framework part of the article.
XMLRPC Android client
If using Eclipse switch to Android workspace (File->Switch Workspace, pick your Android workspace).
After you have switched workspace go to File->New->Android Project, enter project name, select build target and fill the rest of the properties.
Download Android XML-RPC client library from http://code.google.com/p/android-xmlrpc/.
Create new package in our project (right mouse click on project name in Package explorer and select New->Package). Name this package org.xmlrpc.android and copy files form archive directory android-xmlrpc/src/org/xmlrpc/android into this newly created package.
Now our directory structure should be similar to picture below:
Because we’ll be needing internet connection (to connect to our XML-RPC server) we need to add internet permission to our android manifest file. Open AndroidManifest.xml and in raw XML view add next line just before closing manifest tag:
[code lang=”xml”]
[/code]
In our example we’ll be using default layout file res/layout/main.xml but we’ll add an ID to its TextView element so that we can fill it out with received data. So open res/layout/main.xml file and locate TextView element. Add an android.id attribute with @+id/text_view value to it:
[code lang=”xml”]
[/code]
Now we can start building our Android Client. Open Client.java in our com.cf.xmlrpc package and enter:
[code lang=”java”]
public class Client extends Activity {
private XMLRPCClient client;
private URI uri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
uri = URI.create(“http://10.0.2.2/xmlrpc-test/public/server/”);
client = new XMLRPCClient(uri);
TextView textView = (TextView) findViewById(R.id.text_view);
}
}
[/code]
First, we create class variables which will hold our XMLRPC Client and URI for our server. We can access this variables throughout our class.
In onCreate method we assign our uri variable URI object. As you can see we are using 10.0.2.2 address to access our own local web server. 127.0.0.1 or localhost is used by the underlying linux OS on emulator.
Then we create our XMLRPCClient and give its constructor our uri variable.
We’ll also get reference to TextView element of our layout where we’ll display our results.
If Eclipse is signaling for some error due to not having imported needed classes press Ctrl+Shift+O, this will import all needed classes automatically.
Next, we’ll create method which will call test method on our XML-RPC server (built earlier with Zend Framework).
[code lang=”java”]
private String testMethod() {
String text = “”;
try {
text = (String) client.call(“cf.test”);
} catch (XMLRPCException e) {
Log.w(“XMLRPC Test”, “Error”, e);
text = “XMLRPC error”;
}
return text;
}
[/code]
We’re using try – catch block to catch errors and to deal with them. After creating this method we have to call it from onCreate method and display its return value to TextView element. Our modified Client activity class should look like this:
[code lang=”java”]
public class Client extends Activity {
private XMLRPCClient client;
private URI uri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
uri = URI.create(“http://10.0.2.2/xmlrpc-test/public/server/”);
client = new XMLRPCClient(uri);
TextViewtextView = (TextView) findViewById(R.id.text_view);
textView.setText(testMethod());
}
private String testMethod() {
String text = “”;
try {
text = (String) client.call(“cf.test”);
} catch (XMLRPCException e) {
Log.w(“XMLRPC Test”, “Error”, e);
text = “XMLRPC error”;
}
return text;
}
}
[/code]
We are ready to test our Android client. Select Run->Run configurations and create new Android application configuration for our project:
After the emulator boots up we should have something similar to this:
Hoorah! Our Android client is using our XML RPC web service!
Lets now create method which will call our other server function getData.
[code lang=”java”]
private String getDataMethod(int num) {
String text = “”;
try {
Object[] data = (Object[]) client.call(“cf.getData”, num);
for(Object o: data) {
HashMap map = (HashMap) o;
text = text + “‘datetime’ => ” + map.get(“datetime”) + “, ‘number’ => ” + map.get(“number”) + “, ‘title’ => ” + map.get(“title”) + “\n\n”;
}
} catch (XMLRPCException e) {
Log.w(“XMLRPC Test”, “Error”, e);
text = “XMLRPC error”;
}
return text;
}
[/code]
Method we are calling (cf.getData) expects one parameter (integer) and returns an associative array (from PHP’s perspective). In Java we received array with map items.
If you are having trouble figuring out what your custom XML RPC service is returning you be sure to check out great post at Inchoo. It describes how to parse the data returned from XMLRPC.
Next step is to switch method calls in onCreate method:
[code lang=”java”]
textView.setText(testMethod());
[/code]
to this one:
[code lang=”java”]
textView.setText(getDataMethod(12));
[/code]
After saving and running (again select Run->Run configurations) our changed Android client we should have on the emulator something like:
And that’s it. We covered all the elements necessary to build PHP XML-RPC Server, Client and Android application that will harvest it.
Feel free to leave a comment, a question or a critique. Also feel free to request a follow up or an article with stuff that interests you.