追記

zaki日記

2010|02|03|08|10|12|
2011|06|07|10|12|
2012|12|
2013|06|

2013-06-20

_ Android Studio でも apt が使い物になる build.gradle の書き方(暫定版)

Gradle の android plugin では、 Build TypeProduct Flavorの組み合わせ毎に Build Variants が作成され、 Build Variant 毎に別々の apk をビルドすることができます。Gradle で apt を使ったプロジェクトを作る方法はesmasuiさんに教わったのですが、 Android Studio のBuild Variants 切り替えに対応していなかったのでなんとかしてみました。

Android Studio の Build Variants 切り替え対応版 build.gradle

以下が build.gradle の記述です。Android Annotations の例ですが、 dependencies に依存を追加すれば JSON Pull Parser などでもそのまま使えます。

// buildscript とか maven リポジトリの設定は省略

apply plugin: 'android'

configurations {
    apt
}

dependencies {
    // http://stackoverflow.com/questions/16683944/androidannotations-nothing-generated-empty-activity/16802216#16802216
    apt "com.googlecode.androidannotations:androidannotations:2.7.1"
    compile "com.googlecode.androidannotations:androidannotations-api:2.7.1"
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 17
    }
}

android.applicationVariants.all { variant ->
    // ↓ def を付けないと プロジェクトの Dynamic Property になってしまい、常に最後の variant 用のディレクトリが使われてしまう。
    // variant にソースフォルダを追加する方法が見当たらないので R.java 用のソースフォルダを生成場所として利用する。
    def aptOutput = file("${project.buildDir}/source/r/${variant.dirName}")

    variant.javaCompile.doFirst {
        println "*** compile doFirst ${variant.name}, aptOutput=${aptOutput}"
        aptOutput.mkdirs()
        // インクリメンタルビルドでエラーになるので古いファイルが存在する場合は消しておく
        aptOutput.eachFileRecurse groovy.io.FileType.FILES, {
            if (it.name.equals('R.java')) {
                return
            }
            it.delete()
        }
        variant.javaCompile.options.compilerArgs += [
                '-processorpath', configurations.apt.getAsPath(),
                '-AandroidManifestFile=' + variant.processResources.manifestFile,
                '-s', aptOutput
        ]
    }
}

内容の説明

esmasuiさんのエントリの内容 との違いを中心に説明します。

修正点は主に3点です。

1つ目は、

   aptOutput = file("${project.buildDir}/source/r/${variant.dirName}")

   def aptOutput = file("${project.buildDir}/source/r/${variant.dirName}")

とした点です。これは、 def をつけないとプロジェクトの Dynamic Property になってしまい、 Closure の中から参照した際に常に最後の Build Variant が設定した内容を取得してしまうバグを修正するものです。この修正を行うことで、Build Variant 毎ね別々のディレクトリにファイルが生成されるようになります。

2つ目はファイルの生成場所を

   "${project.buildDir}/source/apt_generated/${variant.dirName}"

から

   "${project.buildDir}/source/r/${variant.dirName}"

へ変更したことです。ここは R.java が生成されるディレクトリです。本来であれば apt_generated の様に apt 専用置き場所を作成すべきですが、現状の android plugin では variant に対して新たな Source Root を追加する方法が見つかりませんでした。variant に追加しておかないと Android Studio で Source Root して扱ってくれません。そのため今回は仕方なく R.java と同居する方法をとりました(そのため暫定版です)。

3つ目は、 variant.javaCompile.doFirst に渡す Closure の中に追加した以下のクリーンアップ処理です。

        aptOutput.eachFileRecurse groovy.io.FileType.FILES, {
            if (it.name.equals('R.java')) {
                return
            }
            it.delete()
        }

これは、コンパイルの際のエラーを防ぐためのものです(一度 apt でファイルを生成していると、コンパイルの際にクラスの重複エラーが出ます)。

どうしても R.java との同居が許せない人は

R.java と同居するのがどうしても許せない人は

   def aptOutput = file("${project.buildDir}/source/apt_generated/${variant.dirName}")

として、その直後に以下の行を追加すると apt_generated フォルダを使うこともできます。

   tasks["compile${variant.name}Renderscript"].sourceOutputDir = aptOutput

これは、 Renderscript 用に用意されている Source Root (元のパスは "${project.buildDir}/source/rs/${variant.dirName}" ) を強引に書き換えることで実現しています。この設定をした状態で Renderscript を使用すると、 apt_generated の下に Renderscript のファイルも生成されてしまいます。

Android Studio で開いてみる

この設定を行ったプロジェクトを Android Studio で開くと以下のようになります。

use_r_folder.png

build/source/r/ の下にファイルが生成されています。また、build/source/r/release のフォルダのアイコンが水色になっていることから現在選択されている Build Variant に対応するフォルダが Source Root として使用されていることがわかります。

以下は Renderscript 用のフォルダを乗っ取る場合の例です。

take_over_renderscript.png

先ほど存在した build/source/rs フォルダがなくなった代わりに build/source/apt_generated が作成され、選択されている Build Variants に対応したフォルダが Source Root として使用されます。

今回の内容は https://github.com/zaki50/android_gradle_template で公開している Gradle + Android Studio 用の雛形プロジェクトにも反映させておきました。

6/21 追記

このエントリの(暫定版)を外す方法が何かないかと思って adt-dev で 質問してみた のですが、残念ながら Xavier さんの回答は

