Android Kotlin+Data Bindingでビルドエラーに陥った話

AndroidアプリでWebViewを使う際、URLをViewModelのurlと連動させるというデータバインディングをしたかった。
最低限の実装は以下の通り。

```xml:web_view_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<layout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
                name="viewModel"
                type="com.vitantonio.nagauzzi.unusedappfinder.viewmodel.WebViewViewModel"/>
    </data>

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            tools:context=".view.WebViewFragment">

        <WebView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:url="@{viewModel.url}"/>
    </LinearLayout>

</layout>
```

```kotlin:WebView.kt
@BindingAdapter("url")
fun WebView.bindUrl(url: String?) {
    if (url != null) {
        loadUrl(url)
    }
}
```

```kotlin:WebViewViewModel.kt
class WebViewViewModel: ViewModel() {
    val url = MutableLiveData<String>()
}
```

```kotlin:WebViewFragment.kt
class WebViewFragment : Fragment(), KodeinAware {
    override val kodein by closestKodein()

    private val viewModel by lazy {
        ViewModelProviders.of(this, direct.instance()).get(WebViewViewModel::class.java)
    }
    private lateinit var binding: WebViewFragmentBinding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = WebViewFragmentBinding.inflate(inflater, container, false).also {
            it.lifecycleOwner = this
        }
        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        binding.viewModel = viewModel

        // URLを直接指定（汎用化する際はthis.argumentsで外部から指定できる）
        viewModel.url.value = "file:///android_asset/licenses.html"
    }
}
```

```groovy:app/build.gradle
android {
    ...
    dataBinding {
        enabled = true
    }
}
```

これでいけるだろうと思ったら、ビルドエラーが発生。

```
Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute 'app:url' with parameter type androidx.lifecycle.MutableLiveData<java.lang.String> on android.webkit.WebView. file:/Users/nagauchi/Project/UnusedAppFinder/app/src/main/res/layout/web_view_fragment.xml loc:22:27 - 22:39 ****\ data binding error ****
```

とりあえずググってStackOverflowに辿り着いた。
https://stackoverflow.com/questions/44301545/2-way-databinding-for-webview-and-progressbar
けど、@BindingAdapterの記述は間違っていないし、build.gradleにdataBindingの記述もしていた。
わからなくて小一時間悩みまくった。

## 原因

以下の記述が足りなかった。

```groovy:app/build.gragle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
```

足りなかったのは`apply plugin: 'kotlin-kapt'`の部分。
apply pluginする順番も重要らしい。
とりあえずこれでビルドが通るようになった。

会社のチームプロジェクトではいつの間にか`apply plugin: 'kotlin-kapt'`が付いてたが、
個人環境だとすっかり忘れており、Javaで実装されたData Bindingのソースコードを見よう見まねで進めていた。

## わかったこと
KotlinでData Binding、というかアノテーションを用いたコード生成全般を扱うには、
Kaptというコンパイラープラグインが必要。
https://kotlinlang.org/docs/reference/kapt.html