Reflections on starting Android project with Scala

Hello. In this post I’d like to describe my experiences with Android, Scala, and SBT. I will cover the goals I wanted to achieve, issues I encountered and the results I reached in the end.

Originally this post was published on ScalaC blog at 2016-05-19.

Assumptions

The Android-Scala-SBT combination was not obvious from the very beginning. I was only sure that I wanted to develop some simple Android app (work still in progress) and I didn’t want to use Java for that. Though I was aware that Kotlin has a better adaptation in the Android world than Scala and is probably better suited for production right now, I had a really hard time giving up on functional properties and strong type system offered by Scala.

Just as any other project I’ve made during last 3 years I wanted this to have modules, unit tests and clean separation of concerns. Additionally, I wanted to put some newly-learned habits into practice: usage of automatic formatting tools, code test coverage, additional syntax checking and so on.

I wanted it to be some sort of a prototype project where I could learn Android on the go, but start using Scala from the beginning, and figure my own way of melting Android’s libraries and Scala’s best practices together.

It would force me immediately to face all hardships that could await me. I was aware though that this might be the hard way as even now there are surprisingly few articles describing Android development with Scala.

First attempt

I started somewhere around December. At first, I started out according to the books. I’ve installed Android Studio, downloaded SDKs and generated template Gradle project. Since I wanted to use Scala I installed Scala plugin to the IDE and converted all Java files to Scala using IDE (and moved them to the correct directory). It wasn’t perfect, so I had to manually change files on more than a few places to obtain more idiomatic Scala.

Making Gradle build required a little more effort. First, I had to investigate my options. There is Scala plugin for Gradle, required for building Scala files, and there is Gradle Android Scala plugin converting JVM classes into .dex files. The latter requires us to manually configure Scala version, either Multidex support or Proguard configuration (I used both) and (when I was doing it) downgrade Android plugin, to version supported by Gradle Android Scala plugin.

I had to test a few different options before I found out the setup that let me compile and run my template app without problems. I won’t get into details though. Soon I’ve found out that I will have to give up on Gradle.

Multiproject and other problems

As soon as I had my project running on Scala I wanted to introduce further improvements. I wanted to split the project into modules, add a formatter and style checking. Later on, I intended to try out Slick and Shapeless for a simple client-side database.

Setting up multi-project can be learned by reading up example on GitHub page. It doesn’t explain how I could achieve structure like this:

    [app]
      |
  +---+---+
  |       |
  |    [domain]
  |       |
  +-------+
  |
[core]

though, with some struggle, I could pull that off. (Only later did I learn that such approach is non-standard to Android and as such hardly any build system would support it out of the box.)

However, there is limited support for Scala quality checking plugins on Gradle. SCoverage is still maintained, but Scalastyle is abandoned. Similarly, Scalariform for Gradle also looks like a discontinued project.

Last but not least, when I’ve finally forced my way with multi-project and bid farewell to the newest tools, I learned that I cannot configure any compiler plugin for Scala with Gradle, and without macro-paradise I could not use Slack and Shapeless as I intended.

That was too much. Now I had serious reasons for moving to SBT.

SBT

When I started to look around, there was more than one option when it comes to Scala, Android, and SBT. There was (often suggested by StackOverflow or Reddit) Android plugin (which is currently discontinued) or Android SDK plugin (currently known as SBT Android plugin). The former was off the table as it was no longer supported, so I’ve decided to try out the latter one.

I have to openly admit that my first attempt to port Gradle to SBT using Android SDK plugin was a complete failure. It didn’t compile for reasons I couldn’t understand. Then I tried to port single module version - again it failed. Finally, I tried sbt-android-gradle. It generated SBT project that had a lot of redundant settings, was using single module… but worked. (It also showed that there is awful lot to know about dependencies transitivity and Proguard settings. Generating project with tons of redundant settings and then removing them one at a time while testing whether build still works is the best way to learn that). I could compile my project with SBT, so all up-to-date Scala plugins were available, not to mention compiler plugins and libraries that would depend on macros.

So, splitting the codebase into multiple modules became my major problem.

To understand the problem I need to explain a bit how SBT Android plugin works. When we want to build a project as an Android app we can do that using androidBuild:

