GradleでAndroidを継続的インテグレーションするための雛形
旧ブログ(blog.ogaclejapan.com)から移行してきた古い記事です。 移行に伴い、一部のレイアウトが崩れている可能性もありますmm
GradleでAndroidビルドを検証したので雛形をUPしておく。
参考にしたのは「Android Tools Project Site」のサイト
※ちなみにGradleはバージョン1.2じゃないと動かないらしいので注意!
build.gradleの雛形
以下のコードをAndroidプロジェクト直下にbuild.gradle
という名前で保存する。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.2'
}
}
project.ext {
def projectProps = new Properties()
file("project.properties").withInputStream {
stream -> projectProps.load(stream)
}
props = new ConfigSlurper().parse(projectProps)
manifest = new XmlSlurper().parse(file("AndroidManifest.xml"))
}
apply plugin: 'android'
android {
target = project.props.target
defaultConfig {
//manifestファイルと異なるビルドをする場合のみコメント外すこと
//packageName = manifest.@package.text()
//versionCode = manifest.@versionCode.text()
//versionName = manifest.@versionName.text()
}
buildTypes {
debug {
//packageNameSuffix = ".dev"
debuggable = true
debugSigned = true
zipAlign = true
}
staging {
//packageNameSuffix = ".stg"
debugSigned = true
zipAlign = true
}
release {
debugSigned = false
zipAlign = true
}
}
sourceSets {
main {
manifest {
srcFile 'AndroidManifest.xml'
}
java {
srcDir 'src'
}
res {
srcDir 'res'
}
assets {
srcDir 'src'
}
resources {
srcDir 'src'
}
}
test {
java {
srcDir 'tests/src'
}
resources {
srcDir 'tests/src'
}
}
debug {
java {
srcDir 'profiles/dev/src'
}
resources {
srcDir 'profiles/dev/src'
}
}
staging {
java {
srcDir 'profiles/stg/src'
}
resources {
srcDir 'profiles/stg/src'
}
}
release {
java {
srcDir 'profiles/release/src'
}
resources {
srcDir 'profiles/release/src'
}
}
}
}
sourceCompatibility=1.6
targetCompatibility=1.6
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
tasks.withType(Compile) {
options.encoding = 'UTF-8'
}
packageNameSuffixについて
生成するapkに指定した名前を付加してくれるものと思ってたら、全く違った。。
このパラメータの用途は環境ごとに異なるapkを1つの端末に同時にインストールすることができるようにするための設定だと思われる。
manifestファイルのpackage
属性を環境ごとに一意にすることで別物のアプリとして認識させるためのパラメータのようだ。
生成されるmanifestファイルはこんな感じかな。
(debug版ビルド)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ogaclejapan.dev"
android:versionCode="1"
android:versionName="1.0">
...
</manifest>
(staging版ビルド)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ogaclejapan.stg"
android:versionCode="1"
android:versionName="1.0">
...
</manifest>
ただし、このパラメータを使用するにはmanifestファイルの書き方に注意する必要があるのでメモしておく。
-
manifestファイルの
application
要素以下すべてのパッケージ名をフルパスで定義すること⇒ドット
.
からの相対パスで要素を定義するとpackage
属性を基準にされてしまうので定義したクラスまでのパッケージパスがズレる
プロファイル環境毎に設定ファイルを切り替える
mavenのprofiles機能と同様にdevやstagingなど環境毎に変わるものを上書きすることができる。
この雛形ではprofiles/xx/src
がprofilesと同じ役目を果たしている。
現状、切り替え可能なことを確認できたのは、
- resources配下のプロパティファイル(xx.properties)
- res/values配下の設定ファイル
のみ。
現段階のバージョンが未実装なのか不明だが、 Javaコードや画像ファイル類は反映されなかった。
...
debug {
resources {
srcDir 'profiles/dev/src'
}
res {
srcDir 'res'
}
}
staging {
resources {
srcDir 'profiles/stg/src'
}
res {
srcDir 'res'
}
}
release {
resources {
srcDir 'profiles/release/src'
}
res {
srcDir 'res'
}
}
...
※sourceSetsより前でbuildTypesを定義しないとビルド時にエラーが発生するようなので注意!
フォルダ構成がMaven系の場合
既にフォルダ構成がsrc/main/java,src/main/resources
などmaven系プロジェクトの場合はsourceSets
を以下のように変更してやる必要がある。
...
sourceSets {
main {
manifest {
srcFile 'src/main/AndroidManifest.xml'
}
java {
srcDir 'src/main/java'
}
res {
srcDir 'src/main/res'
}
assets {
srcDir 'src/main/assets'
}
resources {
srcDir 'src/main/resouces'
}
}
test {
java {
srcDir 'src/test/java'
}
resources {
srcDir 'src/test/resources'
}
}
debug {
java {
srcDir 'src/dev/java'
}
resources {
srcDir 'src/dev/resources'
}
}
staging {
java {
srcDir 'src/staging/java'
}
resources {
srcDir 'src/staging/resources'
}
}
release {
java {
srcDir 'src/release/java'
}
resources {
srcDir 'src/release/resources'
}
}
}
...
ちなみにこのプラグインはデフォルトmaven形式を推奨しているので、sourceSetsのデフォルトが上記のような値になっていると思われる。従ってsourceSetsの定義はいらないかも。。
※あと現時点ではEclipseのADTがこのフォルダ構成を認識してくれないので、おすすめしない。
ネイティブ共有ライブラリ(libxx.so)をApkに含める方法
実際のところ、これが一番ハマった。。 EclipseのADTプラグインはlibs/armeabi配下に置いとけば自動で含めてくれてたし、 そもともADTプラグインがどうやってapkを生成しているかなんて全く知らん。
色々なサイトを探しまわった結果、adt-devのForumに同じ質問をしているスレを発見。 https://groups.google.com/forum/?fromgroups=#!topic/adt-dev/SOs6mxZGjMM
Support for .so libraries in Gradle builds? で、結論からいうと、現段階のバージョンでは未実装とのこと…orz
しかし、神現る!! このスレにHackしたという人の書き込みがあり、Hack方法をGistにアップしてくれている。
ただGistのコードだと要らない部分も含まれていたり、 libs配下にsoファイルを置いているケースではなかったりするので、実際に試してたHack定義をメモしておく。
task copyNativeLibs(type: Copy) {
def libsDir = "$projectDir/libs"
from(libsDir) { include '**/*.so' }
into new File(buildDir, 'native-libs')
}
tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }
clean.dependsOn 'cleanCopyNativeLibs'
//この定義があるとgradle tasksコマンドが例外で発生する
tasks.withType(com.android.build.gradle.PackageApplicationTask) { pkgTask ->
pkgTask.jniDir new File(buildDir, 'native-libs')
}
一応コード中にコメントで記載したが、 この定義をしてからGradleタスクのtasksコマンド使用できなくなった。。 解決方法があるのか今のところ不明なため、共有ライブラリが必要なければムリにこのHackを入れないほうが良さげ。