First look at Oxygene for Android development

Jolyon Smith has been posting a lot of really rosy stuff about Oxygene lately.  And he even commented on a recent blog post of mine,  in response to my frustration about Embarcadero blatantly ripping off paying customers by not including Android support as part of the baseline Delphi installation:

[Oxygene is] a better Pascal even than Delphi these days and fully supports Android (and iOS) development using the platform native frameworks, so you get to learn “proper” Android development (portable skills) without having to swallow the Java pill.

Thing is, I’ve been doing some serious looking at Oxygene too lately.  I haven’t reached all of the same conclusions he has, though.  But then again, I’ve been trying to do different stuff.

I have to say, though, his statement that you can use it for Android development “without having to swallow the Java pill” is IME completely incorrect.  Because Oxygene’s Android support is a subset of Oxygene for Java, focused entirely on Dalvik support and not native code like Delphi or Oxygene’s iOS compiler, it’s still the same old Java pill, just with a Pascal-flavored candy coating.  It means you still have all of the JVM’s ugly technical limitations, like no value types and a severely broken and limiting Generics model.  And you’ve still got to work with all of the Android system libraries, which have a very distinct Java flavor to them.

For example, I’ve had an idea for an Android app for a while now.  Like most mobile apps, it would involve Internet connectivity.  So I figured one of the most fundamental things possible, and a good way to get my feet wet, would be to write some code to perform a login operation.  It happens that I’ve already got a simple DWS-based web server I can use for stuff like this, and an OUYA for testing, so I set up my network to make sure the devices could see each other and went to work.

The goal is to create a simple login function: take a URL as input, POST a hardcoded username and password to this URL that executes a login command on my server, and return a string containing the same HTML you would see if you performed the same login in a browser and then used the View Source command.  As a baseline, here’s how I’d do this using only out-of-the-box libraries in Delphi:

[code lang="Delphi"]
function TMyObject.Login(const url: string): string;
var
   params: TIdMultiPartFormDataStream;
begin
   params := TIdMultiPartFormDataStream.Create;
   try
      params.AddFormField('Username', 'test');
      params.AddFormField('Password', 'password');
      params.AddFormField('cmd', 'Login');
      result := http.Post(URL, params);
   finally
      params.free;
   end;
end;
[/code]

TIdMultiPartFormDataStream is a bit obscure. If you don’t know anything about it, it might take a bit of time to research it. But once you do know about it, this only takes a few minutes to write, and it works.  It’s very intuitive, and it works exactly as you’d expect, the first time.  I’ve tested it.  (I don’t have Android support for Delphi, but this works on Windows, and given the changes to the Indy source code shipped with XE5, I can only assume it works with Android too now.)

I tried to do the same thing with Oxygene for Java, using an Android template and actually running this on my OUYA.  I immediately ran into a platform irritation: trying to run anything like this on the main thread will get your application killed.  Apparently all network access has to be done in the background.  So a bit of research turns up the AsyncTask class, which is how you run something in a background thread on an Android device.

AsyncTask is a mess and a half.  It requires three generic type parameters, which can optionally be defined as Void if you’re not using the functionality involved.  The documentation goes on and on about restrictions: you can only create or invoke one from the UI thread, in most (but not all!) Android versions, it will run all AsyncTask requests on a single background thread, and it must report back to the UI thread and not some other thread.  You subclass it and override the virtual method that actually does the work you want, (much like TThread,) and then you can either call Get to wait on the work to be done, or override a second method to asynchronously report back to the main thread.  (With a feature like that available, you’d kind of expect that you could use Oxygene’s async/await language feature here to simplify things, but it doesn’t work.)

So I override AsyncTask with a new class. I call it WebRequest:

[code lang="Delphi"]
  WebRequest = class(android.os.AsyncTask<HttpPost, Void, String>)
  protected
    method doInBackground(url: array of HttpPost): String; override;
  end;
[/code]

Yeah, that’s right.  The DoInBackground method actually takes an array of your basic input type, which in this instance is HttpPost.  Unlike Indy, where you have a TIdHTTP class that handles all HTTP requests, the Android libraries have their own classes for each request type.  Oh well.  Different styles, I guess.  But it gets better.  Now you actually have to set up the POST request.