There's no easy way to do this now, it's all going to be ugly.

でした...

本日のツッコミ(全3件) [ツッコミを入れる]

_ kimukou_26 [初歩的な質問かもしれませんが、すみません。 上記と同じ構成にした時 (android annotaionを使用..]

_ vvakame [apply plugin: 'android-library' の場合 Could not find propert..]

_ zaki [すっかりコメントに気づいてなかった... AndroidStudio でも基本的にはこのやりかたで問題ないはず..]


2012-12-19 2012年 Android Advent Calendar 18日目

_ 2012年 Android Advent Calendar 18日目

Android のビルドシステムの不満点を解消する新ビルドシステムを開発中と聞いて

Android Advent Calendar 18日目の @zaki50です。既に19日目すら終わろうとしていますが皆様いかがお過ごしでしょうか(すみません...)。

今回は、Android Tools Project で開発が進められている新ビルドシステムについて書きます。ここで言うビルドシステムとは、Android アプリソースコードやリソースファイルを apk に変換するための仕組みのことです。現状では eclipse や ant を使ったビルドシステムが提供されていますが、それが今後どのように改善され発展していくか興味があったので調べたことをまとめます。

まず初めにお断りしておきますが、新ビルドシステムはまだまだ開発中のものです。リリース時期が決まってないどころか現状実装されている機能がそのままリリースされるかもわかりません。もちろん未実装の機能もたくさんあります。ですが、実際に試してみる事が出来る程度には実装されているので、興味が有る方はぜひ試してみてください。

今回書いた内容は、 Android Tools Project の New Build System に書かれている内容を元にしています。一次情報に当たりたいという方はぜひこちらも見てください。

今回のエントリはこれを読んで新ビルドシステムに興味をもった人が実際に試して見ることを目指します。元のサイトでは省略されているが実際に試すには必要となる情報を補いながら進めます。

新ビルドシステムが目指すこと

Build System Concepts のページには、新ビルドシステムのゴールとして以下の3つが掲げられています。

  • コードやリソースの再利用性を高めること
  • マルチAPKや有料/無料版など、1つのアプリに対して複数の派生バージョンを簡単に作れるようにすること
  • ビルドの拡張やコンフィギュレーション変更を簡単にすること

上記の内容を具体的に何ができるかで表現すると以下のようになります。

  • リソースがあるライブラリプロジェクトを単一バイナリにビルドすることができ、 maven で使用できる。
  • 一つのプロジェクトから、無料版/有料版、マルチAPK用のさまざまな apk など、一部のコードやリソースが異なる複数の APK を作成することができる。
  • 1つのプロジェクトから複数の APK を作る際、パッケージ名やパーミッションなど、AndroidManifest.xml の内容を個別にカスタマイズすることができる。

このようなことが可能になるビルドシステムに興味はあるでしょうか。興味が有る方はさっそく新ビルドシステムを使用するための環境を整えましょう。

セットアップ

新ビルドシステムを使うための方法は Using the new Build System に書かれています。

新ビルドシステムは Gradle というant と Maven のいいとこ取りみたいなシステムの上に構築されています。そこで、まずは Gradle を使える環境を構築します。 Gradle については、 http://www.infoq.com/jp/news/2012/06/gradle-1 など幾つか解説サイトがあるので詳細はそちらを参照してください。

以下、Mac 上での環境構築を前提に記述します。他の環境の人は適宜読み替えをお願いします。

Gradle のセットアップ

Gradle を http://gradle.org/downloads から落としてきます。注意するポイントは、最新の Gradle ではなく、 Gradle-1.2 をダウンロードすることです。Gradle-1.2 をダウンロードしたら、適当な場所に展開し gradle-1.2/bin/ にパスを通してください。

$ which gradle
/Applications/gradle-1.2/bin/gradle
$ gradle
:help

Welcome to Gradle 1.2.

To run a build, run gradle <task> ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

BUILD SUCCESSFUL

Total time: 1.511 secs

こんな感じに出力されればまずは成功です。

MacPorts でも Gradle をインストールすることができますが、そのまま入れると 1.3 が入ってしまうのでがんばって 1.2 をインストールしてください。

環境変数の設定

環境変数 ANDROID_HOME に、 Android SDK のパスをセットします(もし Android SDK をインストールしていない場合は適当な場所にインストールし、最新の Platform-tools と、android-support-v4 を落としてください)。

$ env |grep ANDROID_HOME
ANDROID_HOME=path-to/android-sdks

この環境変数はビルドの際に SDK の場所を特定するために使用されます。

以上で、新ビルドシステムを使用する準備は完了しました。Android アプリケーションのビルドのために必要なプラグイン等はすべて Gradle が必要に応じてダウンロードしてくれます。

では早速 Gradle でアプリをビルドしてみましょう。

プロジェクト作成

まずは、gradle でビルドするためのプロジェクトの作成です。AndroidManifest.xml や各種リソース、ソースコードなどは今までのプロジェクトと同じですが、配置する場所が異なります。また、ビルドに関する設定を行う build.gradle という名前のファイルを作成する必要があります。

build.gradle の作成

まず、プロジェクト用のディレクトリとして空のディレクトリを作成します(今回は MyProject_gradle にしました)。ここに、build.gradle とソースコードなどを順に配置していきます。

Using the new Build System に書かれている最小の build.gradle は以下のものです。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.1'
    }
}
apply plugin: 'android'

