Ruboto: Ruby on Android

A flexible scripting approach to the Dalvik virtual machine

A common language brings together two dissimilar partners: the Ruby scripting language and Google's custom format for Android programs. Thanks to the robust toolkits in the JRuby and Android projects, you can write and run Ruby scripts that behave dramatically differently from the typical Android program.

Share:

Chris King (christopher.c.king@gmail.com), Software Engineer, Freelance

Photo of Chris KingChris King is a software engineer specializing in mobile development. He is the author of Advanced BlackBerry Development, Advanced BlackBerry 6 Development, and Android in Action, Second Edition.



22 March 2011

Also available in Chinese Japanese Vietnamese

Introduction

Most of the interesting work in software development today occurs at one of the two extremes: huge cloud servers and tiny mobile devices. These domains solve significantly different problems, and, correspondingly, have different tool support. Server development often uses scripting languages to tie together different components and accomplish sophisticated automated tasks, while mobile development focuses on the particular capabilities and needs of a particular device and user.

However, these two extremes share a common language: Java™. Whether Android or the Spring framework, many of the most popular technologies today have adopted a language that's widely understood and supported around the world. This common language can lead to some surprising interactions between areas that you tend to think of as distinct. Java programming opens the door for many cross-platform options, such as easily porting server code to an Android device or tying into native platform abilities from existing components.

This article explores Ruboto, a project that bridges the gap between scripting languages and Android. You will learn about Ruby and Android, how they can come together in the Dalvik virtual machine, how to build and deploy your own scripts, and how this technology has potential for increasing programmer productivity and application flexibility.


Ruby background

Many scripting languages compete for programmers' affections, but Ruby currently holds a powerful position. Most famously, it supports the Rails web framework, but many developers also admire Ruby for its combination of terseness and elegance. An object-oriented scripting language with many modern features like duck typing and metaprogramming, Ruby is robust enough to support complex architectures and simple enough to perform ad hoc tasks.

Ruby comes in several flavors, including the popular JRuby. JRuby is a full Ruby interpreter that is written in the Java language and can run in a Java Virtual Machine (JVM). Unlike the official Ruby, JRuby lets you call Ruby scripts from within Java code, as well as call Java APIs from within your Ruby scripts.


Android background

Android was developed by the Open Handset Alliance, but it is most often thought of as a Google project. Today, Android powers about one quarter of all new smartphones, and its share of the market continues to rise.

Internally, Android runs on a modified Linux kernel. Most applications run in the Dalvik virtual machine (VM), a custom VM that Google designed from the ground up for optimal performance on mobile devices. You can learn more about Dalvik in Resources.

One point many new Android developers miss is that the Java source code they write does not run as Java bytecode. Instead, the Android toolkit converts Java bytecode into Dalvik bytecode. These converted files, which have the .dex extension, are packaged in the application that you deploy to the device. By the time the device runs your program, there's no Java bytecode left.


Android + Ruby = Ruboto

Charles Nutter, a member of the JRuby team, had an epiphany: because the Android toolchain could convert compiled Java code to Dalvik files, and because JRuby had a Ruby interpreter in compiled Java bytecode, then he should be able to run Ruby on Android. Within an astonishingly short time, he had performed this task, and Ruboto was born. Thanks to the efforts of several other developers, Ruboto has become an active project that is growing increasingly intriguing to Android and Ruby developers alike.

Today, Ruboto comes in two flavors: ruboto-irb and ruboto-core. ruboto-irb is an interactive Ruby shell that runs on Android. This project lets you run arbitrary Ruby scripts that can also access Android APIs. This tool may be very useful for developers who want to run tests or perform tasks on their device, but is probably not appropriate for writing applications that you later distribute.

In contrast, ruboto-core provides a framework that lets you create your own Ruboto projects. Using ruboto-core, you can add powerful and flexible scripting support to your project, while retaining access to the Android APIs. Figure 1 shows the ruboto-core build process: auto-generated Java source files and your custom-written Ruby scripts get packaged together into an Android APK that will run on the device.

Figure 1. Constructing a Ruboto app
Flowchart showing the flow from Ruboto Java files to APK.

