Sinatra running on a Motorola Droid |
You can start writing Ruby apps for Android devices TODAY. You don't need to install any SDK, you don't need to install some giant Eclipse IDE, and you certainly don't need to write any Java.
Some of you may have heard of Ruboto, but Damon Kohler and the team at android-scripting have been quietly improving SL4A over the past year, adding tons of features and improving stability.
We'd love to run some simple Ruby scripts on Android, but what about running a complete, albeit simple, application? Will it work?
Most Rubyists use Ruby to build web applications, so let's run with that. Let's build a spy camera app, so I can figure out who's been stealing ink cartridges from our office. The app should (a) show me a snapshot of what the camera currently sees and (b) update that snapshot on demand.
We need a simple, lightweight ruby framework to use. Sinatra is very easy to use and should even be able to run on older Android devices.
Similarly, we need a simple, lightweight, pure ruby web server. WEBrick is pure ruby, part of the standard library, and fast enough to run on Android. Works for me!
First, let's work from our development machine (i.e. laptop). No need to touch the phone just yet.
But wait! What about Sinatra itself? We can't easily install rubygems on our Android phone, so we'll have to vendorize Sinatra and all dependencies and ship them with our application. Since we'll be running JRuby on Android, we can't use any libraries that have native C extensions or are otherwise JRuby-incompatible.
First, let's set some constants for the important directories in our application. When running apps under SL4A, we need to be very explicit about directory paths.
Let's update our load path, so JRuby can find our vendorized gems.
Next, we'll load Sinatra. We'll have to explicitly load rack first, to avoid uninitialized constant errors under SL4A.
Finally, we require the Android API interface, available under SL4A, and initialize an Android object. This will allow us to make API calls, like one that tells the camera to take and store a picture.
Now, let's create a very simple HTML template. The template should just display the latest snapshot, which we'll be saving to public/latest.png. If I click on that snapshot, it should take a new snapshot and refresh the page.
Finally, create a tiny Sinatra app that takes a picture, saves it, and renders the template.
Once JRuby is installed, it's time to deploy your application to the phone.
Connect your phone to your development machine via USB, and simply copy the contents of your app to SL4A's script directory on your phone. There may be some sample ruby scripts left over from the SL4A install; you can delete them if you like.
At this point, just run spycam.rb from SL4A and you're good to go!
Place your newly-activated spy camera somewhere, hide in your office/cube, start your web browser, and navigate to http://ip.address.of.phone:4567. You can do this from inside your local network via wifi, or, carrier permitting, over 3G.
Further Reading
Some of you may have heard of Ruboto, but Damon Kohler and the team at android-scripting have been quietly improving SL4A over the past year, adding tons of features and improving stability.
There's even support for distributing programs as APKs, so the implementation language and dependencies are totally transparent to users.Scripting Layer for Android (SL4A, formerly known as Android Scripting Environment or ASE) brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreters directly on the Android device. These scripts have access to many of the APIs available to full-fledged Android applications, but with a greatly simplified interface that makes it easy to get things done... Python, Perl, JRuby, Lua, BeanShell, JavaScript, Tcl, and shell are currently supported, and we're planning to add more.
We'd love to run some simple Ruby scripts on Android, but what about running a complete, albeit simple, application? Will it work?
Most Rubyists use Ruby to build web applications, so let's run with that. Let's build a spy camera app, so I can figure out who's been stealing ink cartridges from our office. The app should (a) show me a snapshot of what the camera currently sees and (b) update that snapshot on demand.
We need a simple, lightweight ruby framework to use. Sinatra is very easy to use and should even be able to run on older Android devices.
Similarly, we need a simple, lightweight, pure ruby web server. WEBrick is pure ruby, part of the standard library, and fast enough to run on Android. Works for me!
First, let's work from our development machine (i.e. laptop). No need to touch the phone just yet.
Start a New Sinatra Project
But wait! What about Sinatra itself? We can't easily install rubygems on our Android phone, so we'll have to vendorize Sinatra and all dependencies and ship them with our application. Since we'll be running JRuby on Android, we can't use any libraries that have native C extensions or are otherwise JRuby-incompatible.
Make Directories for Gems and Snapshots
Vendorize your Gems
Create the App
Create a file called spycamera.rb in the project directory.First, let's set some constants for the important directories in our application. When running apps under SL4A, we need to be very explicit about directory paths.
Let's update our load path, so JRuby can find our vendorized gems.
Next, we'll load Sinatra. We'll have to explicitly load rack first, to avoid uninitialized constant errors under SL4A.
Finally, we require the Android API interface, available under SL4A, and initialize an Android object. This will allow us to make API calls, like one that tells the camera to take and store a picture.
Now, let's create a very simple HTML template. The template should just display the latest snapshot, which we'll be saving to public/latest.png. If I click on that snapshot, it should take a new snapshot and refresh the page.
Finally, create a tiny Sinatra app that takes a picture, saves it, and renders the template.
Install (Deploy) The App
Now you can finally use your phone! Grab that Android device and install SL4A (r1 APK available here). Run SL4A, go to the interpreters menu, and install JRuby.Once JRuby is installed, it's time to deploy your application to the phone.
Connect your phone to your development machine via USB, and simply copy the contents of your app to SL4A's script directory on your phone. There may be some sample ruby scripts left over from the SL4A install; you can delete them if you like.
Copying the project contents onto the deivice. |
At this point, just run spycam.rb from SL4A and you're good to go!
Starting the Sinatra app from SL4A |
Place your newly-activated spy camera somewhere, hide in your office/cube, start your web browser, and navigate to http://ip.address.of.phone:4567. You can do this from inside your local network via wifi, or, carrier permitting, over 3G.
Happy spying! |
Further Reading
Check out my open-source project, Broadcast, on Github. It's a more refined, general-purpose embedded web app for Android. It allows for further remote monitoring and control, such as location tracking, remote text-to-speech, and remote file management over HTTP.
The source code for the spycam app is available on github here.
Check these out, too:
The source code for the spycam app is available on github here.
Check these out, too:
12 comments:
thanks for sweet script :)
connect via 3G network with ssh tunnel(using ConnectBot and my ssh server) - http://flic.kr/p/8xf3BG
Nice! BTW, Ruboto now supports creating .apks as well: ruboto-core
Ooo, super fun! Thanks!
It doesnt work, I get this error:
spycam.rb:6: syntax error, unexpected tCONSTANT, expecting '}'
...LOAD_PATH << File.join GEM_DIR, dir, 'lib'}
^
spycam.rb:6: syntax error, unexpected '}', expecting tCOLON2 or '[' or '.'
spycam.rb:44: syntax error, unexpected $end, expecting '}'
Sigmar, thanks for the heads up. I fixed the error, and changes have been pushed here.
Great tutorial, thanks!
One problem however, I hear my phone taking the pictures, but they are completely black, any idea?
I'm on HTC Hero, Android 2.1
Spint, if your camera normally works fine but isn't taking pictures properly with this app, it's probably an issue with SL4A and the HTC Hero in particular. You should file a bug here; the team is always improving support for more devices.
At first, camera support for my Motorola Droid was a bit spotty, but I filed a bug and they had it fixed and released within a week or two.
Ok Mike, apparently there was already a related issue (#400), tnx !
nice stuff! I knew about sl4a but didn't know it was this easy now
Yo,
Doesn't work for me.
I get
Dalvik VM unable to locate class 'org/jruby/Main'
java.lang.NoClassDefFoundError: org.jruby.Main
Any ideas?
Great! I tried it on my Nexus One and works! JRuby crashes from time to time, though.
I'll play a bit with this, thanks!
@AJ
I get the same error on my HTC magic, after a few minutes webrick starts up. Because my phone is rather slow i suspect thats wat's causing the error, works later on.
Post a Comment