Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Wednesday, May 9, 2012

Building Android apps in Scala with sbt



If you're thinking about developing Android apps in Scala there are not that many different options for building your project - I started out with a hack based on Rake (source), then there are some ways to get Eclipse to build your project, as documented on the Novoda blog. I personally don't use an IDE, Scala is in contrast to Java perfectly usable in a normal text editor, mainly because it requires a lot less typing and boiler plate code.
My solution based on Rake worked well but had a couple of shortcomings - it added another language to the codebase, and not everyone is necessarily familiar with Ruby, additionally your build time gets longer as the Scala compiler will always perform a full rebuild of the project. A Scala source file typically produces more than just one single class file, so it's not possible to perform a simple time stamp-based check and just recompile changed files. Unfortunately the compiler itself is not able to figure out which files need rebuilding (coming in Scala 2.8). The Scala based build system sbt (simple build tool) implements partial recompilation which means that the code will get built a lot faster. Besides speed improvements it also gives you a complete build tool with external dependency management using Apache Ivy (Maven dependencies are supported as well).
Sbt also follows Rake's approach of using the language itself for the configuration of the build which gives you additional flexibility and expressiveness over static XML files. It also makes the reuse of build steps a lot simpler because you can use the host language's natural abstraction mechanisms. So when I decided to reimplement my build system with sbt it turned out that someone had already written an Android plugin for it. Mark Harrah, the author of sbt, extracted it from someone else's Android project and released it on github, where I found it. I had to make a couple of modifications to get it to build my project but it quickly became obvious that sbt was a better fit for Android Scala projects than any other ad hoc solution. Mark merged my changes back into his repository and eventually asked whether I wanted to take over maintenance of the plugin, hence this introductory blog post. Let's get started!

Installing sbt

First you need to install sbt itself (assuming that Scala is already installed). Detailed instructions are available here, but in a nutshell:

  $ cd ~/bin # or any other directory in your path
  $ wget http://simple-build-tool.googlecode.com/files/sbt-launch-0.7.4.jar
  $ echo 'java -Xmx512M -jar `dirname $0`/sbt-launch-0.7.4.jar "$@"' > sbt
  $ chmod u+x sbt
  
If you're on OS X and use homebrew you can take a shortcut with brew install sbt.

Generating a new project

To get started with new projects sbt already ships with a generator which will set up the initial directory structure (run sbt without arguments). Unfortunately, when using plugins the situation is a bit more complicated as the plugin itself needs to be set up. To make things simpler I created a Scala script to bootstrap a full Android project with sbt. You simply call it with the name of your project and package:

  $ git clone git://github.com/jberkel/android-plugin.git
  $ cd android-plugin
  $ script/create_project foo com.example.android
  
This will create a fully usable Android project called Foo with one activity (showing Hello World).
The generated directory layout follows Maven conventions:

    |-- project
    |   |-- build
    |   |   `-- Foo.scala
    |   |-- build.properties
    |   `-- plugins
    |       `-- Plugins.scala
    |-- src
    |   |-- main
    |   |   |-- AndroidManifest.xml
    |   |   |-- assets
    |   |   |-- java
    |   |   |-- res
    |   |   |   |-- drawable
    |   |   |   |-- layout
    |   |   |   |-- values
    |   |   |   `-- xml
    |   |   `-- scala
    |   |       `-- Activity.scala
    |   `-- test
    |       `-- scala
    |           `-- Specs.scala
    `-- tests
  
The sbt build configuration is in the project directory, source code and unit tests in srctests is used for Android integration testing (more on that later).

Build configuration

The main project build information is contained in the file project/build/Foo.scala:

  import sbt._

  trait Defaults {
    def androidPlatformName = "android-1.6"
  }
  class Foo(info: ProjectInfo) extends ParentProject(info) {
    override def shouldCheckOutputDirectories = false
    override def updateAction = task { None }

    lazy val main  = project(".", "foo", new MainProject(_))
    lazy val tests = project("tests",  "tests", new TestProject(_), main)

    class MainProject(info: ProjectInfo) extends AndroidProject(info) with Defaults {
      val scalatest = "org.scalatest" % "scalatest" % "1.0" % "test"
    }

    class TestProject(info: ProjectInfo) extends AndroidTestProject(info)
                                         with Defaults
  }
  
The project definition is contained in the class Foo which extends ParentProject, a special sbt construct for supporting multiple projects in one single file (sub project documentation). This is necessary because Android integration tests have to be built and installed as a separate apk package. Note the use of Scala's traits to mix in default settings for both projects. If you don't need integration tests in your application you can use a simpler project definition which could look like this:

  import sbt.__
  class Foo(info: ProjectInfo) extends AndroidProject(info) {
    override def androidPlatformName = "android-1.6"
  }
  

