Clojure on Android - Workflow Setup II (Live Coding)

This is the third post of the Clojure on Android series.

Last time we used lein-droid to create a Clojure Android app and we ran it on your Android device, if you had one available.

Announcements and Slides

As I mentioned in the last post I spoke at the FunctionalKats conference about Clojure on Android, it was a lovely conference, thanks to Andrea's team's herculean efforts :)
The slides from that talk cover the material we already talked about and some more we'll cover in the future.

On that note, if you are/know a woman that is curious about Clojure and lives in Ireland, I'll be teaching at the Dublin ClojureBridge Workshop on October 2 and 3. It's a free introduction to Clojure, from any level of previous knowledge, so pass the word around, please! Non programmers welcome, too :)

Now onto the task at hand.

What you will get:
  • running it on an emulator
  • how to use Skummet to make a leaner apk
  • how to setup interactive development with CIDER.
What you need:

You need to have followed the instructions in the previous post.

Android emulator

If you don't have an Android device to use for development, you can use the Android emulator.
A word of warning: performance is varied and unpredictable, for me sometimes it takes minutes to start.

If you hate slow emulators (who doesn't) don't despair yet, I'll show you an alternative just after this.

In order to use the android emulator you have to install these System Images from the android command:

  • ARM EABI v7a System Image
  • Google APIs ARM EABI v7a System Image

Open the emulator manager with android avd, a UI will show up which will allow you to specify screen resolution, and more for your new emulator. You can make many different versions of the emulator, and test your app behaviours with different resolution and more.

A better option

As I said the official Android emulator can be very slow and unresponsive.
Genymotion (many thanks to Alex Yakushev for the tip) is much faster, but you have to pay if you use it commercially. There's an indie license which is cheaper.

It works pretty much as the standard emulator, but with a slicker UI and a good number of presets.

Once you have your emulator running lein droid doall will launch the app on it, see previous post if that sounds unfamiliar.

adb Overview

Here is short overview of adb commands if you have never programmed on Android.
With adb you should be able to do all your android app related tasks from a command line.

  • adb devices shows the attached devices. If your device doesn't show up on adb devices you probably need to enable usb debugging on its settings
  • adb usb will set the adb mode to be through usb
  • adb tcpip <port> will set the adb mode to be over wifi, it's convenient when you need a device not to be attached to usb while debugging
  • adb connect <device-ip-address> to connect to the device after doing adb tcpip <port>, then you can use all other adb commands as if it was attached to usb
  • adb install <path-to-apk> pushes an android app to device
  • adb forward <local> <remote> forwards socket connections from a specified local port to the remote port on the emulator/device instance
  • adb logcat will show you all debugging messages, you can use some filtering, see refs.

Reference

lein droid Overview

We've only seen

  • lein new droid
  • lein droid doall

But there are quite a few important commands, some that mirror the adb commands from above:

  • lein droid clean to wipe all the compiled files, always useful to do that when something behaves oddly in your app
  • lein droid repl which will open a repl connected with the clojure running on the device/emulator
  • lein droid build compiles your app
  • lein droid apk builds an apk out of the built app
  • lein droid install installs the apk on device
  • lein droid run runs the installed app
  • lein droid forward-port forwards to a local port from the remote android port
  • lein droid with-profile <profile> <command> you can execute the commands using a profile that is in your project.clj, we'll use it for Skummet later.

As we saw last time many of these commands are called by lein droid doall, and you only need to call them one by one if you want more granularity than what doall gives you.

repl Overview

lein droid repl which we mentioned above, will open a REPL that runs directly on your device/emulator. It will look something like this:

Binding device port 9999 to local port 9999 ...
$ lein droid repl
(Warning: profile :android-common not found.)
(Warning: profile :android-user not found.)
REPL-y 0.3.7, nREPL 0.2.10
Clojure 1.7.0
Dalvik 0.9
        Exit: Control+D or (exit) or (quit)
    Commands: (user/help)
        Docs: (doc function-name-here)
              (find-doc "part-of-name-here")
      Source: (source function-name-here)
user=> 
user=> (in-ns com.lambdacat.anfocal.main)

You need to use (in-ns... to call functions from main.clj. While there are things you can do just with a repl, using Emacs and CIDER allows you to have your app live update when changing something, see below for how to set it up.

Optional: faster Clojure Android apps with Skummet

The official instructions are here.

You basically need to add the Skummet options to the profiles section of your project.clj:

:lean
[:release
 {:dependencies ^:replace [[org.skummet/clojure "1.7.0-RC3-r2" :use-resources true]
                           [neko/neko "4.0.0-alpha5"]]
  :exclusions [[org.clojure/clojure]
               [org.clojure-android/clojure]]
  :jvm-opts ["-Dclojure.compile.ignore-lean-classes=true"]
  :global-vars ^:replace {clojure.core/*warn-on-reflection* true}
  :android {:lean-compile true
            :skummet-skip-vars []}}]

to set up Proguard, that "shrinks, optimises, and obfuscates your code by removing unused code and renaming classes, fields, and methods with semantically obscure names" you need to install JDK 7
and edit proguard-minify.cfg with the full path to rt.jar

-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/rt.jar

Since Skummet is very much in development, if something doesn't work you might want to try using a SNAPSHOT version of lein-droid with it. Change

 :plugins [[lein-droid "0.4.3"]]

to

 :plugins [[lein-droid "0.4.3-SNAPSHOT"]]

as well.
Or ask in #clojure-android@freenode, alexyakushev, the author is often around and very helpful.

After that you can compile your app with:
lein with-profile lean do clean, droid doall

Which will be one complex, yet familiar, command if you read the section on lein droid above.

CIDER

For Clojure Android interactive development you'll need to use Emacs and CIDER.

First you have to get an Emacs version, if you don't already have one. If you're on Mac, Aquamacs is a good one.

Once you have an emacs install you have to get some package management for it, there is marmalade (which tends to have older version of packages), melpa (bleeding edge snapshots) and melpa stable (up-to-date release version), I suggest the latter.
If you follow the links you'll find instructions to install them.

For convenience, if you have Emacs >24, which you should if you installed Aquamacs, then just add to your ~/.emacs file:

(require 'package) ;; You might already have this line
(add-to-list 'package-archives
             '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(package-initialize) ;; You might already have this line

Hit M-x package-refresh-contents to make sure the list of packages updates.

Hook into device

Now you can install CIDER 0.9.1: official instructions.

Adding this below to your ~/.emacs file and rebooting Emacs could be enough.

(unless (package-installed-p 'cider)
  (package-install 'cider))

Alternatively, if it's not, M-x package-list-packages and find CIDER with C-s cider, select it by typing i when you are on its line, and then x to execute, and you should see it installing.

Once CIDER is installed:

  • open the project.clj file from the project in Emacs: C-x f and then fill in the path
  • open a shell into it with M-x shell
  • run lein droid doall on it and make sure your device/emulator is running the app
  • into that pane do M-x cider-connect RET localhost RET 9999, the repl will open into that pane

If Emacs is new to you here are some more detailed instructions:

  • you'll need 3 panes, 1 for the file to edit, 1 for the shell and 1 for the repl. It may be more convenient for you to have a separate terminal window to do lein droid doall with, if so you'll only need 2 panes
  • open the project.clj file from the project in Emacs: C-x f and then fill in the path
  • split the window horizontally with C-x 2
  • move to the lower buffer with C-x o
  • split the pane vertically with C-x 3
  • choose the pane you want to open a shell into by moving to it with C-x o
  • open a shell into it with M-x shell
  • run lein droid doall on it and make sure your device/emulator is running the app
  • then move to another pane with C-x o
  • into that pane do M-x cider-connect RET localhost RET 9999, the repl will open into that pane

And voila, you will be able to change code and see the changes on your app on the fly, let's see a simple example now.

Live coding "Hello World"

To make sure all of this worked, you need to change something in the main.clj file, so open it in Emacs: C-x f and then fill in the path, you can autocomplete with TAB, it should be under src/clojure/com/lambdacat/anfocal/main.clj.

You should have code similar to this:

(defactivity com.lambdacat.anfocal.MainActivity
  :key :main

  (onCreate [this bundle]
    (.superOnCreate this bundle)
    (neko.debug/keep-screen-on this)
    (on-ui
      (set-content-view! (*a)
        [:linear-layout {:orientation :vertical
                         :layout-width :fill
                         :layout-height :wrap}
         [:edit-text {:id ::user-input
                      :hint "Type text here"
                      :layout-width :fill}]
         [:button {:text R$string/touch_me ;; We use resource here, but could
                                           ;; have used a plain string too.
                   :on-click (fn [_] (notify-from-edit (*a)))}]]))))

Try adding a background colour to the main layout, like this, under the orientation:

[:linear-layout {:orientation :vertical
                 :background-color (android.graphics.Color/parseColor "#ff2020")
                 :layout-width :fill
                 :layout-height :wrap}

and now put your cursor on the closing parenthesis of the (on-ui ... function and press C-x C-e, => true should appear in the mini-buffer at the bottom of Emacs and if you have your emulator/device visible you will see it update with the new colour.

Next Steps

Now you know your way around adb and lein droid, you have an interactive development environment set up and you know how to compile with Skummet.

What we want to do next is:

  • Clojure Android interactive development examples
  • some necessary background Android knowledge

Next post: (Coming Soon)

Thanks to alexyakushev and #clojure-android@freenode for the help.