あの素晴らしいlicense-tools-pluginをもう一度

# :egg: はじめに

Qiita初投稿になります。6年程会社でプログラマとして仕事をし、今はフリーランスでAndroidアプリを中心にJava/Kotlinでゴリゴリ開発してます。今回、Androidアプリで使っているライブラリの表示をする必要がありまして、以前採用させていただいたクックパッドさんの `license-tools-plugin` を使おうとしたのですが、プラグイン自体のアップデートやIDE(Android Studio)の更新もあり、すんなり導入することができませんでした。公式が [クックパッド開発者ブログ](https://techlife.cookpad.com/entry/2016/04/28/183000) で解説していますが、導入方法とハマったポイントを少し長いですが共有します。間違いや補足などがあればコメントにて教えてください。

# :egg: 開発環境

* PC: MacBook Air (11-inch, Early 2014)
* OS: macOS Mojave 10.14.3
* IDE: Android Studio 3.3.2

# :egg: license-tools-pluginとは

クックパッドさんが開発したGradleの神プラグインです。プロジェクトで使用しているライブラリのライセンスをYAMLで管理、HTMLもしくはJSONに一覧を出力してくれます。ライセンスの追記漏れもチェックしてくれる優れものです。GitHubのリポジトリは [こちら](https://github.com/cookpad/license-tools-plugin) です。

# :egg: 導入

Gradleのプラグインなので、プロジェクトルート直下の `build.gradle` に追記します。記事執筆時の最新バージョンは `1.7.0` でした。

```gradle:build.gradle[root]
buildscript {
    ...

    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.cookpad.android.licensetools:license-tools-plugin:1.7.0' // 追加
    }
}
```

アプリ内で使用する為に、app直下の `build.gradle` の冒頭に追記をします。

```gradle:build.gradle[app]
apply plugin: 'com.cookpad.android.licensetools' // 追加
```

動作する為に `JDK8` 以上が必須とのことなので、こちらも `build.gradle` に互換性を追記しておきます。 `JDK8` はAndroid Studio 3.3.2であれば、ビルトインとしてあらかじめ用意されているはずです。

```gradle:build.gradle[app]
android {
    ...

    // 追加
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
```

全ての追記が終わったら `Sync Project` を行い、エラーが出ていなければOKです。

# :egg: 使い方

## ライブラリの依存関係を確認

ライブラリの依存関係を確認します。今回はデモの為に、Androidアプリの開発でよく使うものを追加しました。

```gradle:build.gradle[app]
dependencies {
    // Kotlin
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

    // Android Support Library
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.android.support:cardview-v7:28.0.0'
    implementation 'com.android.support:design:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    // Square
    implementation 'com.squareup.moshi:moshi:1.8.0'
    implementation 'com.squareup.moshi:moshi-kotlin:1.8.0'
    implementation 'com.squareup:otto:1.3.8'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'

    // ReactiveX
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
}
```

## ライセンス情報の作成

依存関係の記述が終わったら、Android Studioのサイドバーにある `Gradle > [project-name] > :app > Tasks > verification` から、 `checkLicenses` タスクを実行します。コンソールにライセンス情報の一覧が出力されるので、app直下に `licenses.yml` を作成して内容をコピペします。

```yaml:licenses.yml
- artifact: android.arch.core:common:+
  name: Android Arch-Common
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache Software License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: https://developer.android.com/topic/libraries/architecture/index.html
- artifact: com.squareup.okhttp3:okhttp:+
  name: OkHttp
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: #LICENSE#
- artifact: org.jetbrains.kotlin:kotlin-stdlib:+
  name: org.jetbrains.kotlin:kotlin-stdlib
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: https://kotlinlang.org/
- artifact: com.squareup.okio:okio:+
  name: Okio
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: #LICENSE#
- artifact: com.android.support:support-annotations:+
  name: Android Support Library Annotations
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache Software License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: http://developer.android.com/tools/extras/support-library.html
- artifact: com.android.support:design:+
  name: Material Components for Android
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache Software License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: http://developer.android.com/tools/extras/support-library.html
- artifact: com.android.support:support-core-utils:+
  name: Android Support Library core utils
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache Software License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: http://developer.android.com/tools/extras/support-library.html
- artifact: com.android.support:interpolator:+
  name: Android Support Library Interpolators
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: The Apache Software License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: http://developer.android.com/tools/extras/support-library.html

# 以下、長いので省略
```

## ライセンス情報の編集

その後 `licenses.yaml` の情報を編集していきます。具体的には `#COPYRIGHT_HOLDER#` や `#LICENSE#` と言ったプレースホルダ部分を編集します。例えば

```yaml:licenses.yaml
- artifact: com.android.support:appcompat-v7:+
  name: Android AppCompat Library v7
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: #LICENSE#
- artifact: com.squareup.retrofit2:retrofit:+
  name: Retrofit
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: #LICENSE#
- artifact: io.reactivex.rxjava2:rxjava:+
  name: RxJava
  copyrightHolder: #COPYRIGHT_HOLDER#
  license: #LICENSE#
```

のような一覧が出力された場合は

```yaml:licenses.yaml
- artifact: com.android.support:appcompat-v7:+
  name: Android AppCompat Library v7
  copyrightHolder: The Android Open Source Project
  license: The Apache License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: https://developer.android.com/topic/libraries/support-library/
- artifact: com.squareup.retrofit2:retrofit:+
  name: Retrofit
  copyrightHolder: Square, Inc.
  license: The Apache License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: https://github.com/square/retrofit/
- artifact: io.reactivex.rxjava2:rxjava:+
  name: RxJava
  copyrightHolder: RxJava Contributors
  license: The Apache License, Version 2.0
  licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
  url: https://github.com/reactivex/rxjava/
```

となります。基本的にGitHubの情報を元に調べ編集していきます。Android Open Source Project(AOSP)は [ここ](https://source.android.com/setup/start/licenses) にライセンスに関する内容が記載されています。全ての情報の編集が終わったら、再度 `checkLicenses` タスクを実行し、エラーが発生しなければOKです。

## ライセンス情報の表示

最後に `Gradle > [project-name] > :app > Tasks > other` から、 `generateLicensePage` タスクを実行し、出力されたHTMLファイルをアプリ内の `WebView` に読み込ませます。

```kotlin:MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    webView.loadUrl("file:///android_asset/licenses.html")
}
```

![screen.gif](https://qiita-image-store.s3.amazonaws.com/0/302356/ddaa57da-f158-744a-33cc-281d06cc11fe.gif)

# :egg: ハマったこと

## checkLicensesタスクが失敗する

`checkLicenses` タスクを実行した際に `missing libraries in licenses.yml` というエラーで失敗してしまう。初回実行時には `licenses.yaml` が存在しないので、コンソールに表示されたライセンスの情報一覧をコピペして作成すればいいのですが、2回目以降であれば不足している情報がコンソールに出力されていますので、YAMLファイルに追記します。また、使用しているライブラリが、内部的に別のライブラリに依存している場合(例えば `appcompat-v7` は内部的に `support-annotations` や `support-compat` に依存している)、その関係性も監視対象になります。そういったライブラリは

```yaml:licenses.yaml
- artifact: com.android.support:appcompat-v7:+
  name: Android AppCompat Library v7
  copyrightHolder: The Android Open Source Project
  license: The Apache License, Version 2.0
- artifact: com.android.support:support-annotations:+
  skip: true
- artifact: com.android.support:support-compat:+
  skip: true
```

と記述することで、一覧から除外することができます。また、グループ一式で除外する場合は

```yaml:licenses.yaml
- artifact: com.android.support:+:+
  skip: true
```

の様にワイルドカードで指定したり、

```gradle:build.gradle[app]
licenseTools {
    ignoredGroups = ['com.android.support']
}
```

の様に記述することで可能となります。

## generateLicensePageタスクが失敗する

コンソールでエラーの内容を確認すると `checkLicenses` タスクでコケていることがほとんどかと思います。 [checkLicensesタスクが失敗する](#checklicensesタスクが失敗する) を参考に解決します。

## 必要な項目が不足している

`licenses.yaml` に必要な項目が不足している場合にも、プラグインのタスクが失敗します。必須項目は以下の通りです。

* artifact
* name
* copyrightHolder/ author/ authors/ noticeのうちどれか1つ

オプションとして付与できる項目は

* year
* skip
* forceGenerate

などがあります。詳しくは公式の [GitHubリポジトリ](https://github.com/cookpad/license-tools-plugin) を参照してください。

# :egg: 最終的な着地点

ここまでのハマった箇所を踏まえて、デモ用のアプリとしてGitHubに [demo-licenses](https://github.com/toranoko0518/demo-licenses) をアップしておきます。参考になるかわかりませんが、躓いていらっしゃる方の助けに少しでもなれたらなと思います。表示させないライセンスについてですが、最終的には `ignoredGroups` と `skip` を併用することで解決しました。 `ignoredGroups` は、名前の通り使用しているライブラリの `groupId` のみにしか対応しておらず `artifactId` では除外できませんでした。 `groupId` + `artifactId` でもプラグインの監視対象から除外できれば良いのになぁ。

# :egg: まとめ

結果的に調べたりなんなりで作業自体のコストはかかってしまいましたが、1から全て自前で実装するよりは遥かに良いです。今後、同様な実装が発生した場合にはこの記事を参考にスピーディに対応したいですね。また、先ほどの `groupId` + `artifactId` で除外するPull Requestなどを本家に出してみたいと思っています。ライセンスの表示は、Androidアプリを開発していく上で必要なことではありますが、開発が進むにつれて管理が億劫になったり、時間を割くことが難しいかもしれません。そんな痒いところに手が届くようなライブラリを開発してくださったクックパッド様には感謝しかないです :pray:

# :egg: どうでも良い話

ライセンスの綴りとして **license** と **licence** があります。大きな違いとして、イギリスでは動詞の場合に『license』名詞の場合に『licence』を使い分けますが、アメリカでは特に区別をせず日常的に『license』が使われるみたいです。結構タイプミスするので気をつけたいです。

# :egg: 参考文献

* クックパッド開発者ブログ: https://techlife.cookpad.com/entry/2016/04/28/183000
* GitHub: https://github.com/cookpad/license-tools-plugin