The remainder of this article focuses on creating a custom Ruboto-based project. Ruboto is still early software; as of this writing, its version number is 0.0.2. It continues to evolve quickly, and may behave slightly differently by the time you read this article. If you encounter issues while running any of the commands below, please see Resources to get the most up-to-date information on Ruboto and Android.


Scripting SMS

Bringing together Ruby and Android lets you create simple scripts that can access Android's powerful functions. You will write a Ruboto script that lets users order seafood from a delivery service. This simple application takes advantage of the strengths of each platform. On the Android side, you will have a simple way to create an SMS message containing your order; the application places orders without even requiring a server. On the Ruby side, you will re-use an existing language processing library that will normalize your orders into a readable format.


Getting started

To build and deploy your Ruby scripts on Android requires several components. You may already have some of these installed; if so, you can use those existing tools.

Because both Android and Ruby are multi-platform, you can run Ruboto on Linux®, Mac OS X, or Windows®. You will use the command line throughout this article.

If you use cygwin for Windows, you may encounter problems while running certain JRuby commands. To be safe, stick with the standard Windows CMD shell if you are running Windows.

Java

You will need a working Java Development Kit (JDK) on your development box. To check if one is already installed, enter the following command:

$ javac -version

If this command finds a version of the JDK, you are set. If not, install the latest version of the JDK from the link in Resources. After installation, add the JDK's bin folder to your PATH and repeat the above command.

Ant

Android ships with its own version of Ant, but Ruboto will need to access Ant as well from its own scripts. If you don't have a stand-alone version of Ant installed, download it from the link in Resources and unzip to any folder. Again, add its bin folder to your PATH. Make sure you can run the Ant command.


Android

Go to the Android Developer Site and install the Android SDK for your operating system (see Resources). After this installs, run the android command located in Android's tools folder. This launches the SDK manager, as shown in Figure 2. You will want to install the following packages, which are listed under Available packages.

  1. SDK Platform Android 2.2, API 8
  2. Android SDK Tools, revision 8
  3. Android SDK Platform-tools, revision 1
Figure 2. Android SDK and AVD Manager
Window showing a list of the available packages.

Create an Android image for development by opening the Virtual devices section of the Android SDK and AVD Manager. Referring to Figure 3, create a virtual device named Froyo that targets Android 2.2 - API Level 8. You can create a virtual SD Card if you like.

Figure 3. Creating an emulator
Window with fields for name: froyo, target: Android 2.2 - API Level 8, 1024 SD card size, skin: default, hardware.

Ruboto apps will run on your device, but development will be much easier if you have write access to arbitrary folders, which requires either using the emulator or a rooted device. The rest of this article focuses on using the emulator. After you finish the project, it will run equally well on an Android device running software version 2.2 or later.

Add Android's platform-tools and tools directories to your PATH. You should now be able to run the commands in Listing 1 from your prompt.

Listing 1. Running commands from your prompt
$ aapt version
$ adb --version

JRuby

JRuby offers an incredibly easy installation. Simply go to http://jruby.org/getting-started and follow the directions. If necessary, add the JRuby bin folder to your PATH. Verify that the installation succeeded by typing the following command:

$ jruby -v

Because Ruboto is hosted on a secure server, you'll need to install the jruby-openssl gem to download it. You can do this with the following command:

$ gem install jruby-openssl

You will also want to install rake, Ruby's equivalent to make or ant. Type the following command:

$ gem install rake

Finally, it's time to install Ruboto itself. Ruboto comes packaged as a gem, so installation is easy. Enter the following command:

$ gem install ruboto-core

Creating the Ruboto project

Ruboto will create an Android project from scratch for you, which ensures that your manifest is set up correctly, scripts are placed in the right collection, and you have access to the necessary libraries. You should take this approach rather than trying to create it yourself or modifying an existing Android project.

To create the project, move to a project folder, then type the following:

$ ruboto gen app --package us.cirion.ruboto.demo --path fishmonger --name Fishmonger --target android-8 --activity Fishmonger

This command does the following:

  • gen app tells Ruboto to create a new Android project from scratch.
  • --package provides the unique Android package name.
  • --path tells Ruboto where to store the project; this must be a new folder name.
  • --name defines the user-visible name of the application; this does not need to be unique.
  • --target specifies which Android version to compile the project against. As of this writing, you must use android-8. An optional argument, --min_sdk, declares that your application can run on earlier Android versions; omit this for now.
  • --activity is an optional argument that tells Ruboto to generate a new Android activity and initialize it.