android {
    target = 'android-17'
}

このままではいくつか問題があるので、以下の修正を行います。

  • ビルドに使用するプラグインのバージョンを最新に
 classpath 'com.android.tools.build:gradle:0.1'

 classpath 'com.android.tools.build:gradle:0.2'

に変更します。現在 milestone 0.2 がリリースされているので、 0.2 を使用するように変更します。

  • Java6 の class ファイルを生成する設定

最近は Java7 を入れている人も多いかと思いますが、Android は Java7 の class ファイルを扱えないので、Java6 互換として処理するように設定を追加します。今は java6 しかインストールしていなくても、将来的に Java7 を入れるかもしれないので今のうちに設定をしておきましょう。

build.gradle の最後に以下の記述を追加します。

sourceCompatibility=1.6
targetCompatibility=1.6
  • maven のリポジトリを参照する設定を追加

build.gradle の最後に以下の記述を追加します。

repositories {
    mavenCentral()
    mavenLocal()
}
  • 依存ライブラリの記述を追加

依存するライブラリを記述します。最近ではほぼ android-support-v4.jar を使用すると思います。Android SDK に含まれる support-v4.jar を依存 jar として追加するには以下の記述を build.gradle の最後に追加します。

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

android-support-v4.jar を自分でローカルの maven リポジトリに入れているのであれば、以下のように記述することもできます。

dependencies {
    compile 'com.google.android:support-v4:r11'
}
  • build.gradle 作成のまとめ

ここまでの修正を行うと、 build.gradle は以下の様になっていると思います。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.2'
    }
}

apply plugin: 'android'

android {
    target = 'android-17'
}

sourceCompatibility=1.6
targetCompatibility=1.6

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}
ソースコードなどをコピー

まず、各種ファイルを配置するためのディレクトリ群を作成します。

$ mkdir -p src/{main,debug,release}/{java,jni,resources,aidl,rs,res,assets}

こんな感じに作成できていればOKです。

$ find .
.
./src
./src/debug
./src/debug/aidl
./src/debug/assets
./src/debug/java
./src/debug/jni
./src/debug/res
./src/debug/resources
./src/debug/rs
./src/main
./src/main/aidl
./src/main/assets
./src/main/java
./src/main/jni
./src/main/res
./src/main/resources
./src/main/rs
./src/release
./src/release/aidl
./src/release/assets
./src/release/java
./src/release/jni
./src/release/res
./src/release/resources
./src/release/rs

現状の Android アプリのプロジェクトからのファイルは、 src/ 以下に配置されます。src/ の直下には、 Sourceset と呼ばれるディレクトリが作成されます。今回は main, debug, release という Sourceset を作成しました。このうち main がすべての基本になるディレクトリです。このプロジェクトで作成するすべての apk に共通するものをここに配置します。 release は リリースビルドの際だけ使用するファイル群を、debug にはデバッグビルドの際に使用するファイル群を配置します。これら以外にも、自由にsourceset ディレクトを作成することができます。

また、全ての Sourceset は直下に以下のファイル/ディレクトリを持つことができます。

AndroidManifest.xml
使用する apk 生成の際に使用する AndroidManifest.xml です。build.gradle で設定の一部を上書きすることができます。
java
Java のソースコードを配置します
res
Android のリソースを配置します。
assets
アセットを配置します。
aidl
AIDL ファイルを配置します。
rs
RenderScript ファイルを配置します。
jni
JNI のファイルを配置します。
resources
Java のリソースを配置します。

次に現状のプロジェクトからファイルをコピーします。元のプロジェクトが ../MyProject にあるとします。

