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 settingsadb usb
will set the adb mode to be through usbadb 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 debuggingadb connect <device-ip-address>
to connect to the device after doingadb tcpip <port>
, then you can use all otheradb
commands as if it was attached to usbadb install <path-to-apk>
pushes an android app to deviceadb forward <local> <remote>
forwards socket connections from a specified local port to the remote port on the emulator/device instanceadb logcat
will show you all debugging messages, you can use some filtering, see refs.
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 applein droid repl
which will open a repl connected with the clojure running on the device/emulatorlein droid build
compiles your applein droid apk
builds an apk out of the built applein droid install
installs the apk on devicelein droid run
runs the installed applein droid forward-port
forwards to a local port from the remote android portlein droid with-profile <profile> <command>
you can execute the commands using a profile that is in yourproject.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.
Comments? Give me a shout at @lambda_cat.
To get the latest post updates subscribe to the LambdaCat newsletter.
You can support my writing on LambdaCat's Patreon.