EDIT MODE

モバイルアプリ開発に関することを書いています

AndroidNDKを含むプロジェクトをCircleCIでビルドする

標準的なAndroidプロジェクトのcircle.yml

2015/5/12現在では、公式サイトによると主要なAndroidSDKは、VMにプリインストールされているとのことです。 そのため、以下のような非常にすっきりしたYAMLファイルで、Androidプロジェクトをビルドすることが出来るようになっています。(テストは省略しています。)

machine:
  java:
    version: openjdk7
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assemble

もしプリインストールされたSDKに、使用したいものが無い場合だけアップデート処理を追記してあげればいいみたいです。

dependencies:
  pre:
    - echo y | android update sdk --no-ui --all --filter "package-name"

AndroidNDKを使用する場合のcircle.yml

公式によると、

We also preinstall the Android NDK; it can be found at $ANDROID_NDK.

とあるので、AndroidNDKもプリインストールされてるようです。 ところが、そのままAndroidNDKを使ったプロジェクトをビルドさせると、以下のようなエラーが出てNDKのタスクで失敗してしまいました。

> Building 2%NDK not configured.
> Building 2%  Download the NDK from http://developer.android.com/tools/sdk/ndk/.Then add ndk.dir=path/to/ndk in local.properties.
> Building 2%  (On Windows, make sure you escape backslashes, e.g. C:\\ndk rather than C:\ndk)

失敗する原因は、$ANDROID_NDKではAndroidNDKのホームディレクトリとして認識出来ないことでした。 そのため以下のように、$ANDROID_NDK_HOMEにプリインストールされているAndroidNDKを指定するとうまくいきました。($ANDROID_NDK_HOMEに言及した元ソースは、思い出せませんでした…)

machine:
  java:
    version: openjdk7
  environment:
    ANDROID_NDK_HOME: /usr/local/android-ndk
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assemble

ビルド中の突然死を予防するcircle.yml

特に具体的なエラーを吐くことなく、ビルドが失敗するケースがありました。 主な対策としては、下記2点が有効なようです。

  1. JVMのHeapSizeを制限する
  2. PreDexingを無効化する
machine:
  java:
    version: openjdk7
  environment:
    ANDROID_NDK_HOME: /usr/local/android-ndk
    JAVA_OPTS: "-Xmx2048m -XX:MaxPermSize=1024m"
test:
  override:
    - echo "Nothing to do here"
deployment:
  master:
    branch: master
    commands:
      - ./gradlew assembleDogfood -PdisablePreDex

JVMのHeapSizeを制限する

JAVA_OPTS: "-Xmx2048m -XX:MaxPermSize=1024m"

ある程度の規模のプロジェクトになると、仮想マシンのメモリを食い尽くしてしまうことが多々あるので、Gradleが使えるリソースに制限をかけてあげると安定します。

PreDexingを無効化する

これは公式サイトのDisable Pre-Dexing to Improve Build Performanceの部分に、詳細が書かれています。 その部分を一部引用すると、以下のように書かれています。

Because CircleCI always runs clean builds this pre-dexing has no benefit; in fact it makes compilation slower and can also use large quantities of memory. We recommend disabling pre-dexing for Android builds on CircleCI.

CircleCIでビルドするときは、PreDexingを無効化してねということらしいです。 やり方は、GradleAndroidPluginのサイトに載ってます。(上記CircleCIのサイトからもリンクが貼られてました。)

まずプロジェクトの直下にあるbuild.gradleに、以下のGradleタスクを追加します。

project.ext.preDexLibs = !project.hasProperty('disablePreDex')

subprojects {
  project.plugins.whenPluginAdded { plugin ->
    if ("com.android.build.gradle.AppPlugin".equals(plugin.class.name)) {
      project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
    } else if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
      project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs
    }
  }
}

次にcircle.ymlでビルドコマンドを叩く箇所に、dsablePreDexプロパティを付与してあげます。 これでpreDexタスクは実行されなくなります。

./gradlew clean assemble -PdisablePreDex

参考にさせて頂いたサイト

まとめ

AndroidNDKを使う場合は、$ANDROID_NDK_HOMEの設定が必要でした。 JVMのHeapSize制限は必要に応じて使えばいいけど、PreDexingの無効化はやっておいたほうがよさそうです。

またcircle.ymlの書き方は、まだまだ変わっていきそうなので、定期的に公式サイトをチェックした方がよさそうだなと思いました。 この記事では触れませんでしたが、エミュレーターの起動やテストまわりも書きやすくなってました。