本当に把握してる？　アプリが使用しているライブラリとライセンスの調べ方

# TL;DR

* 外部ライブラリは`build.gradle`に書いたライブラリ以外にも存在することがある
* `dependencies`タスクを実行することで使用しているライブラリの一覧を調べることができる
* Mave Repositoryを見ればそのライブラリの情報がわかる
* ライブラリがApache License 2.0の場合、jarの中を覗いてNOTICEファイルの有無をチェックしないといけない

# はじめに

作成したアプリをGoogle Playで配布する場合、使用した外部ライブラリのライセンス条件には適切に従わなければなりません。
よって、アプリ開発者は自分のアプリがどんな外部ライブラリを使用しているかを把握しておく必要があります。

Androidでは外部ライブラリの導入にGradleを使うのが標準的なやり方です。
Gradleは、使いたい外部ライブラリが参照（依存）するライブラリも含めてローカル環境にダウンロードしてくれます。
Gradleが煩雑な作業を隠蔽してくれる反面、実は思いも寄らぬライブラリを使用していることがあります。

```build.gradle

//...

dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
}

//...

```

`appcompat-v7`はモダンなAndroidアプリを作るうえでほぼ必須のライブラリで、使用している方は多いと思います。
`appcompat-v7`を取り込むアプリは、同時に以下に挙げるライブラリも取り込んでいることをご存知でしたか？

* android.arch.core:common:1.1.1@jar
* android.arch.core:runtime-1.1.1
* android.arch.lifecycle:common:1.1.1@jar
* android.arch.lifecycle:livedata-1.1.1
* android.arch.lifecycle:livedata-core-1.1.1
* android.arch.lifecycle:runtime-1.1.1
* android.arch.lifecycle:viewmodel-1.1.1
* com.android.support:animated-vector-drawable-28.0.0
* com.android.support:asynclayoutinflater-28.0.0
* com.android.support:collections:28.0.0@jar
* com.android.support:coordinatorlayout-28.0.0
* com.android.support:cursoradapter-28.0.0
* com.android.support:customview-28.0.0
* com.android.support:documentfile-28.0.0
* com.android.support:drawerlayout-28.0.0
* com.android.support:interpolator-28.0.0
* com.android.support:loader-28.0.0
* com.android.support:localbroadcastmanager-28.0.0
* com.android.support:print-28.0.0
* com.android.support:slidingpanelayout-28.0.0
* com.android.support:support-annotations:28.0.0@jar
* com.android.support:support-compat-28.0.0
* com.android.support:support-core-ui-28.0.0
* com.android.support:support-core-utils-28.0.0
* com.android.support:support-fragment-28.0.0
* com.android.support:support-vector-drawable-28.0.0
* com.android.support:swiperefreshlayout-28.0.0
* com.android.support:versionedparcelable-28.0.0
* com.android.support:viewpager-28.0.0

`appcompat-v7`も含めて計30のライブラリです。
念を押しておきますが、これらのライブラリはユーザーが`implementation`を書いたわけではなく、**`appcompat-v7`を`implementation`する文を1行書いただけでくっついてくるライブラリです**。

本記事ではAndroidアプリ制作において、使用されている外部ライブラリをどのように調べればいいかを説明します。
また、Androidライブラリによく適用されているApache License 2.0の帰属告知の調べ方も合わせて説明します。

# 自分が使用しているライブラリを知る

