Ok, accessing SOAP web services from an Android device shouldn't be too much trouble I thought, but I was wrong for different reasons. One of them is that SOAP is not particulary kind to your mobile system resources. Google advocates REST and JSON and as much as I prefer REST over SOAP I had no choice and needed to do SOAP web service communication on my mobile device as the backend did only support SOAP and no REST.
That said, let's tackle the SOAP problem. First I tried to create myself a neat little type-safe web service client through the JDK 6 wsimport tool. But hey, that's not working on Android as classes from the javax.* packages were required which are not available on Android. Ok, there are ways to repackage them as described in http://code.google.com/p/dalvik/wiki/JavaxPackages but the web service I liked to use could not be parsed at all. I could have "cut down"/"fixed" the WSDL and try the repacking, but this looked not very clean to me, starting with workarounds right from the start.
So I looked closer and saw that the backend was created using AXIS. Ok, I tried AXIS and it generated me a web service client. I was happy... but only for a short while. Then I saw that AXIS not only required javax.* packages as well but also java.* packages. Of the latter I was not sure whether they could be repackaged and work on a Dalvik VM (some classes were dropped because of the limited use or high resource consumption, but the Dalvic VM is not a standard/certified VM so some stuff might not work at all).
Great, of the two most popular web service clients none worked for me/Android. After consulting Google and StackOverflow you quickly see that people state that ksoap2-android would do the trick at http://code.google.com/p/ksoap2-android/. It’s a spin-off of ksoap2 at http://ksoap2.sourceforge.net/ for J2ME, so it’s hopefully less resource-hungry than either of the two technologies above, but oh no: ksoap2-android isn’t generating any web service client for you at all. It’s kind of a not type-safe string-in/string-out API. I wanted to reject this option therefore quickly – I wasn’t willing to go back 10 years at first and work with such an API. So I tried a few more things out, briefly thought about HTML scrapping, even tried HTMLUnit (convenient for this purpose even though it’s intended for testing) on the web site, but it failed as it couldn’t parse the messy JavaScript – so not only the WSDL was beyond the specification I assume. I was also embarrassed to have thought about such a means and remorsefully I came back to ksoap2-android and gave in, but it wasn’t as bad as I thought – it did the job cleanly and it is a tiny little library to be used on mobile devices.
So, what did I had to do? First I had to get a hand on the library. Very kindly, the team provided a JAR with all dependencies for android called ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar (check out the project site above – at the time of this writing 2.5.2 was the latest release, even accessible through Maven). That was a good start. I also found a very nice videocast on the subject at http://vimeo.com/9633556 that I liked. To make this blog more touchable. Let’s assume the web service I want to access is Jira, so here is what needs to be done for a login:
HttpTransportSE transportSE = new HttpTransportSE(
“http://my.server.com:8080/rpc/soap/jirasoapservice-v2”);
SoapObject request = new SoapObject("http://soap.rpc.jira.atlassian.com", "login");
request.addProperty("username", username);
request.addProperty("password", password);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
transportSE.call("login", envelope);
Nice, ksoap2-android worked... with HTTP and that was fine for the test server but I needed HTTPS for the productive instance. How to pull that trick with ksoap2? I was a bit blind in the beginning as I did my experiments not in the emulator or on the device, but first tried to understand ksoap2 and the web service I was also new to in a J2SE project as ksoap2 (not the android spin-off) works on a plain JDK, too. However, that version is missing the HTTPS support. So eventually I saw that ksoap2-android has a class called HttpsTransportSE. Boy was I happy to see this, but how to use it? The API looked a bit strange and I found no documentation, but the only source of truth is the code anyway and when looking at the sources it was clear that the parameters are all put into an URL object, so calling it is as simple as this:
HttpTransportSE transportSE = transportSE = new KeepAliveHttpsTransportSE(
“my.server.com”, 443, “/rpc/soap/jirasoapservice-v2, 1000);
That was almost all I needed, but ksoap2-android or rather HttpClient doeesn't trust my server as there was no valid certification path, i.e. Android had no built-in root certificate trusting in the end the certificate from my server. "Crazy" Bob Lee, formerly with the Google Android team, explains how to trust SSL certificates on Android here http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html, but since I planned to use the web service in a safe network I was also fine with trusting all SSL communication in general (of course opening up the gates to man-in-the-middle attacks and similar vulnarabilities) as described e.g. here http://groups.google.com/group/android-developers/browse_thread/thread/1ac2b851e07269ba/c7275f3b28ad.... Just call FakeX509TrustManager.allowAllSSL() before you do any HTTPS communication/call to ksoap2-android and you are fine.
I have to admit that I haven’t expected so much hassle with this task. Clearly, I would have loved to do REST, but I had to do SOAP and this is still the situation in which you will find yourself most of the time if you can’t control the backend and have to use what’s available: Not many companies have made the transition already to REST or offer a REST interface of comparable capabilities. Anyhow, it worked and that’s what counts and in the end it worked even without workarounds like repacking non-shipped packages or other hacks and it worked with just a few lines of code – that’s how it should be. The need for a full-blown web service client is anyway not given on mobile device most of the time as you focus your work on these devices on the certain features that make sense on a mobile device. Blindly re-coding web UIs into mobile applications isn’t the type of mobile applications that makes fun or sense.