$ cp ../MyProject/AndroidManifest.xml src/main/
$ cp -r ../MyProject/src/* src/main/java/
$ cp -r ../MyProject/res/* src/main/res/
$ cp -r ../MyProject/assets/* src/main/assets/

もし、 元のプロジェクトが AIDL ファイルを含んできる場合は、src/main/java/ から src/main/aidl/ へ移動してください。

ここまでくればapk をビルドする準備は完了です。

ビルドと実行

さっそくビルド&インストールします。APK を端末にインストールするので、端末をつなげておいてください。

$ gradle installDebug
Download http://repo1.maven.org/maven2/com/android/tools/build/gradle/0.2/gradle-0.2.pom
Download http://repo1.maven.org/maven2/com/android/tools/build/builder/0.2/builder-0.2.pom
Download http://repo1.maven.org/maven2/com/android/tools/build/gradle/0.2/gradle-0.2.jar
Download http://repo1.maven.org/maven2/com/android/tools/build/builder/0.2/builder-0.2.jar
Deprecated: relying on packaging to define the extension of the main artifact is deprecated, and will not be supported in a future version of Gradle.
:prepareOrgZakkyAndroidMyLibrary10Library
:prepareDebugDependencies
:compileDebugAidl
:generateDebugBuildConfig
:crunchDebugRes
:processDebugManifest
:processDebugRes
:compileDebug
:dexDebug
:processDebugJavaRes UP-TO-DATE
:packageDebug
:installDebug
4184 KB/s (189521 bytes in 0.044s)
    pkg: /data/local/tmp/MyProject_gradle-debug-unaligned.apk
Success

BUILD SUCCESSFUL

Total time: 16.761 secs

BUILD SUCCESSFUL と出力されたでしょうか。もし BUILD FAILED と出た場合は、エラーメッセージを確認して対処してください。 build.gradle の記述ミスか、 src/main/ の下に必要なファイルが存在しないという場合が多いと思います。

gradle tasks と実行すると、他に実行可能なタスクの一覧が出力されます(--all もつければさらに細かい Task も出力されます)。

Flavor の追加

今まで作成した main, debug, release は予め定義されているもの(debug, release は BuildType と呼ばれます。BuildType を追加することもできますが今回は省略します)ですが、Flavor を追加することで、様々なバリエーションを持った APK を作成することができます。 Flavor を追加するには、 Flavor に対応する Sourceset を src/ ディレクトの下に作成し、build.gradle に productFlavors として記述を追加します。

たとえば、無料版と有料版で別 APK を作成するためので Flavor を追加する場合は以下のように build.gradle の android の中に以下の記述を追加します。

android{
    (略)
    // ここから追加
    defaultConfig {
        versionCode = 12
        versionName = "1.2"
    }
    productFlavors {
        freeapp {
            packageName = "org.zakky.myproject.free"
            minSdkVersion = 14
        }
        paidapp {
            packageName = "org.zakky.myproject.paid"
            minSdkVersion = 16
        }
    }
    // ここまで追加
}

すべての Flavor に共通の設定は defaultConfig に記述し、 Flavor 毎の設定は productFlavors に記述します。この例では、全 Flavor 共通で versionCode とversionName を指定し、Flavor の設定で packageName と minSdkVersion を変更しています。各 Flavor にディレクトリに AndroidManifest.xml を置くことができるので、その中で例えな Free 版にだけ広告のために必要な追加 permission を指定することもできます。その場合でも、 versionCode とversionName defaultConfig によって一元管理することでメンテナンスのコストが上がらないように工夫されています。

Flavor を追加すると、gradle に指定するタスクが自動的に増えます。今回は freeapp と paidapp Flavor を追加したので、 installDebug が無くなり、代わりに installFreeappDebug と installPaidappDebug が追加されます(gradle tasks で確認してみてください)。

Flavor を追加した場合は gradle installFreeappDebug の様に、 install + <flavor名> + <build type 名> をタスク名に指定してください。

今回は Flavor の定義を追加しただけですが、 追加した Flavor に対応する Sourceset フォルダの中の java や res フォルダにファイルを配置することで、その Flavor の時のみビルドされるクラスやリソースを追加することができます。たとえば有料版にしか存在しない機能のコードは src/paidapp/java/ に、無料版にしか存在しない広告のレイアウトリソースは src/freeapp/res/layout/ に配置します。

これで一つの プロジェクトから、様々な APK を作成できるようになりました。

各 Flavor や BuildType でどのような設定を行うことができるかは、 Basic Project Setup を参照してください。

ライブラリプロジェクト作成

次に、ライブラリプロジェクトの扱いについてです。

基本的には上に書いたアプリのプロジェクトとほぼ同じなのですが以下の特徴があります。

  • BuildType や Flavor が追加できない
  • maven などで扱うため、.alb という拡張子のファイル(フォーマットは zip) を生成する

アプリのプロジェクトでは Flavor を定義することで様々な APK を生成することができましたが、ライブラリプロジェクトが作成できるのは debug と release の2種類のファイルだけです。また、debug はあくまでUnitTest などのためで、maven リポジトリにdeploy できるのは release 版のみです。

プロジェクトの作成手順はほぼアプリプロジェクトと同じなので、ライブラリプロジェクトについては build.gradle の作成と、maven リポジトリへのdeploy について書きます。

build.gradle の作成

アプリプロジェクトと同じように、空ディレクトリを作成したらまずは build.gradle ファイルを作成します。

以下にライブラリプロジェクト用の build.gradle のサンプルを掲載します。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.2'
    }
}
apply plugin: 'android-library'

sourceCompatibility=1.6
targetCompatibility=1.6

android {
    target = 'android-14'
}

dependencies {
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

apply plugin: 'maven'
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/Users/zaki/.m2/repository/")
            pom.version = '1.0'
            pom.groupId = 'org.zakky.android'
            pom.artifactId = 'MyLibrary'
        }
    }
}

アプりプロジェクト用の build.gradle と違う部分だけ説明します。

  • プラグインが 'android' ではなく 'android-library'
  • maven プラグインを指定し、deploy 先のリポジトリと、deploy するさいの groupId などを指定している。

このような build.gradle を作成したら、アプリプロジェクトと同じように src/main などを作成し、必要なファイルを配置します。

gradle build でビルド御テストが走ります。

maven リポジトリへの deploy

maven リポジトリへは以下のコマンドで deploy することができます。

$ gradle uploadArchives
:packageDebugAidl UP-TO-DATE
:prepareDebugDependencies
:compileDebugAidl
:generateDebugBuildConfig
:processDebugManifest
:processDebugRes
:compileDebug
:processDebugJavaRes UP-TO-DATE
:packageDebugJar
:packageDebugRes
:packageDebugSymbols
:bundleDebug
:packageReleaseAidl UP-TO-DATE
:prepareReleaseDependencies
:compileReleaseAidl
:generateReleaseBuildConfig
:processReleaseManifest
:processReleaseRes
:compileRelease
:processReleaseJavaRes UP-TO-DATE
:packageReleaseJar
:packageReleaseRes
:packageReleaseSymbols
:bundleRelease
:uploadArchives
Uploading: org/zakky/android/MyLibrary/1.0/MyLibrary-1.0.alb to repository remote at file://localhost/path-to/repository/
Transferring 42K from remote
Uploaded 42K
Uploading: org/zakky/android/MyLibrary/1.0/MyLibrary-1.0-debug.alb to repository remote at file://localhost/Upath-to/repository/
Transferring 42K from remote
Uploaded 42K

BUILD SUCCESSFUL

Total time: 5.696 secs
ライブラリプロジェクトを使う

ライブラリプロジェクトが maven リポジトリに deploy されていれば、後は dependency に依存を記述するだけです。先ほどの アプリプロジェクトの build.gradle の dependencies にライブラリプロジェクトへの依存を追加します。

dependencies {
    compile 'org.zakky.android:MyLibrary:1.0'
    compile files("${System.getenv('ANDROID_HOME')}/extras/android/support/v4/android-support-v4.jar")
}

これで MyLibrary プロジェクトに含まれている物を MyProject から利用することができます。

$ gradle installFreeappDebug
Deprecated: relying on packaging to define the extension of the main artifact is deprecated, and will not be supported in a future version of Gradle.
:prepareOrgZakkyAndroidMyLibrary10Library
:prepareFreeappDebugDependencies
:compileFreeappDebugAidl
:generateFreeappDebugBuildConfig
:crunchFreeappDebugRes
:processFreeappDebugManifest
:processFreeappDebugRes
:compileFreeappDebug
:dexFreeappDebug
:processFreeappDebugJavaRes UP-TO-DATE
:packageFreeappDebug
:installFreeappDebug
3365 KB/s (189528 bytes in 0.054s)
    pkg: /data/local/tmp/MyProject_gradle-freeapp-debug-unaligned.apk
Success

BUILD SUCCESSFUL

Total time: 10.026 sec

まとめ

今回は現在開発が進んでいる Gradle ベースの新ビルドシステムを実際に試して、手順とできることを書いてみました。

Flavor のサポートによって1つのプロジェクトから様々な APK が作成できる点と、maven や Ivy と親和性の高いライブラリプロジェクトが大きな目玉です。正式リリースはもうしばらく先になるとは思いますが、今回これらの機能を実際に使ってみて今後は CI との親和性がより高くなりまたメンテナンスもしやすい開発環境が構築できるのではないかなと思いまいた。

既存のプロジェクトの移行は多少面倒ですが、正式リリースの際にはプロジェクトの移行ツールなども提供されるのではないかなと思っています。 今回はじめて Gradle を使ったのですが強力なビルドシステムだと感じました。Android 以外でも Gradle を使用しつつ将来の 新ビルドシステムに備えようと思います。

また、この新ビルドシステムについては adt-dev Group で議論されています。ADT などについてもここで議論されているのでなにか気づいたことがあれば投稿してみるといいとおもいます(@sys1yagi さんのように!)。


2011-12-10 Android Advent Calendar 2011

_ Android開発を行う際の eclipse の便利設定

今日は Android Advent Calendar 2011 参加のエントリです。Advent Calendar って何という方は こちら をどうぞ。

多くの方が Android 開発に eclipse を使用していると思いますが、eclipse の機能を使いこなして快適な開発・効率のよい開発をしているでしょうか。今日は、わたしが普段使っている開発環境で行っている eclipse の設定を紹介したいと思います。まぁどっちでもいい好みの問題といえるような設定から、是非皆さんに使って欲しいお勧め機能までいろいろ紹介します。

今回のエントリでは eclipse の設定画面がたくさん出てきますが、どこにある設定であるかを示すのに [ aaa > bbb > ccc ] という表記をします。一番左が設定画面(Preferences) の左にでている項目を示しています。右はネストした項目だったり右側にでている項目だったりその時々によって異なりますがいちいち説明しません。感じ取ってください。また、設定の項目は英語版での表記です。普段日本語化していないので日本語表記が分かりません。普段日本語化している方はごめんなさい。これも感じ取ってください。

まずは軽めのものから。

Show heap status

[General] の中にある Show heap status チェックボックスです。

001_show_heap_status.png

このチェックボックスをチェックすると、右下の方に現在のヒープの大きさと使用しているメモリの量が表示されます。また、ゴミ箱アイコンをクリックするとeclipse を実行しているJVM で強制的に GC を走らせることができます。

002_heap_status.png

Show line numbers

[General > Editors > Text Editors] にある Show line numbers チェックボックスです。

003_show_line_numbers.png

このチェックボックスをチェックすると、ソースコードの左側に常に行番号が表示されるようになります。コレをチェックしなくても下の方に行番号と列番号が表示されているのでカーソル位置についてはわかるのですがわたしは表示するほうが好きです。ノートパソコンで開発する際など、少しでも画面を有効に使いたい場合は off のほうがいいかもしれません。

004_line_numbers.png

Show whitespace characters

[General > Editors > Text Editors] にある Show whitespace characters チェックボックスです。

005_show_whitespace_characters.png

このチェックボックスをチェックすると、テキスト中の空白、TAB、改行などが可視化されます。具体的には、半角空白が ・ に、 TAB が ≫ などとして表示されます。また、CR/CRLF/LF といった改行の違いも見た目でわかるようになります。半角スペースのつもりがTAB でインデントしてしまったり、行末に余計な空行が入っていてもすぐにわかるのでお薦めです。

006_whitespace_characters.png

Text file encoding

[General > Workspace] にある文字コードの選択のラジオボックスです。

007_text_encoding.png

当然ソースコードはUTF-8 で記述すると思うので、設定を UTF-8 にします。全てのワークスペースで UTF-8 しか使わないという人(大抵の人はそうだと思います)は、eclipse の実行ファイルの所にある eclipse.ini (MacOS X の場合は、 Eclipse.app を右クリックして「パッケージの内容を表示」してから Contents/MacOS/eclipse.ini) を開いて、 -vmargs と書かれた行の下に

-Dfile.encoding=UTF-8

を加えると、eclipse のデフォルトが UTF-8 になります。

Type Filters

[Java > Appearance > Type Filters] で、コード補完時に候補にしたくないクラスを指定します。

私は以下のクラスを指定しています。

android.R
java.awt.*

android.R を指定することで、 R.string などを補完する際は、アプリケーションが生成する R クラスとして補完されるようにしています。うっかり android.R として保管されてムキッって言ってしまう @lychee さんにぜひお勧めな設定です。また、 java.awt.* を指定することで、 List を補完した際に java.awt.List が候補の先頭に出てきてちげーよと思うことがなくなります。

他にも状況に応じて適宜加えると効率アップに貢献します。

Code Style

[Java > Code Style] で変数のプリフィックスを設定ます。

Android のコードはメンバ変数やstatic変数に接頭辞をつけるルールなので、これを eclipse に教えておきます。こうしておくと、getter/setter の生成時などに、変数の接頭辞を無視してメソッド名を生成してくれます。Fields の prefix list に m, Static Fields の Prefix list に s をそれぞれ記述します。

008_code_style.png

Code Templates

[Java > Code Style > Code Templates] で、eclipse が自動生成するコードをカスタマイズできます。わたしが行っているのは主に以下の変更です。

Commens > Files

ファイルの先頭に挿入されるコメントです。コピーライト表記を以下のような感じでいれています。今年が何年かを ${year} 変数から指定することで2012年も安心です。

/*
 * Copyright ${year} 自分の名前<じぶんのメールアドレス>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Comments > Types

クラスやインタフェースの前に挿入されるコメントです。個人で作る場合は @author の記述は邪魔なことが多いので消して以下のようにしています。

/**
 *
 * ${tags}
 */