lazy val app = (project in file("app"))
  .settings(androidBuild:_*)

Similarly when we create standalone Android library we use:

lazy val lib = (project in file("lib"))
  .settings(androidBuild:_*)
  .settings(libraryProject := true)

However, I did not know it back then - similarly to many other open-source Scala projects documentation here is sometimes lacking, and if you want to know answers to some specific questions, you have to either ask the author or consult the source code. At a time I used androidBuildApkLib (which was not deprecated yet, and which you should NOT use now unless you want to fight some funny bugs).

What about putting app and lib in the same build?

lazy val app = (project in file("app"))
  .androidBuildWith(lib)

lazy val lib = (project in file("lib"))
  .settings(androidBuild:_*)
  .settings(libraryProject := true)

You might notice that when we defined dependency with androidBuildWith we didn’t use androidBuild settings anymore. This is because androidBuildWith already applies androidBuild to app and applying it twice breaks the build. That makes putting a little bit more libraries a bit challenging if you are not aware of the fact.

lazy val app = (project in file(appPath))
  .androidBuildWith(domain)

lazy val domain = (project in file(domainPath))
  .androidBuildWith(core)
  .settings(libraryProject := true)

lazy val core = (project in file(corePath))
  .settings(androidBuild)
  .settings(libraryProject := true)

I was testing my options before SBT update deprecating project/build.scala came into life, so I also tested approach mentioned in the README:

object build extends android.AutoBuild {
  ...
}

This approach (when it was still legal) worked only for single module build. Multimodule projects would break. Currently, you won’t be able to use it, but you might still meet such code in older projects.

IDE’s limitations and Scaloid

When I managed to make SBT build and deploy my project with no issues (and when I eventually stopped crying the tears of joy), I could move on and start testing my options with libraries and IDE support.

IDEs

The first thing that many people might find interesting - Android Studio has some issues with accepting SBT config. Though Android Studio with Scala and SBT plugins should be virtually the same as IntelliJ with Android, Scala, and SBT plugins, only the latter gave me minor, not major issues. I cannot say what makes the difference, but if you are settings up a similar project to mine and Android Studio gives up, try IntelliJ instead.

You might also have some errors reported about generated sources - these issues can be solved with disabling source generation within the project setup. Resources are an even bigger problem. To put it bluntly - they do not work. If you got used to using WYSIWYG feature of the Android Studio and if you were fond of the option to fill variables in XML files with their runtime substitutions, you are out of luck. Both Android Studio and vanilla IntelliJ refuses to handle resources in SBT projects.

Scaloid

Since I had to say goodbye to WYSIWYG I’ve decided to give Scaloid a shot. What could be difficult about porting several template-generated XML files into raw Scala code, right?

Apparently, a lot. Currently, Scaloid supports only the older APIs. If you want to use something newer, like FloatingActionButton or NavigationView - forget it, Scaloid doesn’t support them. You have to either restrain yourself to old APIs or write our own Scaloid-like wrappers for those classes (been there, seen things, do not recommend). You might also try to mix them together, but my attempt failed - XML declared layouts rely on other layouts being accessible to them via identifiers, while Scaloid likes to pass already instantiated objects. You are being forced to choose one or the other.

Some things that Scaloid brings might be useful, e.g. methods to inject blocks of code that should be executed on activity creation, restart etc:

class MyActivity extends Activity with SActivity {

  onCreate {
    // action to perform on create
  }
}

I found out that this could be used to decouple views from actions - you declare actions within some controller class, you store view in another class, then activity merely initiates and injects dependencies, and calls those methods to inject behavior. That let me move all view-related code to another module, which accidentally also contains Gradle build so that I could import it into Android Studio, use WYSIWYG features and somehow glue things together.

Improvements?

My current setup works like this:

  • I have SBT multi-project that I import into IntelliJ Idea with Android, Scala, and SBT plugins,
  • different layers are decoupled into separate projects,
  • due to (IDE’s? Plugin’s?) limitations I have to edit views using mock Gradle project in one of those modules,
  • that would cause some troubles during refactoring: IntelliJ would ignore resources, Android Studio would ignore everything outside view project,
  • Scaloid is hardly useful since it only supports older APIs,
  • one should compile project before doing anything with SBT, since sources are not generated by IDE it relies on an outer build to provide them (and SBT Android is nice enough to provide utilities like typed resources),
  • when I create an activity using a template it is generated with XML and Java, then I run Java-to-Scala converter, adjust the code further, extract logic into controllers and split activity into raw view and activity which wires things together (now manually, I want to move to Macwire as a next step).