Dependency management

The main advantage of using sbt/Ivy as a dependency manager is that you declare your dependencies programmatically instead of shipping all the jar files with your project, sbt will then figure out on build time which libraries to download. In sbt, an external dependency is declared as follows:

   val scalatest = "org.scalatest" % "scalatest" % "1.0" % "test->default"
  
This declares a dependency to the module "scalatest" (a Scala test framework), using version 1.0 in the test configuration. A configuration in Ivy works similar to scopes in Maven, you usually use them to separate build and runtime dependencies (sbt will automatically exclude build dependencies from the package).

Hello Android

Besides creating the necessary directory structure for building Scala projects the generator script will also create a simple "Hello World"-style activity, which can be found in src/main/scala/Activity.scala.

  class MainActivity extends Activity {
    override def onCreate(savedInstanceState: Bundle) {
      super.onCreate(savedInstanceState)
      setContentView(new TextView(this) {
        setText("hello, world")
      })
    }
  }
  
In order to build the full package, use the package-debug sbt action:

  $ export ANDROID_SDK_HOME=path/to/android_sdk
  $ sbt update             # download dependencies
  $ sbt package-debug      # build packages
  $ sbt reinstall-emulator # (re)install in emulator
  
This will download all dependencies, then compile and build the two packages (target/foo-0.1.apk,tests/target/tests-0.1.apk). It is worth noting that sbt has two different modes of operation: interactive and command-line. If invoked without action arguments, the interactive session will be launched, which saves start-up time and is quite useful in general.
Sbt will automatically recompile the project definition (even when in interactive mode) which makes it almost as easy to use as other script-based build systems.

1,2,3 testing

Sbt has built-in support for most common Scala testing frameworks (ScalaCheck, specs, ScalaTest). It tries to automatically detect the framework you are using in your project, usually "sbt test" will do the Right Thing. The example project set up by the script defaults to ScalaTest which has excellent BDD support with a DSL similar to rspec's.
Writing Android specs using a Scala framework like ScalaTest is a very convenient way to test generic functionality, but does not replace running tests on the device / emulator itself. The DalvikVM is very different from a normal Java VM (smaller stack sizes etc.), so you should always test on device as well. On Android this is quite painful: you have to create a separate project, get the dependencies right, install the package in the emulator and run a command. With sbt's multiproject support it becomes quite easy to handle integration tests, you can subclass AndroidTestProject to get some additional actions for running tests (test-emulator and test-device). Sbt will also track dependencies between your main and test project.
Another nifty feature is continuous compilation / testing. When you prefix any action with a tilde (~), sbt will automatically trigger it as soon as one of the source files changes, which is very useful when doing test-driven development.

Demo




zegoggl.es
read more...

Your first scala-android apk

Ok, so far we've done some basic stuff. Here's some more before we really get to the good stuff. This post only contains the configuration for getting Scala working with Android. The next tutorial is going to include all the configurations to get a proper Android application packaged with Maven.

To get your environment running, please check this post by Janne.

Ok, let's get to the interesting part. Combining Scala, Maven and Android SDK with a working development environment.

Properties

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>5</maven.compiler.source>
    <maven.compiler.target>5</maven.compiler.target>
</properties>

New dependencies
  • Android
  • Andengine (2d engine)
<dependencies>
    <dependency>
        <groupId>com.google.android</groupId>
        <artifactId>android</artifactId>
        <version>2.3.3</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.andengine</groupId>
        <artifactId>andengine</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

Since the Andengine package is not included in any Maven repository, you'll need to add the file by hand:

mvn install:install-file -Dfile=path-to-andengine.jar/andengine.jar -DgroupId=org.andengine -DartifactId=andengine -Dversion=1.0 -Dpackaging=jar

You can download the Andengine file here.

Remember to set packaging to apk!
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>first-application</artifactId>
<version>1.0</version>
<packaging>apk</packaging>
<name>first-application</name>


Plugins
The Android plugin that handles the apk generation.