Comments > Overriding methods

親クラスのメソッドをオーバーライドする際のコメントです。デフォルトでは (non-Javadoc) としてオーバーライドするメソッドが記述されますがeclipse を使っているなら簡単にオーバーライドされるメソッドに飛べるのでコメント自体を削除しています。

Code > Classbody

クラスを自動生成するさ際に挿入されるコードです。デフォルトでは何も書かれていませんが、わたしは以下のコードを記述しています。

@SuppressWarnings("unused")
private static final String TAG = "${type_name}";
private final ${type_name} self = this;

コレにより、各クラスに自動的に TAG と self が定義されるようになります。不要な場合も多いですが、その場合は自動生成後に削除します。必要になって書くよりも不要なときに消すほうが楽なのでこうしています。また、Android のコーディング規約的にはメンバ変数は m で始めるべきですが、 this と同じように使いたいのであえて付けていません。 self が定義してあると、Activity の中の無名インナークラスで Context を渡さないといけない際に HogeActivity.this と書かずに self でスマスことができます。この方法は @vvakame さんのコードで見かけてわたしも真似するようになった記憶があります。

Fomatter

[Java > Code Style > Formatter] で、オートフォーマットをする際の設定を行います。

フォーマッタ設定は各自の好みや AOSP の設定を使うなどすればいいと思いますが、オートフォーマット除外の tag を有効にしておくのをおすすめします。