You can explore the contents of the fishmonger directory. Ruboto has automatically generated all of the Android files necessary to build and run a basic Activity. Because the application will send SMS messages, you do need to make one change within the AndroidManifest.xml file. Insert the following tag as the first child of the <manifest> element in that file:

<uses-permission android:name="android.permission.SEND_SMS" />

If you omit this permission, you will still be able to build and load your script, but you will get a run time error when your application tries to send an SMS message.


Running the default project

Out of the box, Ruboto generates an Activity and script that will install and run on the device or emulator. If your emulator is not already running, you can launch it with the following command:

$ emulator -avd Froyo

Wait for the emulator to finish booting to the home screen. To ensure all Ruboto files get built and deployed properly, cd to the fishmonger directory and run the following command:

$ rake install

If you encounter an error, try running the command again; sometimes the connection times out during the build process. The initial build takes a while, but later updates happen more quickly. After the installation completes, look for the icon labeled Fishmonger in your emulator. Launch it and wait. As of this writing, the Ruboto engine takes a while to load. Eventually, you will see a screen similar to Figure 4 display.

Figure 4. The template Ruboto activity
Emulator with a window on the left and a keypad and control buttons on the right.

Customizing the project

Now, let's set up the Fishmonger app. First, you'll add natural language support. Ruby has an excellent gem called linguistics that offers many English-language capabilities. As of this writing, Ruboto does not handle the nested directory structure of the linguistics library, so please download this article's linguistics zip file instead and unzip the contents into fishmonger\assets\scripts (see Downloads for a link). This is the stock linguistics gem, modified to flatten out the directory structure. In the future, you should be able to just bundle the gem with your ruboto script.

Writing the script

You're now ready for the meat of the project. The Ruboto framework takes care of all the Java code and Android infrastructure, so all of your work can take place in fishmonger.rb. Erase the default contents of the file. You'll start by adding the text in Listing 2.

Listing 2. Script dependencies
require 'ruboto.rb'
require 'linguistics'
include Linguistics::EN

import "android.telephony.SmsManager"

ruboto_import_widgets :Button, :EditText, :LinearLayout, \
  :RadioGroup, :RadioButton, :TextView

The first two lines load the ruboto and linguistics libraries. The include command will make English language grammar available in your module.

The first import will look familiar to JRuby users: you are adding support for another class. Note that in this case, you're actually using an Android Dalvik class, not a part of the standard Java library. Ruboto will use reflection at run time to load this class and make it available to you.

ruboto_import_widgets behaves similarly. Here, you're adding some Android-specific UI widgets. These are commonly used in Android activities, and Ruboto adds some convenience methods that let you more easily configure the UI.

Next, define the script's handle_create method, as shown in Listing 3.

Listing 3. Configuring the screen
$activity.handle_create do |bundle|
  setTitle 'Freddy\'s Fresh Fish'

  setup_content do
    linear_layout :orientation => LinearLayout::VERTICAL do
      text_view :text => "What would you like to order?"
      @group = radio_group do
        radio_button :text => "Tuna", :id => 0
        radio_button :text => "Trout", :id=> 1
        radio_button :text => "Salmon", :id => 2
        radio_button :text => "Crab", :id => 3
        radio_button :text => "Lobster", :id => 4
      end
      @quantity = edit_text :hint => "Quantity"
      button :text => "Place Order"
    end
  end

handle_create gets called when the user launches the application. In Android, this is where you handle the necessary setup. Standard Android applications generally use XML to define the layout, but in Ruboto, you'll script it instead.

Again, take advantage of Ruboto's functions that provide a bridge between your script and Android. Regardless of your background with Ruby or Android, you should be able to see what's happening within setup_content. You are creating a vertically oriented layout that stacks several widgets on top of each other. This includes text, radio buttons for choosing the type of fish to order, an editable text field for entering the quantity, and a button to place the order. You can use Ruby syntax for configuring your widgets, instead of the more verbose Java syntax generally used in Android.

Setting the id attribute on each radio_button is a bit of a hack; it gives you an easy way to later look up which button was selected.

Android will automatically handle all user interaction with the radio buttons and editable text field. The only piece left to define is handling the Place Order button, shown in Listing 4.

