Android Scala Setup Tutorial - aagahi/spotmint-android GitHub Wiki

Android Scala Setup Tutorial

Install Android sdk

Install Android SDK

http://developer.android.com/sdk/index.html

And launch

./tools/android

And download Google API 7 and 10 bundle (we target API 7 but we'll use emulator with API 10 as the emulator doesn't work correctly with API 7).

Setup ENV var (for example in my case it will be $HOME/works/android-sdk).

export ANDROID_HOME=$HOME/works/android-sdk

Install Android artifacts

Get android deployer

git clone git://github.com/mosabua/maven-android-sdk-deployer.git

Assuming you have android platform 2.1 and 2.3.3 installed in your sdk install the artifact using:

mvn install -P 2.1

mvn install -P 2.3.3

Setup SBT Android for Google Maps Usage

Follow getting started instruction from sbt android-plugin getting-started

Update the project/build.scala settings

val settings = Defaults.defaultSettings ++ Seq (
name := "SpotMint",
version := "0.1",
versionCode := 0,
scalaVersion := "2.8.2",
platformName in Android := "android-7",
resolvers ++= Seq( "Local Maven Repository"  at "file:///Users/alag/.m2/repository/" )
)

We use scala 2.8.2 for many reasons but mostly for its small footprint.

Now specify local repo for maps.

Still in build.scala update dependencies:

  libraryDependencies ++= Seq(
    "org.scalatest" %% "scalatest" % "1.7.RC1" % "test",
    "com.google.android.maps" % "maps" % "7_r1" % "provided" )
  )

maps is provided since it is should be on device.

And finally disable proguard for emulator build (we'll setup an emulator with scala jars embedded so you should bypass proguard stage for faster build process)

val proguardSettings = Seq (
  useProguard in Android := false
)

You should enable proguard when you build your app for device (or market release) or if you don't want to run your app on emulator with custom ramdisk (see later).

Update your project files

When testing maps with your project you need to get an "debug" apiKey. See Google MapKey. Update src/main/res/layout/main.xml file with your apiKey.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">

<com.google.android.maps.MapView
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"
        android:apiKey="the API key"
        />
</RelativeLayout>

Remember that you will need to use a different API Key for market publication process.

Update AndroidManifest.xml

<application
    android:icon="@drawable/android:star_big_on"
    android:label="@string/app_name"
    android:debuggable="true">

    <uses-library android:name="com.google.android.maps" />


    <activity android:label="@string/app_name" android:name=".MainActivity" android:launchMode="singleInstance" android:theme="@android:style/Theme.NoTitleBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

</application>

<uses-sdk android:minSdkVersion="7" />

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

As you can see we added <uses-library android:name="com.google.android.maps" /> and <uses-permission android:name="android.permission.INTERNET" /> required for app using maps.

Using the emulator

Create an emulator image

List all your android target:

$ANDROID_HOME/tools/android list

Create an emulator image for API10 (I had some problem with API7 so I recommend 10)

$ANDROID_HOME/tools/android create avd -n API10 -t 4

(in my case -t 4 is API10).

Customize the emulator with scala jars preinstalled

Inspired from http://zegoggl.es/2011/07/how-to-preinstall-scala-on-your-android-phone.html

Install https://github.com/jberkel/android-sdk-scala and make sure you have

export ANDROID_SDK_ROOT=$ANDROID_HOME

Edit vi ./bin/createdexlibs and ./bin/createramdisks

And adjust platform-tools path:

DX_LIST=`find $ANDROID_SDK_ROOT/platform-tools/ -name dx | sort -r`

Run ./bin/createdexlibs

Now create a custom ramdisk: ./bin/createramdisks

And boot up the emulator:

$ANDROID_HOME/tools/emulator -avd API10 -no-boot-anim -ramdisk ~/.android/avd/API10.avd-custom/ramdisk.img

Get device identifier: $ANDROID_HOME/platform-tools/adb devices

In my case it is "emulator-5554"

Now create the scala jar folder on ramdisk:

$ANDROID_HOME/platform-tools/adb -s emulator-5554 shell mkdir -p /data/framework

And push the scala jars:

for i in configs/framework/*.jar; do $ANDROID_HOME/platform-tools/adb -s emulator-5554 push $i /data/framework/; done

And now reboot the emulator.

Use logcat if required:

$ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat

Use android sbt plugin

Now you're ready to use sbt and deploy on the running emulator using sbt command:

~ android:start-emulator

Connect to the emulator

You can get the emulator log using logcat adb command:

$ANDROID_HOME/platform-tools/adb -s emulator-5554 logcat

Also you can update the GPS position using telnet command on emulator such as:

> telnet localhost 5554
> geo fix -121.45356 46.51119 4392

Using a rooted device

In case you want to run your app on a device you can use https://github.com/scala-android-libs/scala-android-libs. It will require you to root your device but again, will save you tons of times during the building process avoiding the proguard stage.

If you use a Nexus One for dev check this link: http://forum.xda-developers.com/wiki/Nexus_One/Guides_%26_Tutorials#Root - in my case, having my N1 running on 2.3.6, I used the 2/ case (recovery-RA-passion-v2.2.1.img + su-2.3.6.1-ef-signed.zip) and had a problem with Froyo SuperUser tools (at recovery stage, I had to deactivate the signature check, install SuperUser zip, and then REACTIVATE the signature check). Also when installing the scala libs, superuser asks you root access for every command and you have to approuve all requests til the end.

Some known problems

If you're using an API7 ramdisk, you won't get network connectivity, I dont know exactly why.

If you use Scala 2.9.1 (on the emulator or a device) it seems that you might get a "LinearAlloc exceeded capacity" error/crash. This can probably be solved by with some dex parameters or image customization, see http://www.netmite.com/android/mydroid/2.0/dalvik/docs/embedded-vm-control.html. Also using scala 2.8.2 seems to be an appropriate workaround right now considering smaller build package generated. Scala 2.10.x seems to fix this problem (see SI-4620). If you're using a rooted device with scala-android-libs, you might also need to install scala-2.8.x dexed afterwards (using android-sdk-scala tools) instead of 2.9.1.

OSX tips

To use sbt as Idea plugin with android you can setup the env var as such

launchctl setenv ANDROID_HOME $ANDROID_HOME

⚠️ **GitHub.com Fallback** ⚠️