Gradleで相対パスでライブラリプロジェクトを参照する
パッと出てこなかったのでメモっとく
こんな構成の時、appからlibraryを参照したいとする。
myProject - app targetLibrary - library
myProject/settings.gradle
include 'app', ':..:targetLibrary:library'
myProject/app/build.gradle
dependencies {
compile project(':..:targetLibrary:library')
Gradle Plugin 1.1.0-rc1でJVMでテストを実行出来るようになったらしい
New Build System - Android Tools Project Siteの1.1.0-rc1のRelease Noteに以下の文が
Unit testing support. Unit testing code is run on the local JVM, against a special version of android.jar that is compatible with popular mocking frameworks (e.g. Mockito).
という事で早速試してみました。
セットアップ
Android Studioを1.1 beta 4にする
まずはAndroid Studioを1.1 Beta 4以上にします。Android Studioを1.1 Beta 4はcanary channelで配布されてます。

gradle pluginを1.1.0-rc1にする
プロジェクト直下のbuild.gradle
dependencies {
classpath 'com.android.tools.build:gradle:1.1.0-rc1'
}
dependenciesにtestCompileでjunit4を追加する
gradle plugin 1.1.0-rc1からdependenciesにtestCompileというキーワードが増えました。localのUnit Testで使うライブラリを定義できます。
dependencies {
testCompile 'junit:junit:4.11'
testCompile "org.mockito:mockito-core:1.9.5"
}
Enable Unit Testing Supportを有効にする
Android Studioの[Preference]-[Gradle]-[Experimental]でEnable Unit Testing supportを有効にします。この設定の後gradle syncを行うかAndroid Studioを再起動して下さい。

テストを書く
テストはsrc/test/java配下に置きます。ディレクトリを作ってもそのままではコードを認識してくれません。

Build VariantsのTest ArtifactをUnit Testsに変更すると各種dependenciesのパスが通った状態でコードを記述出来るようになります。

テストコードを書きます。
ListUtils.java
public class ListUtils { public static <T> T head(List<T> list) { if (list == null || list.isEmpty()) { return null; } return list.get(0); } }
普通のJUnit4です。
import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; public class ListUtilsTest { @Test public void head() { List<String> strings = new ArrayList<>(); assertThat(ListUtils.head(strings), nullValue()); strings.add("a"); assertThat(ListUtils.head(strings), is("a")); strings.add("b"); assertThat(ListUtils.head(strings), is("a")); } }
Gradleで実行する
まずはGradleで実行してみます。gradle pluginを1.1.0-rc1からtest, testDebug, testReleaseなどのタスクが増えました。
./gradlew testDebug
module_name/build/reports/tests/index.htmlにレポートが吐かれます。

Android Studioで実行する
Android StudioではEdit ConfigurationsでJUnitのConfigurationを定義します。デフォルトとの変更点は下部のBefore launchです。Makeになっているのでそれを削除しGradle-awareを選択します。そこでtestDebug等のタスクを指定します。

あとは実行するだけ。エラーになるとreportsのindex.htmlを見に行かないとダメです。まだこの辺はこなれてない感じですね。

まとめ
とりあえずテストをlocalで実行する所まで書きました。今回追加されたUnit Testの機能はAndroidTestCompileと共存するのでdeviceが必要なテストと不要なテストを分けて管理出来るようになりました。
Unit Testの方はmockable-android.jarというjarを生成していました。これをテストで参照している様です。中身をザッとみたら実装はなくどれもRuntimeExceptionをthrowしていました。mockableという事でUnit TestではAndroid Frameworkのクラスをmockitoなどでmockして差し替えましょうという事みたいです。
TextUtilsとかもmock差し替えが必要みたいなのでRobolectricとの置き換えはまだ先になりそうです(そもそも置き換えられるかもちょっと不明)。Shadow的な仕組みが今後追加されるんでしょうか?気になる所です。
参考
BintrayにAndroidのライブラリをアップする
Maven Centralは拝承しないといけなくて面倒だ、Bintrayは何か適当にアップ出来るらしいという事でBintrayに飛びついたのですがリポジトリにライブラリをアップする手順が難解で挫折し続けていました。途方に暮れていた所社内で以下のBintrayのページとリポジトリを教えてもらいました。
bintray/bintray-examples · GitHub
中の人が色んなパターンのファイルをBintrayにアップする方法を書いたサンプル集です。サイコー。gradle-aar-exampleってのもあってホントにサイコーです。
AndroidのライブラリをBintrayにアップする
bintray-examples/gradle-aar-example at master · bintray/bintray-examples · GitHubを読めば分かるんですが一応手順をメモっときます。
Bintrayのアカウントを作る
とりあえずBintrayのアカウントを作りましょう。フリーでは500MBのスペースを得られます。
API Keyを確認する
アカウントを取ったらBintrayのmaven repositoryにファイルをアップロードする時に必要なAPI Keyを確認します。
自分のプロフィール画面を開き、Editから編集画面へ行きます。

編集画面にAPI Keyという項目があります。

gradle.propertiesに設定を書く
あとはGradle用の設定を書くだけです。Bintrayにファイルをアップロードする為に必要なuser名とAPI Keyをgradle.propertiesに記述します。この時gradle.propertiesは.gitignore等に含めてVCSにはcommitしないようにしましょう。(local.propertiesだとbuild.gradleから見えなかったので今回はgradle.propertiesに書きました。何か良い方法あれば教えて下さい。)
gradle.properties
bintray_user=USER_NAME bintray_api_key=API_KEY
build.gradleに設定を書く
長いですがそんなに複雑でもないです。groupIdやversion、siteUrl等固有の値は変更しないといけないですが他はテンプレです。
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
classpath 'com.github.dcendents:android-maven-plugin:1.2'
}
}
apply plugin: 'com.android.library'
android {
//省略
}
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
group = 'com.sys1yagi.android'
version = '1.0.0'
def siteUrl = 'https://github.com/sys1yagi/toaster'
def gitUrl = 'https://github.com/sys1yagi/toaster.git'
bintray {
user = bintray_user
key = bintray_api_key
configurations = ['archives'] //When uploading configuration files
pkg {
repo = 'maven'
name = 'toaster'
desc = 'Android Toaster! You can use toast anywhere.'
websiteUrl = siteUrl
issueTrackerUrl = 'https://github.com/sys1yagi/toaster/issues'
vcsUrl = gitUrl
licenses = ['Apache-2.0']
labels = ['android']
publicDownloadNumbers = true
}
}
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
name 'toaster'
url siteUrl
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'sys1yagi'
name 'Toshihiro Yagi'
email 'sylc.yagi@gmail.com'
}
}
scm {
connection 'https://github.com/sys1yagi/toaster.git'
developerConnection 'https://github.com/sys1yagi/toaster.git'
url siteUrl
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
task findConventions << {
println project.getConvention()
}
アップロードする
taskにbintrayUploadが増えます。実行するとaarがBintrayのmaven repositoryにアップロードされます。

jcenterに登録する
↑のページの右下からjcenterへの登録を申請するフォームへ飛べます。申請が通ればbuildscriptの所でjcenter()って書いてるプロジェクトならフツーにdependenciesでライブラリを追加出来るようになります。

試しにアップしたもの
toasterというどうしようもないライブラリをアップしてみました。jcenterへのpublishは依頼中なのでまだbintrayのmaven repositoryを参照しないと使えません。今後はもっと有益なライブラリをアップできるよう善処します。
gradle-tab-completion.bashをMacに導入する際に必要な修正と、初回実行時の留意点
Android開発を爆速にする10のコマンドラインスクリプト - クックパッド開発者ブログ
われらが@tomorrowkeyが書いてくれた↑で紹介されている、Gradleのタスクをcompletionしてくれるgradle-tab-completion.bashなんですが2014-12/21現在でMac(10.9.5 Mavericks)に導入するにあたってちょっと修正が必要なのでその点について書きます。あと初回実行時に留意するべきポイントがあるので解説します。
Macに導入する場合に必要な修正
gradle-tab-completion.bashは以下のgistで公開されてます。
Gradle tab completion for Bash. Works on both Mac and Linux.
導入方法とかは↑に書いてあるので省きます。現在公開されているgradle-tab-completion.bashには誤りがあってMacでは正常に動きません。すでにgistに誤りについてのコメントがあるのでいずれ直ってるかもしれません。
必要な修正は21行目です。余計なスペースがあるんですね。
before
21: if [[ -x `which md5 2 > /dev/null` ]]; then # mac
after
21: if [[ -x `which md5 2> /dev/null` ]]; then # mac
この修正をすれば正常にMacで動作します。
初回実行時の留意点
gradle-tab-completion.bashの中身を読んでみると、33行目で一度gradleのtasksを実行してそれらをgrepしつつawkなどをかまして対象のbuild.gradleのタスク一覧を取り出しています。
33: commands=$($gradle_cmd --no-color --quiet tasks | grep ' - ' | awk '{print $1}' | tr '\n' ' ')
その後この一覧をキャッシュして使いまわします。その為初回のcompletionは./gradlew tasksの実行が完了するまで待たされます。
プロジェクトによっては./gradlew tasksがすごく時間がかかったりする場合もあるのでcompletionがフリーズした印象を受けたりします。というか僕はそれではまりました(./gradlew tasksが1分かかった。待ちきれず中断しまくった)。
また、build.gradleのmd5のハッシュ値を見て更新されたかどうかを判定しているので、build.gradleを更新したあとの最初のcompletionも時間がかかると思います。
初回、更新後は気長に待ちましょう。
まとめ
gradle-tab-completion.bashベンリサイコー

ビルド時にjava.lang.OutOfMemoryError: GC overhead limit exceededで死ぬときはdexOptionsにjavaMaxHeapSizeをセットすると良い
タイトルそのまんま。gradleでビルドしていて以下のエラーに出会ったら、
java.lang.OutOfMemoryError: GC overhead limit exceeded
build.gradleのdexOptionsにjavaMaxHeapSizeを指定すれば大体直る。
android {
dexOptions {
javaMaxHeapSize "2g"
}
}
この問題が出る兆候に「ビルドがめちゃくちゃ長い」というのがある。スワップしまくってるんだろうか。とりあえず2gくらいに設定しておけば大体いけると思う。