Running and debugging application works fine through a command line. You have to remember about running compile before android:package/android:run/android:debug (and starting up Android emulator manually before). If you use remote debugging, a number of the port can be figured out with Android Device Monitor.

To be honest I am not entirely happy with such workflow. It requires a lot of attention and effort and whole flow is obviously inferior to what Java/Kotlin developers have with Android Studio. In the near future, I intend to look into Macroid - it makes use of Scalaz IO/State monads which is perfect if you intend to keep your application as free of side effects as possible. Additionally, it doesn’t rely heavily on decorators for half the Android classes (Activity => SActivity, Service => SService, etc) but accepts the native ones. That probably eliminates the problem with being limited to older APIs.

Until I learn more about it, the only thing that would stop me from using Macroid would be lack of visual assistance like WYSIWYG - I am really new to Android development and I would not like to google source code for something I could click out in a few seconds (especially since I find coding visual aspects of the application really dirty. And when UI input and state mutation comes into play it becomes really sad for me). If I find some utility that helps with modifying UI without restarting application time after time I will immediately ditch XML for Macroid. SBT Android’s author suggested Protify which I want to try out soon. So far I can only tell that it relies on dynamic reloading of the views, making it possible to edit the views live. For now, I am not able to tell what are the limitations of such approach.

On the bright side, I could use all improvements of SBT build like code coverage, style check, and formatting, just like described in my previous post. Because of that writing, the code itself felt very rewarding.

Summary

There is no single, comprehensive and complete tutorial about starting your adventure with Android and Scala. If your requirements are limited you might pull off to use Scala with Gradle. As your demands grow you will be more attracted towards SBT environment.

Tools for development of Android apps with Scala and SBT may seem lacking. Workflows that you’ve learned with Java/Kotlin approach will have to go away. Libraries like Scaloid have limited usefulness and you will have to create workarounds or embrace their limitations if you want to achieve anything.

Hopefully, things will slowly change for better - half a year ago if you wanted to use SBT Android you had to read README, closed GH issues and ask the author to learn about many gotchas. Now, there is an official tutorial which explains things that I had to learn the hard way. Also, there are some commercial projects developed with Scaloid or Macroid which gives hope that someone is interested in maintaining them. Projects like Protify might soothe the pain of incomplete IDE support. The biggest challenge would be putting together pieces of knowledge scattered around.

At the end of the day, you have to ask yourself what do you want more. Java-based stack seems to be more mature and reliable at the moment. If you want to get things done it is undoubtedly the best option there, perhaps some pains could be lessened with Kotlin. If you are not afraid of being the lab rat and you are prepared to pave the way and you are sick of even thinking about programming in Java ever again - be prepared for a lot of hardships.

Personally, I’ll take the advantage of paying my bills with Android development and stick to fighting the issues with Scala. If you have more experience with Scala-Android stack, please share your suggestions. Every opportunity to learn is welcome.

If you want to try out Scala on Android, despite dragons ahead, here are some sources for the starter (it took me surprisingly long to learn about some of these):

  • SBT Android official documentation/tutorial - getting through it should save you like 90% of issues I had to deal with when I was setting up the project,
  • Scaloid - while personally, I find it somewhat limited (no support for newer features) it was used to create some actual app, so it would be simply,y unfair to not mention it,
  • Macroid alternative/improvement (?) over Scaloid; has some nice features (IO monad like UI actions!) that makes it the goal of my next research,
  • Protify - gives you the alternative to UI design workflow based on Android Studios’s WYSIWYG - live coding of the UI; should solve the problem of being limited to XML files and let you use Scaloid/Macroid/whatever you like,
  • Introduction to Android - last but not least. Even if you will try to improve code with Scala and wrap raw API with something nicer and safer, you still will work with some SDK classes directly. Besides, you won’t get very far if you don’t learn what happens in your app.