How to Build an Android App in Scala 2.13

Maciek Gorywoda
Apr 7 · 11 min read

Or at least we will talk today about one of a few ways to do it. If you want to learn more about what is possible, and why it might be a good idea to consider an alternative to standard Android app development, please take a look a look at this article on Scala on Android or watch the associated conference talk.

But today we will talk about how to use GraalVM Native Image to compile Scala code to a file executable on Android, with Gluon libraries to access the Android platform beneath, and JavaFX for Graphical User Interface. Scala is in a way just a cherry on the top of the cake here — with GraalVM you can choose from a wide array of programming languages. It probably makes sense to stick to JVM languages if you want to code for the Android platform, but Scala is still just one of the options. One reason I could give as to why you should consider it is that it allows for writing complex logic in concisely and elegantly, and since GraalVM Native Image is already a pretty heavy-weight player, you probably wouldn’t use it if you wanted to write only a light front-end for your CRUD app. It shows what its ahead-of-time compilation is capable of only if the code you write is complex enough. And Scala is a great choice for writing complex code.

Requirements

  1. You will need a good computer. Haha, but for real. Building a native image of even a minimal example app takes a while and can eat all the RAM that you still have after Intellij is done with it.

But don’t run away in fear just yet. Before you are ready to let GraalVM take over your computer and compile that Android APK, you can use the JavaFX maven plugin to just quickly compile the GUI and run the app on your laptop. We will talk about it in a moment.

2. We will use Linux. As far as I know, for a moment Android native images work only on Linux machines. If you use a Mac or Windows and you are still able to follow this tutorial and get a working Android, please contact me and describe how you did it. Seriously. I want to know. (update: Ivan reported that it works on Windows with WSL)

3. Download GraalVM, Community Edition based on Java 11, from here.

4. Add this to your ~/.bash_profile:

export GRAALVM_HOME=<path to GraalVM home directory>
export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH

When you type in java -version it should display something like this now:

> java -version
openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment GraalVM CE 21.0.0 (build 11.0.10+8-jvmci-21.0-b06)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.0 (build 11.0.10+8-jvmci-21.0-b06, mixed mode, sharing)

(The GraalVM version may differ)

5. Type native-image to check if it's already there on the path. If not, install it with:

gu install native-image

gu should be available now in your console because of $GRAALVM_HOME/bin in your PATH. Also, read this and install whatever you need.

6. You will need adb , "Android Debug Bridge", to connect to your Android device and install the app on it. Here you can find more on how to do it. Oh, and if it's not clear yet, you will need an Android device 😉

7. Make sure your gcc is at least version 6. You can try following these steps. On top of that, you will need some specific C libraries (like GTK) to build the native image and it varies from one computer to another, so I can't tell you exactly what to do. But it shouldn't be a big problem. Just follow error messages saying that you lack something and google how to install them. In my case this was the list:

libasound2-dev (for pkgConfig alsa)
libavcodec-dev (for pkgConfig libavcodec)
libavformat-dev (for pkgConfig libavformat)
libavutil-dev (for pkgConfig libavutil)
libfreetype6-dev (for pkgConfig freetype2)
libgl-dev (for pkgConfig gl)
libglib2.0-dev (for pkgConfig gmodule-no-export-2.0)
libglib2.0-dev (for pkgConfig gthread-2.0)
libgtk-3-dev (for pkgConfig gtk+-x11-3.0)
libpango1.0-dev (for pkgConfig pangoft2)
libx11-dev (for pkgConfig x11)
libxtst-dev (for pkgConfig xtst)

Dependencies

Okay, if you reached this point and everything seems to work, it means you probably should be able to compile and run one of the example apps:

Whichever you choose, just clone the whole GitHub repository, and go to one of the subfolders. HelloGluon is based on HelloGluon from Gluon samples. HelloFXML is based on… HelloFXML from the same repo, but I simplified it — I removed all Gluon dependencies, leaving only bare JavaFX and the Gluon’s client-maven-plugin, to show what is the bare minimum for an Android app made this way. In both cases, we use Maven — not SBT, which is the standard Scala build tool because we need Maven plugins that don't have their SBT equivalents yet, as far as I know (I plan to make research about it soon). Install mvn if you don't have it yet.

In the case of HelloGluon (but not HelloFXML), we will create the app with the help of Gluon Mobile — a platform which uses JavaFX to build Java client apps. It looks like this will be the way to build Android apps with GraalVM in foreseeable future. No standard Android widgets — JavaFX instead. It has some interesting implications: the layer of abstraction we create between ourselves and the Android platform is not just a helpful tool, it’s a requirement. We won’t be able to access Android SDK — either at all or unless we get involved in some serious hacking which I don’t recommend. Instead, the idiomatic way here is to write your code platform-agnostic and access the platform’s characteristics only when it’s actually needed. For example, you will see in the HelloGluon code that we check if we are on the desktop instead of Android, because if yes then we need to provide window size for our app. If we are on Android, we can just let the app’s window take the whole screen. If you decide to write something more complex with this tech stack, you will quickly see that you can use Gluon’s libraries and JavaFX (maybe together with ScalaFX) to achieve the same results other developers get by tinkering with Android SDK, while you are writing code that can be easily re-used on other platforms as well. (But please note I don’t claim it will be completely platform-independent right away — just easy to re-use).

