├── README.md ├── build.sbt ├── linux_install_sdk.sh ├── mac_install_sdk.sh ├── project ├── Build.scala ├── build.properties └── plugins.sbt ├── sbt └── src ├── main ├── AndroidManifest.xml ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-ldpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── layout │ │ └── main.xml │ └── values │ │ └── strings.xml └── scala │ └── com │ └── myapp │ └── MainActivity.scala └── test └── scala └── com └── myapp └── test └── MainTest.scala /README.md: -------------------------------------------------------------------------------- 1 | ## Android Scala Example 2 | 3 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/emstlk/android-scala-example?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) 4 | 5 | Android project with sbt 0.13.8, Scala 2.11.7 and android-sdk-plugin 1.4.4 6 | 7 | ### Requirements 8 | 9 | * Java 1.7+ 10 | * Android SDK 11 | 12 | Also you can use script to install Android SDK 13 | 14 | ##### On Mac 15 | ``` 16 | $ ./mac_install_sdk.sh 17 | ``` 18 | ##### On Linux 19 | ``` 20 | $ ./linux_install_sdk.sh 21 | ``` 22 | 23 | ### Usage in console 24 | 25 | To compile and build 26 | 27 | ``` 28 | $ ./sbt android:packageDebug 29 | ``` 30 | 31 | To run test with Robolectric (not needed device) just type 32 | 33 | ``` 34 | $ ./sbt test 35 | ``` 36 | 37 | ### Usage in IDE 38 | 39 | You have to import project from Intellij IDEA (I use version 14.1) or Android Studio 40 | 41 | Choose SBT project and Android SDK like this 42 | 43 | ![Import android project](https://cloud.githubusercontent.com/assets/3140251/7283309/5998b608-e93e-11e4-95d1-353c8c2055f2.png) 44 | 45 | Probably you want to run project from IDE, so just make new "Android application" run configuration 46 | 47 | **Warning!** 48 | 49 | In "Before launch" section you should remove "Make" command and add "Run external tool" with `./sbt android:packageDebug` command 50 | 51 | ![Android application configuration](https://cloud.githubusercontent.com/assets/3140251/7283334/83eeb22c-e93e-11e4-91c1-ac0394082827.png) 52 | 53 | Also you may want to use a good emulator, so I prefer [Genymotion](https://www.genymotion.com) emulator 54 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | minSdkVersion in Android := "15" 2 | 3 | targetSdkVersion in Android := "21" 4 | 5 | platformTarget in Android := "android-21" 6 | 7 | buildToolsVersion in Android := Some("21.1.1") 8 | 9 | scalaVersion := "2.11.7" 10 | 11 | javacOptions ++= Seq( 12 | "-source", "1.7", 13 | "-target", "1.7", 14 | "-Xlint:unchecked", 15 | "-Xlint:deprecation" 16 | ) 17 | 18 | scalacOptions ++= Seq( 19 | "-target:jvm-1.7", 20 | "-encoding", "UTF-8", 21 | "-feature", 22 | "-unchecked", 23 | "-deprecation", 24 | "-Xcheckinit" 25 | ) 26 | 27 | libraryDependencies ++= Seq( 28 | "com.android.support" % "appcompat-v7" % "21.0.2", 29 | "org.robolectric" % "robolectric" % "3.0" % "test", 30 | "org.scalatest" %% "scalatest" % "2.2.1" % "test", 31 | "junit" % "junit" % "4.11" % "test", 32 | "com.novocode" % "junit-interface" % "0.11" % "test", 33 | "org.apache.maven" % "maven-ant-tasks" % "2.1.3" % "test" 34 | ) 35 | 36 | unmanagedClasspath in Test ++= (bootClasspath in Android).value 37 | 38 | proguardOptions in Android += "-keepattributes Signature" 39 | -------------------------------------------------------------------------------- /linux_install_sdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo apt-get update -qq 4 | sudo apt-get install libc6-i386 lib32z1 lib32stdc++6 5 | 6 | OLD_PWD=$PWD 7 | 8 | mkdir .sdk 9 | cd .sdk 10 | wget http://dl.google.com/android/android-sdk_r24-linux.tgz 11 | tar xf android-sdk_r24-linux.tgz 12 | SDK_PATH=$PWD/android-sdk-linux 13 | 14 | cd $OLD_PWD 15 | 16 | echo yes | $SDK_PATH/tools/android update sdk --all --filter platform-tools --no-ui 17 | echo yes | $SDK_PATH/tools/android update sdk --all --filter build-tools-21.1.1 --no-ui 18 | echo yes | $SDK_PATH/tools/android update sdk --all --filter android-21 --no-ui 19 | echo yes | $SDK_PATH/tools/android update sdk --all --filter extra-android-support --no-ui 20 | echo yes | $SDK_PATH/tools/android update sdk --all --filter extra-android-m2repository --no-ui 21 | 22 | echo "sdk.dir=$SDK_PATH" > local.properties 23 | -------------------------------------------------------------------------------- /mac_install_sdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OLD_PWD=$PWD 4 | 5 | if which brew2 >/dev/null; then 6 | brew install android-sdk 7 | SDK_PATH=/usr/local/opt/android-sdk 8 | else 9 | mkdir .sdk 10 | cd .sdk 11 | curl -O http://dl.google.com/android/android-sdk_r24-macosx.zip 12 | unzip android-sdk_r24-macosx.zip 13 | SDK_PATH=$PWD/android-sdk-macosx 14 | fi 15 | 16 | cd $OLD_PWD 17 | 18 | echo yes | $SDK_PATH/tools/android update sdk --all --filter platform-tools --no-ui 19 | echo yes | $SDK_PATH/tools/android update sdk --all --filter build-tools-21.1.1 --no-ui 20 | echo yes | $SDK_PATH/tools/android update sdk --all --filter android-21 --no-ui 21 | echo yes | $SDK_PATH/tools/android update sdk --all --filter extra-android-support --no-ui 22 | echo yes | $SDK_PATH/tools/android update sdk --all --filter extra-android-m2repository --no-ui 23 | 24 | echo "sdk.dir=$SDK_PATH" > local.properties 25 | -------------------------------------------------------------------------------- /project/Build.scala: -------------------------------------------------------------------------------- 1 | object Build extends android.AutoBuild 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.8 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.4.4") 2 | -------------------------------------------------------------------------------- /sbt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sbtver=0.13.8 4 | sbtjar=sbt-launch.jar 5 | sbtsha128=57d0f04f4b48b11ef7e764f4cea58dee4e806ffd 6 | 7 | sbtrepo=http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch 8 | 9 | if [ ! -f $sbtjar ]; then 10 | echo "downloading $sbtjar" 1>&2 11 | if ! curl --location --silent --fail --remote-name $sbtrepo/$sbtver/$sbtjar; then 12 | exit 1 13 | fi 14 | fi 15 | 16 | checksum=`openssl dgst -sha1 $sbtjar | awk '{ print $2 }'` 17 | if [ "$checksum" != $sbtsha128 ]; then 18 | echo "bad $sbtjar. delete $sbtjar and run $0 again." 19 | exit 1 20 | fi 21 | 22 | [ -f ~/.sbtconfig ] && . ~/.sbtconfig 23 | 24 | java -ea \ 25 | $SBT_OPTS \ 26 | $JAVA_OPTS \ 27 | -Djava.net.preferIPv4Stack=true \ 28 | -XX:+AggressiveOpts \ 29 | -XX:+UseParNewGC \ 30 | -XX:+UseConcMarkSweepGC \ 31 | -XX:+CMSParallelRemarkEnabled \ 32 | -XX:+CMSClassUnloadingEnabled \ 33 | -XX:MaxPermSize=256m \ 34 | -XX:SurvivorRatio=128 \ 35 | -XX:MaxTenuringThreshold=0 \ 36 | -Xss2M \ 37 | -Xms128M \ 38 | -Xmx512M \ 39 | -server \ 40 | -jar $sbtjar "$@" 41 | -------------------------------------------------------------------------------- /src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emstlk/android-scala-example/71cb7c1632c3db9d5c8746e677d97181f6ff0d17/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emstlk/android-scala-example/71cb7c1632c3db9d5c8746e677d97181f6ff0d17/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emstlk/android-scala-example/71cb7c1632c3db9d5c8746e677d97181f6ff0d17/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emstlk/android-scala-example/71cb7c1632c3db9d5c8746e677d97181f6ff0d17/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Main Activity 4 | Hello World! 5 | 6 | -------------------------------------------------------------------------------- /src/main/scala/com/myapp/MainActivity.scala: -------------------------------------------------------------------------------- 1 | package com.myapp 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | 6 | class MainActivity extends Activity { 7 | 8 | override def onPostCreate(savedInstanceState: Bundle) { 9 | super.onPostCreate(savedInstanceState) 10 | setContentView(R.layout.main) 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/scala/com/myapp/test/MainTest.scala: -------------------------------------------------------------------------------- 1 | package com.myapp.test 2 | 3 | import android.widget.TextView 4 | import com.myapp.{MainActivity, R} 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.robolectric.annotation.Config 8 | import org.robolectric.{Robolectric, RobolectricTestRunner, RuntimeEnvironment} 9 | import org.scalatest.Matchers 10 | import org.scalatest.junit.JUnitSuite 11 | 12 | @RunWith(classOf[RobolectricTestRunner]) 13 | @Config( 14 | manifest = "src/main/AndroidManifest.xml", 15 | resourceDir = "../../target/android-bin/resources/res", 16 | sdk = Array(21) 17 | ) 18 | class MainTest extends JUnitSuite with Matchers { 19 | 20 | @Test 21 | def simpleCase() { 22 | val context = RuntimeEnvironment.application.getApplicationContext 23 | val mainActivity = Robolectric.setupActivity(classOf[MainActivity]) 24 | val view = mainActivity.findViewById(R.id.simpleTextView).asInstanceOf[TextView] 25 | view.getText.toString shouldBe context.getString(R.string.welcome) 26 | } 27 | 28 | } 29 | --------------------------------------------------------------------------------