Formatter の Edit ボタンを押し、 On/Off tags タブを選択します。そこに表示される Enable On/Off tags にチェックをつけます。デフォルトのタグとしては @formatter:on と @formatte'Formatter'r:off が設定されていると思います。

009_on_off_tags.png

この設定を有効にすることで、ソースコード中にオートフォーマットを行わない行を作ることができます。これでいつでも気兼ねなくオートフォーマットできます。

// @formatter:off
手動で頑張って整形したコード(配列の初期化を適当な数で折り返したい場合とか)
// @formatter:on

Save Actions

[Java > Editor > Save Actions] で、ファイルを保存する際に自動で実行する処理を指定します。

↑でオートフォーマット除外をしていれば常にオートフォーマットしても問題ないので Save Actions として実行することをおすすめします。

Templates

[Java > Editor > Templates] でコードや Javadoc に挿入するテンプレートを定義できます。私は以下のテンプレート定義を追加しています。

logd

Log.d(TAG,""); を生成するテンプレートです。コード中で logd<Ctrl-Space>(補完発動) すると、Logcat にデバッグログを出力するコードが一瞬で書けます。

name
logd
Context
Java
Automatically insert
yes
Description
log.d(TAG, );
Pattern
${:import(android.util.Log)}Log.d(TAG, ${cursor});
loge

Log.e(TAG,""); を生成するテンプレートです。コード中で loge<Ctrl-Space>(補完発動) すると、Logcat にエラーログを出力するコードが一瞬で書けます。

