Finally I have found a great dynamic language for writing Android apps - Rhino, a JavaScript implementation in Java. Rhino can run in interpreted mode, which makes it suitable for running on Dalvik (since on-the-fly byte code generation on Dalvik isn't implemented by dynamic languages, yet).
I used the work by Brice Lambson as a starting point. He has created a version of Rhino for the Android Scripting Environment (ASE). With the new release of the ASE you can now write scripts using JavaScript.
Since I want to write applications for Android in a dynamic language, I decided to experiment with embedding Rhino in an Android app. I created a new Android Java project, grabbed the Rhino jar-file from the ASE web site and dropped it in the libs directory. By browsing the documentation at the Rhino web site, it was quite straightforward to write a working demo.
Here is the code:
package miki.jsapp;
import android.app.Activity;
import android.os.Bundle;
import org.mozilla.javascript.*;
public class JSApp extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
doit(
"var widgets = Packages.android.widget;\n" +
"var view = new widgets.TextView(TheActivity);\n" +
"TheActivity.setContentView(view);\n" +
"var text = 'Hello Android!\\nThis is JavaScript in action!';\n" +
"view.append(text);"
);
}
void doit(String code)
{
// Create an execution environment.
Context cx = Context.enter();
// Turn compilation off.
cx.setOptimizationLevel(-1);
try
{
// Initialize a variable scope with bindnings for
// standard objects (Object, Function, etc.)
Scriptable scope = cx.initStandardObjects();
// Set a global variable that holds the activity instance.
ScriptableObject.putProperty(
scope, "TheActivity", Context.javaToJS(this, scope));
// Evaluate the script.
cx.evaluateString(scope, code, "doit:", 1, null);
}
finally
{
Context.exit();
}
}
}
very cool & good experiment, thank you very much for sharing.
ReplyDeleteI think newer Android installs have Google's V8 javascript engine embedded in them. Would it be possible to run android apps built out of javascript on top of V8?
ReplyDeleteIf so, the next step might be to try to leverage node.js within android, though I'm not sure if/how node's dependencies (even though they're limited) would work out. I can imagine some rather interesting lightweight daemons, or listening apps, you could put together if you can get node running on a smartphone.
It is a very cool idea to use the V8 engine! I guess the trick is how to make calls between Dalvik and V8. Wonder if someone has looked at that?
ReplyDeleteRhino is 'server side' interpreted JavaScript running in the JVM... it doesn't use V8, as far as I understand it. Think Jython, JRuby, Groovy.
ReplyDeleteYes, Rhino is implemented in Java and does not use V8, but if there would be a way to access Java libraries from V8 that would be an alternative way to run "native" apps written in JavaScript on Android.
ReplyDeleteThis is a really great post and I would really like to experiment with this further. I have checked the ASE downloads page for a .jar file, and there does not appear to be one! :(
ReplyDeleteCould you provide a link to the .jar file you used. It looks like the ASE people are now offering a stand alone interpreter and I would really like to be able to evaluate dynamic code WITHIN my java Android app.
Thanks!
Nevermind. I found the .jar file in the rhino extras .zip file. :)
ReplyDeleteOkay, real problem this time. When I reference the .jar file, the org.mozilla.javascript package shows up but appears to be empty. It looks like the bulk of the .jar file's contents are embedded in a .dex file within the .jar file and not in .class files as usual.
ReplyDeleteI have never seen this before and don't know how to get Eclipse to actually register the package contents.
Did you run into this issue? Thanks.
Hi David, I did not run into the Eclipse issue. Let me get back to you in a couple of days. Best, Micke
ReplyDeletecool
ReplyDeleteHi,
ReplyDeleteI played around with compilation for Rhino and managed to generate class files and dex/aapt them into a jar, which I copied to the device. Then I used DexClassLoader to load the classes in android. I was able to run simple Javascript files with code including creation of variables. However, I ran into a problem when I included functions and using liveconnect. When I used either, I got a CloneNotSupportedException thrown from the constructor of the newly created class. I cannot see a clone() call anywhere within the constructor, so I'm confused as to how to proceed further. Any help will be most welcome! Thanks in advance.
@Jay
ReplyDeleteSounds like very interesting work you are doing!
Perhaps clone() is called somewhere in the framework. Perhaps it would help to implement clone in the generated class? You could also try to ask for help on the Rhino mailing list.
Do you dex the files on the device? Would be very cool to do this.
Best, Micke
@Mikael,
ReplyDeleteI did try using the Rhino command line option to make the generated class implement the Cloneable interface, since I don't have direct control of the generated class bytecode (Its written by Rhino classfilewriter). This resulted in a wrapper class which implemented cloneable and a wrapped class which was essentially the same as before and gave the same exceptions. I further managed to get liveconnect working, previously I wasn't generating the package name correctly causing Java to fail somewhere within the VM. I don't dex the files on the device, since I can generate the class files on the host, I can use dx in command line mode too. Bad news is, that functions still don't work, (they fail with the same exception), I'm hoping its something similarly simple.
We all waiting for you to answer David's question!
ReplyDeleteOkay, real problem this time. When I reference the .jar file, the org.mozilla.javascript package shows up but appears to be empty. It looks like the bulk of the .jar file's contents are embedded in a .dex file within the .jar file and not in .class files as usual.
I have never seen this before and don't know how to get Eclipse to actually register the package contents.
Did you run into this issue? Thanks.
Hello
ReplyDeleteNice Tutorial
but when i run in eclipse it will show error
Dx at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
[2012-10-28 16:17:10 - HTMLViewer] Dx 1 error; aborting
[2012-10-28 16:17:10 - HTMLViewer] Conversion to Dalvik format failed with error 1
help me out where is my problem?
Thanks
Parag
I was having the same issue as you David, until I found out that the correct jar file is not that one. It is not in the download section of the ASE website, but you can grab it by cloning or downloading the project's source, or by using this direct link: http://code.google.com/p/android-scripting/source/browse/rhino/rhino1_7R2.jar
ReplyDelete