<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>maven-android-plugin</artifactId>
    <version>2.8.4</version>
    <configuration>
        <sdk>
            <!-- Don't forget to set your ANDROID_HOME environment variable to your SDK directory! -->
            <path>${env.ANDROID_HOME}</path>
            <!-- Platform 10 is Android 2.3.3 -->
            <platform>10</platform>
        </sdk>
        <jvmArguments>
            <jvmArgument>-Xmx1024m</jvmArgument>
        </jvmArguments>
        <!-- All of these go into the /src/main/android/ directory, we don't
        want to polute the project root directory. -->
        <androidManifestFile>${project.basedir}/src/main/android/AndroidManifest.xml</androidManifestFile>
        <resourceDirectory>${project.basedir}/src/main/android/res</resourceDirectory>
        <assetsDirectory>${project.basedir}/src/main/android/assets</assetsDirectory>
        <nativeLibrariesDirectory>${project.basedir}/src/main/android/native</nativeLibrariesDirectory>
        <resourceOverlayDirectory>${project.basedir}/src/main/android/overlay</resourceOverlayDirectory>

        <deleteConflictingFiles>true</deleteConflictingFiles>
        <undeployBeforeDeploy>true</undeployBeforeDeploy>
    </configuration>
    <extensions>true</extensions>
</plugin>
Last we need the most important plugin of them all, ProGuard. Without this plugin the apk generation will fail since the Scala dependency will generate too many files.
<plugin>
<groupId>com.pyx4me</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>2.0.4</version>
    <executions>
        <execution>
            <phase>process-classes</phase>
            <goals>
                <goal>proguard</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <injar>android-classes</injar>
        <libs>
            <lib>${java.home}/lib/rt.jar</lib>
        </libs>
        <obfuscate>false</obfuscate>
        <options>
            <option>-keep public class * extends android.app.Activity</option>
            <option>-keep public class * extends android.app.Application</option>
            <option>-keep public class * extends android.app.Service</option>
            <option>-keep public class * extends android.content.BroadcastReceiver</option>
            <option>-keep public class * extends android.content.ContentProvider</option>
            <option>-dontskipnonpubliclibraryclasses</option>
            <option>-dontoptimize</option>
            <option>-printmapping map.txt</option>
            <option>-printseeds seed.txt</option>
            <option>-ignorewarnings</option>
        </options>
    </configuration>
</plugin>
With these settings you should be able to create a working development environment for Android development with Scala. Make a test run by running the following command: mvn package to see if the environment compiles.
Congrats! You have an Android application that does nothing.
Also, if you can't get things working with the tutorial, here's the pom.xml you can use to get your application to compile.
From my point of view getting Android, Scala and Maven working together is a real pain in the ass and I couldn't have done the configuration without the following tutorials:
http://www.scala-lang.org/node/345 (Scala with Maven) Thanks to the Scala community.
Building Android applications with Maven and IntelliJ 11/26/2010 Thanks to Christian Bauer for an exellent tutorial.
Also some more information from Proguard:
http://code.google.com/p/maven-android-plugin/wiki/ProGuard?spec=svn331


Marko Pukari
read more...

Functional Programming and Android Game Development, a Happy Couple

For the past few months I’ve been writing a game for Android using Scala. I’ve been really impressed with the syntax of Scala after almost 15 years of Java programming. When we started doing the game, it seemed like proper object-orientation and game programming didn’t really fit. Doing nice object constructs and class hierarchies, although easier to read, develop and debug, is not well suited for a mobile device with limited memory and the tips that Google gives on Android development (avoid unnecessary objects, getters and setters etc) seems to guide you away from good OO principles too.

But the more I learn from the functional programming side of Scala, the more I feel that it goes well together with mobile game development.

Garbage collection seems to be your worst enemy in real-time gaming on mobile devices. It’s the one thing that can bring your game to grinding halt in the middle of best action and surely drive your gamers away.

FP concepts and Scala’s syntax help you to avoid unnecessary objects and garbage collecting. Creating and loading objects is expensive so in game programming you load and create in advance and pool what ever you can instead of creating on the fly and discarding after using.
Different collections and operating on them directly are in the heart of Scala and functional programming. So in game programming, pool what resources and game objects you can and instead of taking single objects from the pool, use Scala’s different advanced collection operations (filtering, mapping, collecting etc.) directly on the pools.

Scala’s syntax also allows returning values/objects/functions from pretty much any code block. With value-returning if/else blocks and object yielding for loops you are able to avoid using a lot of unnecessary temporary variable and mutable states.

One Scala's feature that wasn't a good idea with regards to memory and garbage collection was implicit conversions. I was using AndEngine library for the game and wanted to richen the Sprite implementation with few convenience methods. So I created a RichSprite and made and implicit def that when needed, converted Sprite to RichSprite. This unfortunately uses a constructor call to create a RichSprite. So you'll end up with one Sprite instance and one RichSprite instance, so you'll have more memory usage and eventually more garbage collecting. So I just ended up using the traditional class RichSprite extends Sprite which is a bit of a disappointment but works better for this purpose.

I’ll try to give you some code examples in the future blog entries, but in the mean time I’m happy to answer any questions, comments and would love to hear your opinions on using Scala on game programming




 Janne Sinivirta
read more...