Kotlin用のCleanArchitectureのテンプレート作ったよ！

# はじめに
CleanArchitectureってなに？という話は[この辺を参照](http://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc)
で、CleanArchitectureの最大の問題は、**きっちりやろうとすればするほど、クラス数が増えていくということ。**
Kotlinを導入してせっかくコード量が減るのに、クラス数が増えることで作業が増えてしまえば、旨味が減ってしまう。
しかもAndroid-Studio(Ver3.0)の対応がまだ途中なのか、微妙にKotlinのクラス作成手順がメンドクサイ

なので、解決策として、**CleanArchitecture用のテンプレートを用意し、極力クラス作成に関わる作業を簡略化し、必要最低限の作業で必要なクラスを一括で作成できるようにした。**

ちなみにこの記事の内容はGithubのREADMEの内容をほぼそのまんま持ってきてます。

# 諸々置き場
ココ
https://github.com/kiuchikeisuke/Android-Studio-CleanArchitecture-template-forKotlin

# 前提条件
- [Kotlin](https://kotlinlang.org/)**([Android-Studio 3.0](https://developer.android.com/studio/preview/index.html)を推奨)**
- [Dagger2](https://google.github.io/dagger/) 
- [RxJava2](https://github.com/ReactiveX/RxJava) 
- [KotterKnife](https://github.com/JakeWharton/kotterknife) (**非必須ではあるが強く推奨**)

# インストール
#### Macの人
以下のコマンドで終わり

```
./install.sh
```

手動の場合は以下の５つのフォルダを、
`$ANDROID_STUDIO_FOLDER$/Contents/plugins/android/lib/templates/activities/`に貼り付ける

- `BaseCleanArchitectureTemplateKotlin`
- `DataTemplateKotlin`
- `DomainTemplateKotlin`
- `PresenterActivityTemplateKotlin`
- `PresenterServiceTemplateKotlin`

#### Windowsの人
手動で以下の５つのフォルダを、
`$ANDROID_STUDIO_FOLDER$\plugins\android\lib\templates\activities\`に貼り付ける

- `BaseCleanArchitectureTemplateKotlin`
- `DataTemplateKotlin`
- `DomainTemplateKotlin`
- `PresenterActivityTemplateKotlin`
- `PresenterServiceTemplateKotlin`

# 使い方
## 1.ベーステンプレートを作成する
テンプレート>Activity>`CleanArchitectureTemplate`を選択する
<img width="868" alt="selectBaseTemplate.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/963f4d33-239e-c7e7-db9a-26ff00f7bbc4.png">

もし、新規作成する場合は、以下の画面で`CleanArchitectureTemplate`を選ぶ
<img width="1049" alt="createNewPrj.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/46c3c61a-07a0-c27c-6eae-5ffe8ecdea3f.png">

その後、各種設定を行う

- **Application Class Name** -> ルートとなるApplicationクラス名を設定。任意でOK
- **Create kotlin src dir?** -> kotlin用のディレクトリを作成するかどうか。事前に作っていない場合はチェックする
- **Need Realm?** -> [Realm](https://realm.io/) を使うかどうか。使うならチェックする
- **Need Retrofit2?** -> [Retrofit2](http://square.github.io/retrofit/) を使うかどうか。使うならチェックする
- **Use Swagger?** -> RetrofitのAPIが[Swagger](http://swagger.io/)(RxJava2使用) で生成する場合はチェックする

設定が終わったらFinishクリック

## 2. build.gradleを修正する
以前、「[AndroidStudio3.0 CanaryでKotlin開発の事始め](http://qiita.com/k_keisuke/items/82ab752c43edda28ffe6)」でも触れたように、kotlinのデフォルトバージョンが古いためビルドエラーが発生するケースがあるので、build.gradleを修正する
<img width="1341" alt="gradleError.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/cd1f6142-bf6a-f3d6-6a56-687c0ecbc43b.png">

```groovy:root/build.gradle
buildscript {
//    ext.kotlin_version = '1.1.2-3' 元の記載
    ext.kotlin_version = '1.1.2-4'
    repositories {
        maven { url 'https://maven.google.com' }
        jcenter()
    }
```

同様に、app/build.gradleのapplyの記載がおかしくなることがあるのでこれも修正する(原因がわからないのでもし知っているからいたら情報を。。。)

```groovy:app/build.gradle
- apply {
-     plugin: 'com.android.application'
-     plugin: 'realm-android'
- }
-
- apply {
-     plugin: 'kotlin-android'
-     plugin: 'kotlin-kapt'
- }

+ apply plugin: 'com.android.application'
+ apply plugin: 'realm-android'
+ apply plugin: 'kotlin-android'
+ apply plugin: 'kotlin-kapt'
```

# 各種テンプレートの使い方
**一部のテンプレートはユーザー作業が必要なので注意**

## DataTemplateKotlin
DataLayerのテンプレートを作成する
<img width="471" alt="dataTemplate.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/28900d53-439c-b6b4-45ba-5ccb3b5cae9c.png">

ウィザードに沿っていくと、XXXDataSource,XXXDataRepositoryというクラスが作成される。

で、XXXDataSourceクラスを見ると、以下のような記載がある

```kotlin:XXXDataSource
/*    FIXME MUST add below method to RepositoryModules */
//    @Provides fun provideMainDataSource(repository: MainRepository): MainDataSource = repository
```

注意書きの通りにコメントアウトされている、`@Provides fun provideMainDataSource(repository: MainRepository): MainDataSource = repository`の記載をコピーし、RepositoryModulesクラスに貼り付ければOK

DataLayerはDomainLayerに対してI/Oを提供する

## DomainTemplateKotlin
DomainLayerのテンプレートを作成する
<img width="473" alt="domainUsecaseTemplate.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/7926197b-8c74-4683-46f1-5abe6f6d5567.png">

dataLayerに対してInputが必要かどうか、PresenterLayerに対してOutputを行うかどうかのチェックによってそれぞれ、IoUsecaseClass / InputOnlyUseCaseClass / OutputOnlyUseCaseClass /SimpleUseCaseClass のいずれかが作られる

DomainLayerはビジネスロジックを実装し、DataLayerとPresenterLayerをつなぐ役割を持つ

## PresenterActivityTemplateKotlin
PresenterLayerのActivityのテンプレートを作成する
<img width="471" alt="presenterActivityTemplate.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/dfc018d6-bac7-d864-9899-75b9e12d23c8.png">

ウィザードに沿って入力すると、ComponentClass, ContractClass, ModuleClass, PresenterClass, ActivityClass, FragmentClass, fragment.xmlが作られる

で、ActivityClassを見ると以下のような記載がある

```kotlin:ActivityClass
        /* FIXME 1st:MUST add below method to RootComponent */
        // fun newSomeComponent(module: SomeModule): SomeComponent

        /* FIXME 2nd:initialize SomeComponent like this */
        (application as MainApplication).rootComponent
                .newSomeComponent(SomeModule(fragment as SomeContract.View))
                .inject(fragment)
```

注意書き1の通りにコメントアウトされている、`fun newSomeComponent(module: SomeModule): SomeComponent`の記載をコピーし、RootComponentクラスに貼り付ける
その後、注意書き2の部分のMainApplicationを正しいものに修正する

## PresenterServiceTemplateKotlin
PresenterLayerのServiceのテンプレートを作成する
<img width="473" alt="presenterServiceTemplate.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/3eed6d27-1e26-ebb0-e16a-395a8bc6cfdd.png">

ウィザードに沿って入力していくと、ComponentClass, ContractClass, ModuleClass, PresenterClass, ServiceClassが作られる。

で、ServiceClassを見ると以下のような記載がある。

```kotlin:ServiceClass
/* FIXME 1st:MUST add below method to RootComponent */
// fun newMainComponent(module: MainModule): MainComponent

/* FIXME 2nd:initialize MainComponent like this */
(application as MainApplication).rootComponent
        .newMainComponent(MainModule(this)).inject(this)
```

注意書き1の通りにコメントアウトされている、`fun newMainComponent(module: MainModule): MainComponent`の記載をコピーし、RootComponentクラスに貼り付ける
その後、注意書き2の部分のMainApplicationを正しいものに修正する

# Example
Exampleフォルダの下に簡単なサンプルを用意したので、各クラスを具体的にどう実装するかはそちらを参考にした方がよいかと。

サンプルの内容は、Input1ボタンを押したらTextViewに「Input 1」を、Input0ボタンを押したらTextViewに「Input 0」を表示するという内容。

いずれRetrofitを使ったサンプルも作ろうかなぁとは思わなくもない・・・かもしれない.