name
loge
Context
Java
Automatically insert
yes
Description
log.e(TAG, );
Pattern
${:import(android.util.Log)}Log.e(TAG, ${cursor});
logw

Log.w(TAG,""); を生成するテンプレートです。コード中で logw<Ctrl-Space>(補完発動) すると、Logcat に警告ログを出力するコードが一瞬で書けます。

name
logw
Context
Java
Automatically insert
yes
Description
log.w(TAG, );
Pattern
${:import(android.util.Log)}Log.w(TAG, ${cursor});
logi

Log.i(TAG,""); を生成するテンプレートです。コード中で logi<Ctrl-Space>(補完発動) すると、Logcat に情報ログを出力するコードが一瞬で書けます。

name
logi
Context
Java
Automatically insert
yes
Description
log.i(TAG, );
Pattern
${:import(android.util.Log)}Log.i(TAG, ${cursor});
tracelog

Log.dで、実行しているメソッドのトレースログを出力するコードを生成するテンプレートです。コード中で tracelog<Ctrl-Space>(補完発動) します。

name
tracelog
Context
Java
Automatically insert
yes
Description
log.d(TAG, );
Pattern
${:import(android.util.Log)}Log.d(TAG, "${enclosing_method}(...) called.");
onclick(2012/07/28追加)

Viewに対して OnClickListener をセットするためのコードテンプレートです。DialogInterface#OnClickListener と import が重複しないようになっているので両方を同じソースコード内で使用できます。

name
onclick
Context
Java
Automatically insert
yes
Description
set View#OnClickListener
Pattern
setOnClickListener(${imp:import(android.view.View)}new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               ${cursor}
           }
       });
onclick(2012/07/28追加)

Dialogに対して OnClickListener をセットするためのコードテンプレートです。View#OnClickListener と import が重複しないようになっているので両方を同じソースコード内で使用できます。

name
onclick
Context
Java
Automatically insert
yes
Description
set Dialog#OnClickListener
Pattern
setOnClickListener(${imp:import(android.content.DialogInterface)}new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               ${cursor}
           }
       });

起動設定(2012/07/13追加)

[Run/Debug > Launching] 起動対象の設定を行います。

デフォルトの設定では、Launch Configuration を指定しないでテストなどの実行を行う際、現在選択している(開いている)ものを対象にしたものが起動されます。実際の開発では直前に実行したものを起動したほうが便利なことが多いので、この設定を変更します。

010_Launching.png

この設定は小川 信一さんの「Google API Expertが解説する Google App Engine for Java実践ガイド」に載っていました。 この本は GAE/J の本ですが、Eclipse の tips も豊富に載っているのでとてもお勧めです。

まとめ

自分の eclipse をみながら普段どんな設定をしているかを書いてみましたが、このエントリの内容でみなさんの Android 開発が少しでも楽になればと思います。

本日のツッコミ(全1件) [ツッコミを入れる]

_ あおいたん [tracelogの見出しがlogiになってますよ]


2011-10-30 あと2日... だと

_ RC-S620/S を ADK(Arduino) から使う場合のちょっとした修正

RC-S620/S は、シリアル接続でコントロールできる NFC Reader/Writer モジュールです。arduino 向けライブラリが FeliCa Developers' Blog で公開されているので、ADK からもわりと簡単に使用することができます。

このライブラリはとても便利なのですが、使用するうえで一つ困ることがあります。それはこのライブラリが RC-S620/S との通信にシリアルポートを使用してしまうため、Arduino IDE の シリアルモニターが使えなくなってしまうことです。そこで、ライブラリが使用するシリアルポートを変更可能にするパッチを作成しました。

このパッチを適用すると、TX1/RX1 を使用するようになります。使用するポートを変更したい場合は、 RCS620S.h の SERIAL_RCS620S マクロの定義を変更してください。

また、 setup() などで RC-S620/S との通信に使用するシリアルポートを有効にする必要があります。以下のコードを追加してポートを有効にしてください。シリアルモニターを使用する場合は、 Serial.begin(115200); も残しておく必要があります。

 SERIAL_RCS620S.begin(115200);

arduino-RCS620S.zip に適用する場合は、ディレクトリ構造が異なるので patch -p3 とするなど、適宜調整してください。

RCS620S_port_selectable.diff

diff --git a/firmware/RCS620S/RCS620S.h b/firmware/RCS620S/RCS620S.h
index 9792859..f2a17c0 100644
--- a/firmware/RCS620S/RCS620S.h
+++ b/firmware/RCS620S/RCS620S.h
@@ -16,6 +16,15 @@
 #define RCS620S_MAX_CARD_RESPONSE_LEN    254
 #define RCS620S_MAX_RW_RESPONSE_LEN      265

+
+/*
+  for default Serial port, use Serial
+  for TX1/RX1,             use Serial1
+  for TX2/RX2,             use Serial2
+  for TX3/RX3,             use Serial3
+*/
+#define SERIAL_RCS620S Serial1
+
 /* --------------------------------
  * Class Declaration
  * -------------------------------- */
