Android studioにおけるbuild.gradleの設定について

#はじめに
最近Eclipse + ADTからstudioに移行した際にgradleの設定で色々行ったので個人メモとして残しておきます。

studioへの移行については他の方がまとめていらっしゃるので今回は特に触れませんが、私が行ったprojectでは単純にExportしても動かなかったので空のprojectを作ってソースやらリソースを移植しました。

http://techbooster.org/android/environment/16158/

#環境情報
Android studio 1.4
gradle 1.3.1

#Gradleについて
・Gradleは、Groovyで書かれているAntのよう汎用的にビルドができるツールです。
・Maven/Ivyリポジトリをサポートしているのでライブラリの依存関係の管理や追加などは自動で行ってくれる
・Antとも連携可能なようです。※いずれ機会があれば試してみます。

#Androidアプリプロジェクトとファイルの構成
![スクリーンショット 2015-10-16 20.37.06.png](https://qiita-image-store.s3.amazonaws.com/0/96091/10d842fc-ebd6-c8a6-0247-d9eba959026d.png)


#アプリケーション内のbuild.gradleの設定

```
build.gradle

//プラグインの宣言
apply plugin: 'com.android.application'

//定数定義 gradleでは以下のようの定数を指定することができる
def VERSION_CODE = 1
def VERSION_NAME = "1.0.0"
def PACKAGE_NAME = "com.kazuhiro.helloworld"
def APPNAME = "Hello World"

//androidのビルド設定のメイン
android {
    //アプリをビルドする際のSDKの設定
    //compileSdkVersionやbuildToolsVsersionの記述
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    //マニュフェストエントリ
    defaultConfig {
        applicationId PACKAGE_NAME
        minSdkVersion 15
        targetSdkVersion 22
        versionCode VERSION_CODE
        versionName VERSION_NAME
    }

    dexOptions{
        jumboMode true

        //gradleでビルドしてOutOfMemoryErrorが出るのであれば指定した方がよいです
        javaMaxHeapSize "2g"
    }

    //jar ファイルに含まれるリソースファイルが複数あると重複エラーになるので
    //packagingOptionsにて必要に応じて指定しておく。
    packagingOptions {
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
    }

    //lintオプション
    //abortOnError falseにすることでlintエラーが発生してもエラーとならないようにする。
        lintOptions {
        abortOnError false
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

    //署名設定
    signingConfigs {
        //デバッグ用
        debug {
            storeFile file(debugKeystore)
        }

        //release 用
        release {
            storeFile file(productKeystore)
            keyAlias productKeyAlias
            storePassword productKeyPass
            keyPassword productAliasPassword
        }
    }

    productFlavors {
        dev {
            applicationId "${PACKAGE_NAME}.dev"
            manifestPlaceholders = [appName: "${APPNAME} dev"];
        }

        product {
            applicationId PACKAGE_NAME
            manifestPlaceholders = [appName: "${APPNAME}"];
        }
    }

    //ビルド定義
    buildTypes{
        debug{
            debuggable true
            applicationIdSuffix ".debug"
            signingConfig signingConfigs.debug
        }

        release{
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}

//ライブラリ依存関係
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
}

```

##各項目の説明
各項目の詳細は以下のとおりです。

###プラグインの宣言
**アプリケーションの場合**
```
apply plugin: 'com.android.application
```

**android ライブラリの場合**
```
apply plugin: 'com.android.library'
```

###def
以下のように指定することでbuild.gradlde利用できる定数を宣言できます。便利ですね :smile: 

```
def VERSION_CODE = 1
def VERSION_NAME = "1.0.0"
def PACKAGE_NAME = "com.kazuhiro.helloworld"
def APPNAME = "Hello World"
```

###android{}
Android Gradle Pluginでは、android {} ブロックにビルドの設定などを記述していきます。

##Build Target
アプリビルド時のAndroid SDK及びToolのVersionを指定してください。

```
android {
    //アプリをビルドする際のSDKの設定
    //compileSdkVersionやbuildToolsVsersionの記述
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

}
```

##defaultConfig
ADTの場合は、Manifesfファイルに直接記述していましたが、build.gradleに記述しておくことでビルド時に自動でマニフェストに追加してくれます。

```
defaultConfig {
    applicationId PACKAGE_NAME
    minSdkVersion 15
    targetSdkVersion 22
    versionCode VERSION_CODE
    versionName VERSION_NAME
}

```

##packagingOptions
複数のLibraryが利用されるときに META-INF内のFileがConflictするため重複エラーにならないように以下のように指定することで回避することができます。必要に応じて適時追加してください。

```
 packagingOptions {
     exclude 'META-INF/NOTICE.txt'
     exclude 'META-INF/LICENSE.txt'
     exclude 'META-INF/NOTICE'
     exclude 'META-INF/LICENSE'
 }

```


##signingConfig
署名付きAPKファイルを生成する際のkeysotreの設定情報を記述する。debug/reelaseそれぞれ記述することができます。
パスワードは直接buld.gradleに記述せずに外部ファイルもしくは、gradle.propertiesに出しておいた方が良いですね。
今回はgradle.propertiesから読み込む例を記載しておきます。

```
//署名設定
signingConfigs {
    //デバッグ用
    debug {
       storeFile file(debugKeystore)
    }

    //release 用
    release {
        storeFile file(productKeystore)
        keyAlias productKeyAlias
        storePassword productKeyPass
        keyPassword productAliasPassword
    }
}
```

***gradle.properties***
gradle.propertiesにプロパティとして以下のように定義しておきます

```
#デバッグ用のデバッグ署名
debugKeystore=../keystore/debug.keystore

#release用の署名情報
productKeystore=../keystore/product.keystore
productKeyAlias=com.kazuhiro.helloworld
productKeyPass=Hello
productAliasPassword=hello
```

***外部ファイルの場合***
http://www.slideshare.net/MakotoYamazaki/20150425-droidkaigi-gradle
のP15に記載されている方法でも取り込めるようです。そのうち試してみたいと思います。

##productFlavors
開発版と商用版、有料版アプリ、無料版アプリなどをわけてapkを作成したい場合に、productFlavorsに定義することでそれぞれ作成したいアプリを作成することができます。

Product Flavorは任意の数だけ定義できるので、複数パターンのアプリを作る必要がある場合は便利な機能です。

今回は、開発用、商用版向けに変更したい場合を例に記載しておきます。
アプリケーションIDと、アプリ名を変更するようにしております。

```
 productFlavors {
     dev {
         applicationId "${PACKAGE_NAME}.dev"
         manifestPlaceholders = [appName: "${APPNAME} dev"];
     }

     product {
         applicationId PACKAGE_NAME
         manifestPlaceholders = [appName: "${APPNAME}"];
     }
 }

```

上記に記載してますが、manifestPlaceholdersというものを使うことでManifestファイルにて変数を埋め込むことができます。
ここではアプリ名を変更する例を記載してます。

```
AndroidManifest.xml
<application
        android:name=".BaseApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="${appName}" ←アプリ名
        android:largeHeap="true"
        android:theme="@style/AppTheme" >

        <activity
            android:name=".TopActivity"
            android:label="${appName}"　←アプリ名
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

```

##buildTypes
debuggableなどの設定や署名、proguardの利用などの設定を行うことができます。
実際にはproductFlavorsとの組み合わせでビルドすることになります。
applicationIdSuffixなどもかえられるのでdebug用、release用とで区別してapkを作成することができます。

```
buildTypes{
    debug{
        debuggable true
        applicationIdSuffix ".debug"
        signingConfig signingConfigs.debug
    }

    release{
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.release
    }
}

```

##ソースやソースファイルの切替について
Product Flavorごとにディレクトリを分け、ソースファイル、画像などのリソースファイルなどをProduct Flavorごとに切り替えることもできます。

下記のようにmain と同じ階層にproductFlavorsで追加した開発用のdevと同じ名前のフォルダを作成して、javaファイル、リソースファイル、assetsの各種ファイルを配置しておくことでビルド時に選択したBuild Variantによって自動でおきかえてくれます。
drawbleのアイコンを開発用に用意することでアプリアイコンも商用用と開発用で切り替えることも可能です。

※ここでは、productはmainを利用するためproduct用のディレクトリは作成していませんが、必要であればproductのフォルダを作成してください。

![スクリーンショット 2015-10-17 22.48.50.png](https://qiita-image-store.s3.amazonaws.com/0/96091/2657fc5b-7ff9-0de6-cacb-3c7349fff406.png)


#その他
アプリによりPUSH機能を使っている場合は、GCMのpermissionでパッケージ名.permisson.C2D_MESSAGEと記述する必要がありますが、manifestファイルにて以下のように指定おくことでFalvorによってパッケージ名が変わる場合も考慮することができます。

```
<permission android:name="${applicationId}.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

```

ちなみにBroadcastReciver等のintentfileterのカテゴリ名等でパッケージを指定する場合も同様です。

```
<receiver
  android:name="xxxxxx" 
  android:permission="com.google.android.c2dm.permisson.SEND"
  
  <intent-filter>
     <action android:name="com.google.android.c2dm.permisson.RECEIVE"
     <category android:name="${applicationId}">
  </intent-filter>

</receiver>

```

#build.gradleの書式について
@opengl-8080さんがまとめられているので参考にしてみてください。
http://qiita.com/opengl-8080/items/a0bb31fb20cb6505188b


#まとめ
・Antに比べて容易に設定できるので使いやすい
　Eclipse + ADTの時のantでごにょごにょやってた時よりもだいぶ楽ですね :smile: 
　ステージング向けとか、開発環境向けとか、商用向けのアプリの切り替えやリソースファイルなども環境によって差し替えられるのでそのよう
　な開発をしている場合Eclipseで開発している場合はADTのサポートも終了するので早急にstudioへの移行を検討した方が良いかと思います。

・gradleでは上記以外の内容以外にも色々できるので今後はCI連携とか試してみたいです。

#参考サイト
http://tools.android.com/tech-docs/new-build-system/user-guide
http://www.slideshare.net/MakotoYamazaki/20150425-droidkaigi-gradle