Scala and Android in an Eclipse project

Android

This article is an introduction on how to build Scala Eclipse projects for Android. You may also want to read an IBM article on the same topic.

For a quick start, the two key issues are:

  1. The Scala builder has to be at the right position in the builder chain
  2. The project's bin folder has to be the first entry in the project's class path 

1. Preparation

Follow these instructions to install the Eclipse Scala plugin, if you haven't already. Make sure you have the Android SDK, and the Android (ADT) plugin installed. After setting the Android SDK location in Eclipse under Window->Preferences->Android, you should be ready to develop Android applications with Java.

 

2. Scala's android-library

Note: For Android 1.0, Release 2 and possibly later, you can choose to skip this section. Read below for details.

Android does not support all of the standard Java class libraries. Hence, it is useful to create a stripped version of the Scala standard library that only uses those features that are available on Android.

On Android 1.0, Release 2, the class loader/verifier seem to load and verify classes only when needed. Consequently, you can use the standard Scala library without modifications as long as you don't use classes that refer to features not available on Android, such as scala.reflect.ScalaBeanInfo that refers to package java.beans. Nevertheless, it might be useful to create a stripped library jar to be on the safe side.

For the latest version of Scala, you have to build your own scala-android library. For Scala 2.7.0 you can download the android-library with sbaz and skip the next section.

2.1. Compile and package

Download the scala sources from SVN.

There is currently no ant target in the build.xml file to build the android-library. Here is a quick and dirty solution: copy the content of the directory src/android-library to src/library and overwrite existing files. Now type ant in your Scala SVN checkout folder. This creates a scala-library.jar in folder build/pack/lib. Rename it to android-library.jar and save it for later use.

 

3. Create the project

Create an Android project under Project Wizard -> New -> Android -> Android Project. For this introduction, name your package hello and your activity class ScalaOnAndroid.

Then add the Scala nature to this project with Scala -> Add Scala Nature from the project's context menu.

Go to the project properties dialog. Under Builders move the Scala Builder between the Android Pre Compiler and the Android Package Builder. For reference, your .project file should now look like this:

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>scala-on-android</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>ch.epfl.lamp.sdt.core.scalabuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>com.android.ide.eclipse.adt.ApkBuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>ch.epfl.lamp.sdt.core.scalanature</nature>
		<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
		<nature>org.eclipse.jdt.core.javanature</nature>
	</natures>
</projectDescription>

Now include the android-library.jar to the project dependencies. Open the project properties and go to the java build path -> libraries tab. Remove the "Scala Library" and add the android-library.jar as an external JAR.

Last but not least, remove the automatically generated Java Activity, and replace it with one of the following Scala classes. (Your new Activity should have the same name and package as the removed Java class.) You can either reuse the generated Android resource class R:

package hello
 
import android.app.Activity
import android.os.Bundle
 
class ScalaOnAndroid extends Activity {
  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)
  }
}

or create a message programmatically:

package hello
 
import android.app.Activity
import android.os.Bundle
import android.widget.TextView
 
class ScalaOnAndroid extends Activity {
  override def onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    val tv = new TextView(this)
    tv.setText("Hello Android, it's me, Scala!")
    setContentView(tv)
  }
}

Sometimes, you get weird error messages such as

hello.ScalaOnAndroid must be public, or the system will not be able to instantiate it

Do a clean build (Project -> Clean) and/or close and reopen the project in such cases.

Finally, you can launch your application with right click on your project -> Run As... -> Android Application.

There is one more step. Some Scala features such as inner functions seem to be problematic for the ADT. Follow the next section on how to convince the ADT to cooperate.

 

4. Add bin folder to the class path

Go to the project properties. Under Java Build Path -> Libraries add the project's bin folder as an external class folder. Go to the Order and Export tab and move the newly added folder to the top of the list. For reference, your .classpath should now look like this: 

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="lib" path="<path-to-your-workspace>/scala-on-android/bin"    />
	<classpathentry kind="src" path="src"    />
	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"    />
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"    />
	<classpathentry kind="lib" path="<path-to-your-Scala-install>/lib/android-library.jar"    />
	<classpathentry kind="output" path="bin"    />
</classpath>

This step is necessary due to some integration problem with the Java (JDT) Eclipse plugin. The Android plugin uses the JDT to check whether the main activity really extends android.app.Activity. For Scala classes from source files with inner functions, the JDT doesn't seem to find all super classes (for whatever reason). After adding the bin folder to the top of the Order and Export list the problem goes away, presumably because the type hierarchy is then build from class files which seem to pose no problem.

Copyright © 2009 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland