ScalaでAndroid開発 - Docker編

AndroidやScala/sbtも日進月歩なので、変化追い易くなればと思い Docker で開発環境を作ってみた。

今回はDockerの勉強を兼ねて Ubuntu 14.04 ベースで Android SDK + sbt のイメージを作ったので、これを使ってScalaでのAndroid開発の環境を準備した。Dockerとの役割分担の方針として：

1. sbtでのビルドやAndroidデバイスの定型操作などCUI操作はDockerのコンテナ上でやる
2. 実機USB接続やエミュレータ実行、IDE起動はオーバーヘッドの少ないホスト機でやる
3. 両者の通信は、adbサーバの5037番ポートをDockerコンテナからホスト機にSSHフォワードして行う
 
ことにした。

## (1) Dockerのセットアップ
ホスト機にMacを使っているので [boot2docker](https://github.com/boot2docker/boot2docker) を入れる。
[この記事](http://dev.classmethod.jp/tool/docker/getting-started-docker-on-osx/)などを参考にした。

```shell-session
$ brew install boot2docker
$ boot2docker init
$ boot2docker up
```

## (2) Dockerイメージの動作確認
下のコマンドで、Android SDK + sbt + sshd が入ったイメージ ( [ikuo/android-sbt](https://registry.hub.docker.com/u/ikuo/android-sbt/) ) からコンテナが起動する。初回はイメージのダウンロードで小一時間かかる。

```shell-session
$ docker run -it --rm -p 7022:22 ikuo/android-sbt:0.2 "`cat ~/.ssh/id_rsa.pub`"
```

最後の引数にある `id_rsa.pub` は、コンテナにssh接続する時に使う鍵ファイル。
動作確認なので `--rm` をつけて終了時にコンテナを消すようにしてある。
`-p 7022:22` でコンテナの22番ポートにホスト機(boot2dockerの場合はboot2docker-vm)の7022番をフォワードする。

boot2dockerの場合はさらに[この記事](http://qiita.com/ikuyamada/items/3f12de859a87d51fdd79) などを参考に、ホスト機の7022番をboot2docer-vmの7022番にフォワードさせておく：

```shell-session
# Macでoot2docker 使っている場合の追加手順
$ VBoxManage controlvm "boot2docker-vm" natpf1 "ssh to android-sbt,tcp,127.0.0.1,7022,,7022"
```

コンテナが起動したらホスト機からコンテナに下のようにSSH接続して、adbサーバが使う5037番をホスト機にフォワードしておく。adbのclient/server構成やポート番号などは[こちら](http://developer.android.com/tools/help/adb.html)を参考にした。

```shell-session
$ ssh ubuntu@localhost -p 7022 -R 5037:localhost:5037 -Nv
```

ホスト機で、 `adb start-server` してから適当なエミュレータ起動や実機接続をしておくと、コンテナ上のadbコマンドからホスト機のAndroidデバイスが見えるようになる。

```shell-session
ubuntu@xxxxxxxxxx:~$ adb devices
List of devices attached
999673041154999 device
```

※ ホスト機でadbサーバが起動していない場合は `error: protocol fault (no status)` のような表示になる。

## (3) android-sdk-plugin でのビルド

最近自分はsbtでのAndroidプロジェクトのビルドに[android-sdk-plugin](https://github.com/pfn/android-sdk-plugin)を使っているので、先のDockerのイメージも android-sdk-plugin に必なものだけを含めた。sbt-android plugin との違いは[こちら](http://taisukeoe.github.io/blog/2014/03/13/pfn-android-sdk-plugin/)にあったりする。

今回は既に android-sdk-plugin ベースのプロジェクトが手元にあったので、git cloneした後に下のように android update project を実行して Android SDK のパスを設定した。

```shell-session
ubuntu@...:~/work/myproject$ android update project -p . -t android-19
ubuntu@...:~/work/myproject$ git checkout proguard-project.txt
```
※ proguardの設定が上書きされたのでgitでリセット(2行目)

その後sbtでapkをビルドして`run`すると、ホスト機上のエミュレータや実機端末でアプリが無事に起動した。

```shell-session
ubuntu@...:~/work/myproject$ sbt android:package
ubuntu@...:~/work/myproject$ sbt run
```

動作確認に使ったアプリは[こちら](https://github.com/ikuo/garaponoid)。

## (4) IDEでのファイル編集
レイアウトファイルなどはホスト機の IDE (IntelliJ IDEA) でレンダリング確認しながら編集したいので、[こちらの手順](https://github.com/boot2docker/boot2docker#folder-sharing)を参考にファイル共有をセットアップした。

```shell-session
$ docker run -itd -v /data --name my-data busybox /bin/sh
$ docker run --rm -v /usr/local/bin/docker:/docker -v /var/run/docker.sock:/docker.sock svendowideit/samba my-data
$ boot2docker ip
    192.168.59.103
```

上のコマンドは svendowideit/samba というイメージをもとに `my-data` という名前でファイル共有用のコンテナを起動するもの。my-dataコンテナは間違って消してしまわないように`-itd`オプションをつけてシェルをバックグラウンドで起動してある。

\\192.168.59.103\data に共有フォルダができるので、MacならここにFinderで「サーバに接続」すると /Volumes/data にCLIでファイルを読み書きできるようになる。ここにコンテナからアクセスするには起動時に`--volumes-from my-data`をつけて /data を読み書きする。

ということで(2)のコンテナ起動にこのオプションをつけると、android-sbtのコンテナ起動コマンドは下のようになった：

```shell-session
$ docker run -it --rm -p 7022:22 --volumes-from my-data ikuo/android-sbt:0.2 "`cat ~/.ssh/id_rsa.pub`"
ubuntu@...:~$ sudo chown -R ubuntu /data
```

後は /data 以下にプロジェクトファイルをgit cloneするなりして編集＆ビルドすればOK。