The HttpPost class has a method called SetParams, which takes a HttpParams object, which you add names and values to.  Intuitively, you’d think that that’s how you set up a POST request with parameters. But when I tried that, the server didn’t receive any parameters.  So I asked about it on StackOverflow, and found out that SetParams actually does nothing (it’s there because it’s part of a parent class) and the correct way to do it is to create a list of name/value pairs, wrap that in a UrlEncodedFormEntity object, and then call the HttpPost’s SetEntity method on that.  Obviously!

So with that, I can fire off my POST request, and look at the string it retur–wait, no, it can’t be that simple.  We’re in Java-land, remember?  First, the HttpPost object can’t actually request anything; it’s just an object that describes the action to take.  If you want to fire a HTTP request, you have to create a AndroidHttpClient object, which is analogous to TIdHttp except that it doesn’t have its own methods for HTTP requests; you feed it objects like the HttpPost instead.  So I set one up and code up the request.  It returns a string containing the results from my–oh, wait.  Nevermind.  We’re still in Java-land.

I can only assume that the folks who wrote all this Android code were part of the Chrome team at Google, because the whole thing appears to be written to benefit people who are writing web browsers, not attempting to simply retrieve results from servers.  It returns a HttpResponse object, which contains a lot of metadata about the response, but has no method anywhere that returns a string!  To actually get at the output, you need a BasicResponseHandler object, which knows how to magically extract the HTML returned by the server from the HttpResponse object and return it as a string.

So I finally have this to the point where it will compile and run, with all the Android permissions set correctly and the background code set up propertly.  I build, deploy to my OUYA, and eagerly examine the output, hoping to bask in the sweet, sweet HTML I was expecting… and instead get a 302 redirect from the server.

You’ve gotta be freaking kidding me.

Indy gives me the HTML.  It sees the redirect and handles it internally, like a Web browser would, by default, out of the box.  I don’t have to care about redirects.  I don’t have to know redirects exist.  (I do, of course; I’m the one who set up the server page I’m calling into.  But client-side, I shouldn’t have to.)  But in the Java framework, it all gets thrown in my face.  Time for some more research.

The research doesn’t actually reveal any clear way to get AndroidHttpClient to handle the redirect, so I end up doing it manually, which means I have to actually care about the HttpResponse object and not just hand it off to BasicResponseHandler, because it’s got the metadata I need.  So I have it check for 301 or 302 redirect codes and fire off a GET request (which requires creating a new HttpGet object, of course) if it sees that.

I build, deploy, and run again, and finally, FINALLY there is HTML as the output, that actually came from the server.

It’s the source of the login page I just used, not the page I was supposed to be redirected to after logging in.

I poke around server-side a little and find out that dumped me back to the login page, as it was supposed to, because the second request did not contain the session cookie that the server issued as part of the response to the first request.  Of course.  (When I did this in Indy, I didn’t have to care about cookies or know they exist, any more than I had to care about redirects.)

Back to poking around in documentation.  So apparently the right way to deal with this is to create a BasicCookieStore object and attach it to the BasicHttpContext object that your AndroidHttpClient is using for its request.  I do that… and still get redirected back to the login page.  For some strange reason, it’s not working.  So I asked about that on StackOverflow… and got nothing.

This is the point where I gave up.

This took me two days to research, required me to write well over 100 lines of code, define 3 classes (not counting the main class that’s invoking all of this), use 12 Java framework classes, include 18 units in my USES clauses… and ended in failure.  I have no doubt that actually making it work right would take even more code and even more complexity, all to do what I accomplished in a single, 14-line procedure in Delphi.

Here’s what I’ve concluded from all this:

First, I’m not sure how anyone ever manages to actually create an Android app, when even the most simple and fundamental of tasks require dealing with this much runaround.

Second, RemObjects already has an Oxygene native code compiler for mobile devices, for iOS.  They really ought to make one that targets the Android NDK.  (Maybe then I could use Indy!)

Alternatively, maybe they should figure out some way to use the NDK to host a CLR VM on an Android box, and then I could use the full Oxygene feature set.  But just try Googling about ways to run .NET apps on an Android device and you’ll see that it’s something that a lot of people are trying and only accomplishing with very, very limited (and very expensive!) solutions, so this might be technically infeasible.  But either way the current solution is no good, mostly because it’s chained to Java, which is no good.  I ended up feeling like the guy who wonders why he took that Java pill in the first place, and if he had it to do all over, would have just chosen the blue pill instead. 😉

