#1397 Attempts at Fandroid

groves Thu 20 Jan 2011

I've been attempting to get Fantom running on Android for the past couple days with middling success. I searched through the discussions here and on Google, but I didn't find any references for how to do it. As such, I muddled forward on my own. If there are already instructions for doing it, please send a link my way and skip the travails below.

My first test worked perfectly. I generated a base project with an ant build.xml using android's tools, compiled a simple Fantom main into a jar using build's JarDist, added that to the android project's libs, and was able to successfully call into that on the Android emulator. Fantom said "Hello, android world" in the phone's logs, no problem.

I'm running into more difficulty with the second step: extending the controlling class in the android application, Activity, with a Fantom class. That'll let me drive the UI from Fantom.

The first hurdle I had to overcome for that was bootstrapping the Fantom runtime. The Activity class is initialized by Android, and Fantom expects to be bootstrapped before any of its classes are constructed. This is something of a chicken and egg problem. My initial attempt at getting things to go in the proper order was to add a Java subclass of Activity that contained the code that normally gets generated into fanjardist::Main in its static block. The Fantom activity class would then subclass it, the superclass' static block would be run before the Fantom class was instantiated, and the runtime would be ready to go. Unfortunately that doesn't work with the Fantom compiler. Since the Fantom class extends the Java class, the Java class needs to be on the classpath for the Fantom compiler. However, the Fantom compiler loads and executes the code in the Java class to be able to use Java reflection to examine it. That causes the static block of Fantom bootstrap code to be executed, and running the bootstrap code while the compiler is running causes all kinds of explosions.

My next go at bootstrapping bore more fruit. I load the fanjardist.Main class and call the main method off of it via reflection in the static block. That runs the same bootstrap code, but since fanjardist.Main isn't present on the compile classpath, I get a ClassNotFoundException during compilation and don't run the bootstrap code. It's super-hacky, but it works well enough to get the Fantom subclass compiled and running on the emulator. Is there a more standard way of bootstrapping Fantom in non-main environments?

With that working, I attempted what I'm stuck on now, overriding a method from the android Activity class in my Fantom subclass. In HelloAct.fan I override onCreate, which gets called once the Android application is up and running. When super.onCreate gets called in there, I get java.lang.NoSuchMethodError: com.bungleton.anfan.FanActivity.onCreate from Dalvik. Using javap on the bytecode generated for HelloAct, I can see the super call is a standard invokespecial on the proper method, and it looks like the stack is being set up properly beforehand. I wrote an equivalent Java class, and the only difference in the bytecode for that method is that Fantom generates a stack size of 32 for the method, which is way larger than necessary. I thought perhaps the dalvik translator had trouble with that, but I edited the bytecode by hand to have an appropriate stack size, and it didn't make any difference.

At this point I'm kinda stumped. I'm assuming it's a problem in the translation of JVM bytecode to Dalvik bytecode, but I'm not sure where to look in the Dalvik bytecode. Are there other differences between Fantom classes and Java classes that could be leading to weirdness? The bytecode for a Fantom class looks really similar to the bytecode for a Java class to me.

vkuzkokov Thu 20 Jan 2011

Doesn't overriding onCreate() in FanActivity help?

brian Thu 20 Jan 2011

That will be a very cool project if you get it working!

I am not familiar at all with Andriod so I don't know specifics on that side. This problem sounds more like Andriod setup issue than Fantom issue. But I think you are the right track - figure out how to run the Fantom "main" code which JarDist generates.

Although I am not sure why that is causing a Fantom compiler problem. The Fantom code shouldn't need to compile against that Java code does it?

groves Thu 20 Jan 2011

@vkuzkokov No, overriding onCreate doesn't make any difference, and I don't think it should. You can override a method that's in the superclass of your superclass in Fantom, right?

@brian I've got Android running the Fantom main code; it's the calling of Java superclass methods from a Fantom subclass that's failing now. If I don't do that, the Fantom subclass is instantiated properly and can have other code in it called from Java.

The Fantom HelloAct extends the Java FanActivity, so it needs FanActivity to compile. HelloAct needs to extend FanActivity because FanActivity does the Fantom bootstrapping. If FanActivity's bootstraping code runs as part of the compiler's loading it, bad things happen.

In any case, I've worked around that by using reflection, so I'll keep poking at the Dalvik stuff to see what's getting lost in translation. I was just hoping there were some base-level differences between Java and Fantom classes that would be a good place to start.

tcolar Thu 20 Jan 2011

From http://fantom.org/doc/docLang/JavaFFI.html

Features which are not yet available in Java FFI:

  • Subclassing a Java class more than one level deep

Not sure if you are running into that, but could be, it caused me issues before and is quite limiting.

Other than that I'm wondering if their could be some classloader issues .. but I'm not familiar with android classloading.

tcolar Thu 20 Jan 2011

Also as far as bootstraping Fantom from Java, I do it in My Netbeans IDE.

This seem to be the minimum that works for me:

System.setProperty("fan.home", fanHome);
Sys.boot();

Login or Signup to reply.