diff --git a/firmware/RCS620S/RCS620S.cpp b/firmware/RCS620S/RCS620S.cpp
index fe9eb01..bf0f776 100644
--- a/firmware/RCS620S/RCS620S.cpp
+++ b/firmware/RCS620S/RCS620S.cpp
@@ -309,7 +309,7 @@ void RCS620S::writeSerial(
     const uint8_t* data,
     uint16_t len)
 {
-    Serial.write(data, len);
+    SERIAL_RCS620S.write(data, len);
 }

 int RCS620S::readSerial(
@@ -324,8 +324,8 @@ int RCS620S::readSerial(
             return 0;
         }

-        if (Serial.available() > 0) {
-            data[nread] = Serial.read();
+        if (SERIAL_RCS620S.available() > 0) {
+            data[nread] = SERIAL_RCS620S.read();
             nread++;
         }
     }
@@ -335,7 +335,7 @@ int RCS620S::readSerial(

 void RCS620S::flushSerial(void)
 {
-    Serial.flush();
+    SERIAL_RCS620S.flush();
 }

 int RCS620S::checkTimeout(unsigned long t0)

2011-10-26 GDDまであと一週間とか...

_ Changes to Library Projects in Android SDK Tools, r14 の翻訳

2011年10月25日11:30 AM, Android SDK テックリードの Xavier Ducrohet の投稿。

Android 4.0 の SDK と新しい開発ツール群をrevision 14として先週リリースしました。新しいツール群はビルドパフォーマンスを改善する沢山の変更を含んでいます。これらの変更の中に、ライブラリプロジェクトの扱われ方の変更が含まれています。これはライブラリサポートとコードの再利用性を改善するための第一歩です。ライブラリプロジェクトの扱いに関する変更が既存のプロジェクトに対して影響しないよう考慮していますが、新ツールへ移行する際に問題が発生する場合もあります。ライブラリプロジェクトに対する変更と移行時の問題の解決方法については以下を読んでください。

以前は、ライブラリプロジェクトのリソースとソースコードはメインプロジェクトのリソースとソースコードをコンパイルする際の追加フォルダとして扱われていました。大抵の場合はこの方法でうまく行きますが、2つの問題がありました。

  1. コンパイルされたコードとリソースの両方を含んだ単一のJarファイルとして配布することが可能かと聞かれるが、Android のリソースに対するIDがコンパイル時に決まってしまうためそれは不可能だった。
  2. ライブラリプロジェクトの実装が Eclipse では柔軟性に欠けていた。ユーザーがプロジェクトをどこに配置しているかに依存しない形でプロジェクトフォルダ外のソースフォルダを追加することは簡単ではない(これは SVN や git のようなソースコード管理システムを使ってチーム開発をする上で必要になる)。

r14では、コンパイルされたコードによるライブラリへ移行することでこの両方の問題を一度に解決することにしました。この方法は、Eclipse における柔軟性のなさを改善すると共に、ライブラリを単一の Jar ファイルとして配布することを可能にします。

リリースノートで見たかもしれませんが、この方式への移行は幾つかの場合で既存のプロジェクトに影響を与えます。しかし修正は難しくありません。

一つ目の影響は、ライブラリプロジェクトに含まれるリソースのIDが final ではなくなったことによるものです。この変更により、Javaコンパイラはライブラリに含まれるIDの値をインライン展開できなくなります。これは、 ID の値を switch 文の case ラベルとして使用できないことを意味します。 このようなコードが存在する場合、Eclipse が提供するリファクタリング機能を用いて、 switch 文を if/else に変換することができます(here 参照)。

移行が正しく行えなかった場合の図

二つ目は、プロジェクトによっては新しい方式に正しく移行されない場合があることです。 dex のビルドステップでのクラス重複などのエラーが発生し、プロジェクトのコンパイルに失敗します。 ADT14 はこれまでのプロジェクトを新しい方式へ移行させますが、既存の方式が抱える問題により正しく移行できないこともあります。移行が正しく行われないと、これまでの方式と新しい方式によってプロジェクトがライブラリを2回参照してしまい、ライブラリ側のクラスが2回パッケージングされてしまいます。このような場合は、Package Explorer(パッケージエクスプローラー) で <ライブラリ名>_src という名前の余分なソースフォルダがないか確認してください。右のスクリーンショットこのような場合の例を示しています。

エラーを修正するには、以下の手順で余分なソースフォルダを取り除いてください。

  • ソースフォルダを右クリックし、Build Path > Remove from Build Path を選択する
  • ダイアログがポップアップするので、完全にフォルダが取り除かれるよう "Also unlink the folder from the project"にチェックが付いていることを確認する。

このライブラリプロジェクトに対する変更により、コンポーネントの再利用に対するより良いサポートを提供します。コンポーネントの作成、利用、管理をより簡単に行えるよう引き続き改善を行なっています。私達のゴールは開発者の方々がすべてのフォームファクターに対して素晴らしいユーザーエクスペリエンスを持ったアプリの作成をお手伝いすることです。

ライブラリプロジェクトは組織内部でしか使用していないのでバイナリでの配布よりも今までのソースコードベースの方式が良いという開発者の方もいます。ソースコードベースの方式も新方式と平行してサポートできるようにする方法も検討中です。

最後に、私達が r14 で把握しているいくつかの既知の問題(とそのワークアラウンド)を次のサイトに記述しています。 http://tools.android.com/knownissues

これらの問題を修正するアップデートの公開に向けて作業を続けています。できるだけ早くリリースできることを期待しています。


2010|02|03|08|10|12|
2011|06|07|10|12|
2012|12|
2013|06|
追記