Third, I’ve gained a tremendous amount of respect for Remy Lebeau and the rest of the Indy team for putting together a library that manages to do such a good job of dealing with this all complexity where it belongs–inside the library–and not tossing it in the developer’s lap!

As always, any feedback is welcome.  I’m particularly interested in knowing if there’s any intuitive Android HTTP library available on par with Indy.  Maybe I’m just looking in the wrong part of the system libraries?

12 Comments

  1. Iztok Kacin says:

    If that is correct then I can only say…well I am without words :). I agree Indy is great for quick coding and simplicity. While I do not agree how they handle some things I have to admit it works and works well and also is very easy to use. And lately they have done a lot on the side of code quality. Keep up the good work Remy and team.

    Just for comparison how it would be done in SenchaTouch javascript framework:

    Ext.Ajax.request(
    {
    url: ServerURL + ‘/’ + API,
    method: ‘POST’,
    jsonData: {
    Username: ‘test’,
    Password: ‘password’,
    Cmd: ‘login’
    },

    success: function(response, opts)
    {
    // call the on success event handler
    OnSuccess(Ext.decode(response.responseText));
    },
    failure: function(response, opts)
    {

    }
    }

    Under the hood there is tremendous power and flexibilty of Ext.Ajax.request but out of the box it does that. You get out the complete JSON object. Sure it is dynamic language but on the other hand if you check it out is is so much object oriented (SenchaTouch not javascript) and so well crafted that it is a joy to use.

  2. Jamie says:

    > And you’ve still got to work with all of the Android system libraries, which have a very distinct Java flavor to them.

    I actually view this as a strength. It means you can rely on the voluminous documentation and examples available on the web. Granted, they’re in another language, but the techniques, classes and API interface is the same. This kind of community documentation for basic introductions, sample apps or complex techniques is a great help.

    • Mason Wheeler says:

      …and yet somehow, no one was able to explain to me how to get the HTTP client to retain its cookies from one request to another. (I did tag the post as “Java”.)

      So much for strong community support and documentation.

  3. Jolyon Smith says:

    The “platform irritation” of not being able to run network requests in the main thread could be seen as ensuring that you don’t do something that you really shouldn’t be doing in the first place. Making it easier to do it “wrong” isn’t necessarily a good thing. 🙂

    I shall look at implementing this myself and see if it isn’t perhaps a little more straightforward than it perhaps at first appears.

  4. Linas says:

    Have you tried http://loopj.com/android-async-http/? It looks pretty straightforward to me. The good thing about java is that you can find 3rd party library for almost anything.

  5. Bunny says:

    Why not use Handlers?

  6. Kryvich says:

    Android is a new beast for us Delphi developers, we need adapt to it.

    I’ve found this: http://stackoverflow.com/questions/5169468/handling-httpclient-redirects
    You can override the default behaviour of HttpClient by sub-classing DefaultRedirectStrategy and overriding its #isRedirected() method.

    Please write when you resolve the issue.

  7. Rsin says:

    Good post.

    However, there seem to be things that are downright impossible in XE5 right now though making it a tricky choice as a general purpose Android dev tool.

    The choice of going with NDK not only means we can’t rely on any existing samples/docs but also make some features hard to access. Try implementing one of these in XE5 (i actually need all of them so this list is not made up and most app might need one or more features from the list):
    – how would one implement an android service ?
    – how would one work with Play Store/Google Cloud Messaging (Google has only published the SDK (Java) version of library).
    – how about implementing a broadcast receiver (for example to start android service on boot and lot of other uses)
    – intents is a massive topics but again XE5 seems slim on info on this right now

    Some things can be done with JNI bridge but others might be impossible at this time.

    As far as interactive data driven apps (e.g. back-end database) XE5 looks quite capable and likely delivers on promises.

    As general purpose one Oxygene or plain old Java involve more work but allow everything to be done.

    Caveat Emptor as usual.

  8. Ronaldrigo says:

    My name is Ronald. Am new here. Am getting a lot of help from this forum.

  9. […] back in September last year, Mason Wheeler blogged about his first experiences with developing for Android using Oxygene. I said at the time that I would look into reproducing his efforts and […]