今回は下記の依存関係を例に説明します。
Android Studioのプロジェクト作成ウィザードをデフォルト設定で進めた結果作成される依存関係にプラスして[Apache Commons Codec](https://commons.apache.org/proper/commons-codec/)を追加しています。

```build.gradle

//...

dependencies {
    // Android Studioが初期状態で追加済み
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    // 追加
    implementation 'commons-codec:commons-codec:1.11'
}

//...

```

さて、自分が使用しているライブラリを知る方法を説明します。

実はこれはGraldeタスクを1発実行するだけでわかってしまいます。
Gradleウィンドウから`androidDependencies`タスクを実行しましょう。

![pic1.jpg](https://qiita-image-store.s3.amazonaws.com/0/82681/4b29937f-dafe-6bc1-70a1-d1b4296139f8.jpeg)

すると、Runウィンドウにわらわらと結果が出てきたと思います。
その中の`releaseRuntimeClassPath`から始まるブロックを見てみましょう。

```androidDependencies実行結果.

...

releaseRuntimeClasspath - Dependencies for runtime/packaging
+--- com.android.support:appcompat-v7:28.0.0@aar
+--- com.android.support.constraint:constraint-layout:1.1.3@aar
+--- commons-codec:commons-codec:1.11@jar
+--- com.android.support:support-fragment:28.0.0@aar
+--- com.android.support:animated-vector-drawable:28.0.0@aar
+--- com.android.support:support-core-ui:28.0.0@aar
+--- com.android.support:support-core-utils:28.0.0@aar
+--- com.android.support:support-vector-drawable:28.0.0@aar
+--- com.android.support:loader:28.0.0@aar
+--- com.android.support:viewpager:28.0.0@aar
+--- com.android.support:coordinatorlayout:28.0.0@aar
+--- com.android.support:drawerlayout:28.0.0@aar
+--- com.android.support:slidingpanelayout:28.0.0@aar
+--- com.android.support:customview:28.0.0@aar
+--- com.android.support:swiperefreshlayout:28.0.0@aar
+--- com.android.support:asynclayoutinflater:28.0.0@aar
+--- com.android.support:support-compat:28.0.0@aar
+--- com.android.support:versionedparcelable:28.0.0@aar
+--- com.android.support:collections:28.0.0@jar
+--- com.android.support:cursoradapter:28.0.0@aar
+--- android.arch.lifecycle:runtime:1.1.1@aar
+--- com.android.support:documentfile:28.0.0@aar
+--- com.android.support:localbroadcastmanager:28.0.0@aar
+--- com.android.support:print:28.0.0@aar
+--- android.arch.lifecycle:viewmodel:1.1.1@aar
+--- android.arch.lifecycle:livedata:1.1.1@aar
+--- android.arch.lifecycle:livedata-core:1.1.1@aar
+--- android.arch.lifecycle:common:1.1.1@jar
+--- android.arch.core:runtime:1.1.1@aar
+--- android.arch.core:common:1.1.1@jar
+--- com.android.support:interpolator:28.0.0@aar
+--- com.android.support:support-annotations:28.0.0@jar
\--- com.android.support.constraint:constraint-layout-solver:1.1.3@jar

...

```

`androidDependencies`タスクは、アプリの依存関係を提示してくれるタスクです。
通常、releaseタスクの実行時クラスパスと実際に取り込んでいるライブラリは一致します。
したがって、アプリが使用しているライブラリの一覧を知るためには`releaseRuntimeClasspath`を見ればよい、ということになります。

なお、より詳細な依存関係が知りたい、という人は`dependencies`タスクを実行しましょう。

![pic2.jpg](https://qiita-image-store.s3.amazonaws.com/0/82681/85316a77-e72f-46a8-006e-1e5b31058d8c.jpeg)


```dependencies実行結果.

...

releaseCompileClasspath - Resolved configuration for compilation for variant: release
+--- com.android.support:appcompat-v7:28.0.0
|    +--- com.android.support:support-annotations:28.0.0
|    +--- com.android.support:support-compat:28.0.0
|    |    +--- com.android.support:support-annotations:28.0.0
|    |    +--- com.android.support:collections:28.0.0
|    |    |    \--- com.android.support:support-annotations:28.0.0
|    |    +--- android.arch.lifecycle:runtime:1.1.1
|    |    |    +--- android.arch.lifecycle:common:1.1.1
|    |    |    |    \--- com.android.support:support-annotations:26.1.0 -> 28.0.0
|    |    |    +--- android.arch.core:common:1.1.1
|    |    |    |    \--- com.android.support:support-annotations:26.1.0 -> 28.0.0
|    |    |    \--- com.android.support:support-annotations:26.1.0 -> 28.0.0
|    |    \--- com.android.support:versionedparcelable:28.0.0
|    |         +--- com.android.support:support-annotations:28.0.0
|    |         \--- com.android.support:collections:28.0.0 (*)
|    +--- com.android.support:collections:28.0.0 (*)
|    +--- com.android.support:cursoradapter:28.0.0
|    |    \--- com.android.support:support-annotations:28.0.0
|    +--- com.android.support:support-core-utils:28.0.0
|    |    +--- com.android.support:support-annotations:28.0.0
|    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    +--- com.android.support:documentfile:28.0.0
|    |    |    \--- com.android.support:support-annotations:28.0.0
|    |    +--- com.android.support:loader:28.0.0
|    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    +--- android.arch.lifecycle:livedata:1.1.1
|    |    |    |    +--- android.arch.core:runtime:1.1.1
|    |    |    |    |    +--- com.android.support:support-annotations:26.1.0 -> 28.0.0
|    |    |    |    |    \--- android.arch.core:common:1.1.1 (*)
|    |    |    |    +--- android.arch.lifecycle:livedata-core:1.1.1
|    |    |    |    |    +--- android.arch.lifecycle:common:1.1.1 (*)
|    |    |    |    |    +--- android.arch.core:common:1.1.1 (*)
|    |    |    |    |    \--- android.arch.core:runtime:1.1.1 (*)
|    |    |    |    \--- android.arch.core:common:1.1.1 (*)
|    |    |    \--- android.arch.lifecycle:viewmodel:1.1.1
|    |    |         \--- com.android.support:support-annotations:26.1.0 -> 28.0.0
|    |    +--- com.android.support:localbroadcastmanager:28.0.0
|    |    |    \--- com.android.support:support-annotations:28.0.0
|    |    \--- com.android.support:print:28.0.0
|    |         \--- com.android.support:support-annotations:28.0.0
|    +--- com.android.support:support-fragment:28.0.0
|    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    +--- com.android.support:support-core-ui:28.0.0
|    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    +--- com.android.support:support-core-utils:28.0.0 (*)
|    |    |    +--- com.android.support:customview:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    \--- com.android.support:support-compat:28.0.0 (*)
|    |    |    +--- com.android.support:viewpager:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    |    \--- com.android.support:customview:28.0.0 (*)
|    |    |    +--- com.android.support:coordinatorlayout:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    |    \--- com.android.support:customview:28.0.0 (*)
|    |    |    +--- com.android.support:drawerlayout:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    |    \--- com.android.support:customview:28.0.0 (*)
|    |    |    +--- com.android.support:slidingpanelayout:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    |    \--- com.android.support:customview:28.0.0 (*)
|    |    |    +--- com.android.support:interpolator:28.0.0
|    |    |    |    \--- com.android.support:support-annotations:28.0.0
|    |    |    +--- com.android.support:swiperefreshlayout:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    +--- com.android.support:support-compat:28.0.0 (*)
|    |    |    |    \--- com.android.support:interpolator:28.0.0 (*)
|    |    |    +--- com.android.support:asynclayoutinflater:28.0.0
|    |    |    |    +--- com.android.support:support-annotations:28.0.0
|    |    |    |    \--- com.android.support:support-compat:28.0.0 (*)
|    |    |    \--- com.android.support:cursoradapter:28.0.0 (*)
|    |    +--- com.android.support:support-core-utils:28.0.0 (*)
|    |    +--- com.android.support:support-annotations:28.0.0
|    |    +--- com.android.support:loader:28.0.0 (*)
|    |    \--- android.arch.lifecycle:viewmodel:1.1.1 (*)
|    +--- com.android.support:support-vector-drawable:28.0.0
|    |    +--- com.android.support:support-annotations:28.0.0
|    |    \--- com.android.support:support-compat:28.0.0 (*)
|    \--- com.android.support:animated-vector-drawable:28.0.0
|         +--- com.android.support:support-vector-drawable:28.0.0 (*)
|         \--- com.android.support:support-core-ui:28.0.0 (*)
+--- com.android.support.constraint:constraint-layout:1.1.3
|    \--- com.android.support.constraint:constraint-layout-solver:1.1.3
\--- commons-codec:commons-codec:1.11

...

```

`androidDependencies`は最終的に使用されるライブラリを箇条書き形式で教えてくれますが、`dependencies`は依存関係をツリー形式で教えてくれます。
あるライブラリが本当に必要かどうかを調査するときはこちらを使いましょう。

# 何のライブラリかを調べる

`androidDependencies`で一覧を出力してみると知らないライブラリがたくさん出てきます。
そのようなライブラリは[Maven Repository](https://mvnrepository.com/)で調べてみましょう。
例えば`android.arch.lifecycle:viewmodel`を調べてみると、[以下のページが出てきます](https://mvnrepository.com/artifact/android.arch.lifecycle/viewmodel)。

![pic3.jpg](https://qiita-image-store.s3.amazonaws.com/0/82681/7aa217d6-5d61-5843-022b-f57ffe116a2e.jpeg)

このページから、`android.arch.lifecycle:viewmodel`はどうやらAndroid Lifecycle ViewModelという名称のAndroidパッケージの一部で、Apache License 2.0で配布されていることがわかります。
よって、`android.arch.lifecycle:viewmodel`はApache License 2.0の頒布条件にしたがえばよいことがわかります。

# 実は自動でやってくれる

ここまで長々と説明しましたが、実は**以上の手順を自動的に出力してくれる（しかも物によってはライセンス表示のアクティビティまで作ってくれる）Android Studioプラグインは多数存在します**。
@tyoroさんの記事にまとまっていますのでそちらを参照してください。

[Androidアプリにライセンス表示を埋め込むライブラリいくつか](https://qiita.com/tyoro/items/f7045cea7cf5d98a80b9)


# おまけ：[Apache License 2.0]NOTICEファイルを知る

「自動でやってくれるんだったらもうやることないだろ？」と思われるかもしれません。
が、Apache License 2.0でライセンスされたライブラリを使うためにライセンス表示をする場合、自動化できない作業があります。
それは帰属の内容の告知です。

Apache License 2.0では、使用するライブラリが帰属を有している場合、ドキュメントにその内容を見えるところに表示しなければならいという条件があります。
この帰属の内容を含むファイルはNOTICEファイルなどと呼ばれます。

厄介なことにAndroid（Java）の世界ではNOTICEファイルはjarやaarの中に埋め込んで配布されるのが一般的です。また、NOTICEファイルはファイル名や書式に決まりはありません。
つまり、**使用するjarやaarがNOTICEファイルに相当するファイルを含んでいるか、1つ1つ見て回る作業が必要なのです**。

以下にAndroid Studioを使って効率的に（？）確認していく手順を説明します。

1. Projectウィンドウの`Android`と表示されているコンボボックスをクリックする
   ![image.png](https://qiita-image-store.s3.amazonaws.com/0/82681/5e335821-b3c8-af71-e7bc-0a53ce4dc627.png)
2. コンボボックスの一覧から`Project`を選び表示を切り替える
3. `External Libraries`から中身を見たいライブラリを選択する
   ![image.png](https://qiita-image-store.s3.amazonaws.com/0/82681/10f7cf11-ea71-24a3-6742-7ae6438d6a28.png)

Android Studioでは依存関係にあるライブラリがすべて見えるようになっているのですね。

さて、ここで先ほどのAndroid Lifecycle ViewModelにNOTICEファイルがあるか調べてみましょう。
`Gradle:android.arch.lifecycle:viewmodel-1.1.1`を掘り下げていくと……

![image.png](https://qiita-image-store.s3.amazonaws.com/0/82681/604974e0-9326-e6e9-8d66-16ce752c125a.png)

`META-INF`の中に`android.arch.lifecycle_viewmodel.version`という見慣れないファイルがありましたが、中身を覗いてみると、ファイル名どおり本当にバージョン情報だけしか記述されていません。
ほかにファイルもないので、どうやらAndroid Lifecycle ViewModelにはNOTICEファイルはなさそうです。

つぎに、ApacheのCommons-CodecにNOTICEファイルがあるか調べてみましょう。
`Gradle:commons-codec:commons-codec:1.11@jar`を掘り下げていくと……

![image.png](https://qiita-image-store.s3.amazonaws.com/0/82681/404b3416-c339-7cea-8ce3-51b1e89d1cb2.png)

`commons-codec-1.11.jar`の`META-INF`の中に`NOTICE.txt`があるのを見つけました。
`NOTICE.txt`を開いてみると確かに帰属の内容（クレジットの情報）が書いてありますね。
ライセンス表示にはこの記述を引用すればよさそうです。

今回はNOTICEファイルは`META-INF/NOTICE.txt`というパスで存在していましたが、ライブラリによっては全く異なるファイル名・ファイルパスに存在していることも珍しくありません。
根気よく探していきましょう。

# おわりに

ライセンス条件に従わないソフトウェアを頒布すると、最悪の場合著作者から訴えられ裁判に発展することもあります。
ライセンスされたソフトウェアは適切に取り扱いましょう。