In the pom.xml of HelloGluon and HelloFXML, you will find a list of plugins and dependencies the apps use. Let's take a look at some of them.

  • We will use Java 16 and Scala 2.13. Not much to say here apart from that I’m very happy I see this version number here. In my work with Android SDK, I still have to use Scala 2.11 and the Android version of Java, which is still something in-between 7 and 8.
  • A tiny Scala library which resolves this problem in the interaction between Scala 2.13 and GraalVM Native Image. Thank you, Ólafur!
  • For the GUI we will use JavaFX 16.
  • In the case of HelloFXML, the javafx-fxml library is needed to let us handle FXML files. FXML is one way to describe the layout of GUI widgets in JavaFX. The other is to put them there directly in code, which is what we do in HelloGluon. Both have their pros and cons. FXML files can be generated by a WYSIWYG editor called Scene Builder, which is very useful, but on the down side it uses reflection to connect the generated view with the code.
  • In the case of HelloGluon, we will use two libraries: Glisten and Attach. Glisten enriches JavaFX with additional functionality specifically designed for mobile applications. Attach is an abstraction layer over the underlying platform. For us it means we should be able to use it to access everything on Android from the local storage to permissions to push notifications. I want to explore this with example apps and tutorials because if any of these features don’t work well and there are no easy alternatives, it means the whole tech stack is not mature yet. But from what I saw so far I’m carefully optimistic.
  • javafx-maven-plugin lets us use mvn javafx:run command and quickly test changes to the app's GUI.
  • scala-maven-plugin lets us use Scala in Maven builds (well, d’oh). Thank you, David!
  • client-maven-plugin lets us compile Gluon and JavaFX code into a native image. In the case of HelloGluon, you will find here a list of Gluon dependencies. HelloFXML does not need them but instead it requires a reflectionList tag with the name of a controller for the view generated from the FXML file.

The code

In both example apps the actual Scala code only sets up a few widgets and displays them. In HelloGluon, the Main class extends MobileApplication from the Glisten library and then construct the main view programatically, in two methods: init() for creating the widgets, and postInit(Scene) for decorating them. In HelloFXML it's even simpler: the Main class extends Application from JavaFX (Glisten's MobileApplication is a subclass of this one) and in its start(Stage) method we load the scene from the FXML file. The FXML file describes two widgets — a button and a label — and it points to HelloFXMLController as the controller for those widgets. In there we can initialize them and react to button clicks. (For the details, please follow the links in this paragraph).

If you want to write any more complex application, you will probably mix those two approaches: FXML for more-or-less static views and programatically set up widgets in places where the UI within one view changes in reaction to events (think, for example, of a scrollable list of incoming messages). Also, the choice should be affected by how much of the GUI code you want to cover with tests. I would suggest to build reasonably light GUI controlled by Scala classes which don’t rely on Gluon or JavaFX and therefore can be unit-tested — but this is a topic for another article.

By the way, at this point you should be able to easily see how you can delete everything referring to Scala from pom.xml and still write an app on Android in Java 16 (which is cool as well — we can’t do that in the standard Android SDK). It shows one thing that is very impressive to me. To write an Android app this way, I put together work of many brilliant people who do not necessarily even know about each other. Some of them work on Scala libraries, some on GraalVM, others on Gluon libraries, and JavaFX. All of them create new features and fix bugs for a lot of reasons, not really caring about that somewhere there someone wants to write an Android app in Scala. Yet, it all fits together. And it works the other way around too: by writing Android apps in Scala with all this tech stack, we test and experiment with all the puzzle pieces. We can provide feedback for their makers and maybe even help to fix some bugs or write some code that will be useful to someone else, someone who never thought of writing Android apps in Scala.

How to run the app

As I mentioned already, building an Android native image takes time, so we want to avoid doing it too often. Even before running the app for the first time, you should invest some time in unit, component, and integration tests, so that if you change something in your app you could still be sure it works correctly even before any manual testing. Then, to check how your GUI looks like and works, use:

mvn javafx:run

If everything looks fine, build the native image… but first, for your desktop:

mvn client:build client:run

After all, we are cross-platform here. Unless you want to test features of your app that will only work on a mobile device, you can first run it as a standalone desktop application. This will again let you test some layers of the app without actually running it on an Android device. And then, if all looks good, or if you decide to skip this step:

mvn -Pandroid client:build client:package

Successful execution of this command will create an APK file in the target/client/aarch64-android/gvm directory. Connect your Android phone to the computer with an USB cable, give the computer permission to send files to the phone, and type adb devices to check if your phone is recognized. It should display something like this in the console:

> adb devices
List of devices attached
16b3a5c8 device

Now you should be able to install the app on the connected device with adb install <path to APK> and a moment later you should see a new icon on your device's main screen. When you click on the icon, it should open approximately the same screen as the desktop version of your app.

Installation might not work for a number of reasons, one of the most popular being that your Android simply does not allow installing apps this way. Go to Settings, find “Developers options”, and there enable “USB debugging” and “Install via USB”. If you can’t find “Developers options” anyway then it might mean you need to do something like tapping the field with your Android OS version number ten times (or just google it).

If everything works and you see the app’s screen on your device, type adb logcat | grep GraalCompiled to see the log output. Now, for example, if you installed HelloGluon, you can click the button with the magnifying glass icon on the app's screen and you should see "log something from Scala" printed to the console. Of course, for anything more complex, please look into plugins in the IDE of your choice that can display logs from adb logcat in a more user-friendly way.

And that’s it. Where do we go now?

Hey, you made it to this point! It’s already quite far.

If you managed to build one of the example apps and want to code something more complex, there are at least a few ways you can learn how to do it:

Geek Culture

Proud to geek out.

 by the author.

Sign up for Geek Culture Hits

By Geek Culture

Subscribe to receive top 10 most read stories of Geek Culture — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Geek Culture

A new tech publication by Start it up (https://medium.com/swlh).

Maciek Gorywoda

Written by

Scala. Rust. Bicycles. Trying to mix kickboxing with aikido. Trying to be a better person too. Similar results in both cases. 🇪🇺 🇵🇱

Geek Culture

A new tech publication by Start it up (https://medium.com/swlh).

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store