Listing 4. Placing an order
  handle_click do |view|
    if view.text == "Place Order"
      count = @quantity.text
      food = @group.child_at(@group.checked_radio_button_id).\
        text.downcase
      order = Linguistics::EN::plural(food,count)
      SmsManager.default.send_text_message("4155551234", \
        nil, "Please send #{count} #{order}", nil, nil)
      finish
    end
  end
end

If you have previously written Android applications, you'll notice that you're using a different paradigm for handling selection. Android developers tend to write unique click handlers for each selectable item. In Ruboto, though, it's easier to create a global click handler for your Activity, and within there to test for which item the user clicked.

You extract the number and the type of fish that the user chooses. If they did not check a radio button, Ruboto will internally handle the run time error gracefully. Otherwise, you will pass off the text to the linguistics library and ask it to create the proper noun form for you. The library can handle the different rules for pluralization, so it will generate values like 1 salmon, 2 salmon, 1 crab, 2 crabs, and so on. It even recognizes written numbers, so it will also create phrases like one lobster, three lobsters, and so on. This is very impressive behavior for a single line of code and shows the power of leveraging existing scripts to easily add capabilities to your application.

Likewise, sending an SMS message requires only a one-line call to a convenient Android method. Ruboto lets you use Ruby-style syntax to invoke this method; the Java code equivalent would be SmsManager.getDefault().sendTextMessage(). You provide the recipient's phone number and the text to send, and pass nil for the optional parameters. If you are running on a device and would like to actually send an SMS message, substitute a valid phone number. If you want to test in the emulator, you can substitute an emulator's port number, such as "5554."

Running the script

One of the most powerful aspects of Ruboto is that you can change functionality by simply loading an updated script. Even though you have completely changed what this application does, you do not need to rebuild the application or reload the APK. Instead, type the following at the command line:

$ rake update_scripts

This will copy the linguistics scripts and your new fishmonger script to the emulator or an attached device. When you relaunch the application, you will see your new screen, as shown in Figure 5.

Figure 5. Android ordering page
A screen showing options to order tuna, crab, trout, salmon, and lobster along with an amount and place order button.

If you are running a non-rooted device or make any changes to the Java files or the Android manifest, you can load the update by typing the rake installation command again. Note that even non-rooted devices can update their scripts on the fly; for example, you could download new scripts from the Internet or generate them at run time. The firmware limitation only applies to pushing files over your USB connection.

Go ahead and play around with the application. After you make a valid selection and press the order button, the screen will automatically close. If you used a valid recipient address, they will shortly see your message arrive. Figure 6 shows the very busy fishmonger's list of recent orders.

Figure 6. Standardized orders from Ruboto script
Screen showing 4 different orders.

Conclusion

Ruboto is still an early effort, but even in its current state it provides a very useful and flexible way to write and distribute Android software. Ruboto's success results from the strengths of JRuby and Android: JRuby has already done the hard work of writing a full Ruby interpreter in the Java language, and Android's Dalvik toolchain provides an impressive conversion from standard Java bytecode to its custom Dalvik bytecode.

As you've seen, Ruboto scripts can be extremely short, while offering strong capabilities from both Ruby and the Android. The ability to mix and match Ruby scripts, Ruby and Java syntax, and Android APIs gives you many options for increased productivity.

Ruboto is a compelling bridge to developers on both sides of the client/server divide. Android developers will appreciate its reflective powers, which give them the ability to dramatically update application capabilities on the fly. Ruby developers have gained a fairly painless way to bring their scripting expertise to the mobile platform and can leverage existing Ruby code to create new applications. Both camps will be watching with great interest as this project further matures.


Downloads

DescriptionNameSize
Article source codefishmonger.zip65KB
Article source codelinguistics-rb.zip34KB

Resources

Learn

Get products and technologies

  • Download the Android SDK, access the API reference, and get the latest news on Android from the official Android developers' site. Version 1.5 and later will work.
  • Android is open source, which means you can get the source code for it from the Android Open Source Project.
  • Get JDK 6 Update 21.
  • Download Ant.
  • Innovate your next development project with IBM trial software, available for download or on DVD.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=642287
ArticleTitle=Ruboto: Ruby on Android
publish-date=03222011