Flutter - iOSアプリでライセンスplistを半自動で生成して設定画面に表示できるライブラリを作りました

# Dart, Flutterで車輪の再開発をしてみました
Swiftでは @mono0926 さんが作った [LicensePlist](https://github.com/mono0926/LicensePlist/) がありますが、Flutterを使ったiOSアプリでは同等のライブラリが存在しなかったので、Dartで作成してみました。

@mono0926 さんの該当記事はこちら

https://qiita.com/mono0926/items/973752b69c881e00c507#comment-3060a817c4ba199567b9

今回作成したライブラリの置き場所はこちらです。
今回はiOSのみの対応でAndroidは対応できてないです。今後対応する予定はありますが、いい感じの実装方法が思い浮かんでないので、誰か助言を...。

https://github.com/nomunomu0504/dart_license_plist

https://pub.dev/packages/dart_license_plist

---

動作結果としては、LicensePlistとほぼ同じになるように寄せました。
（このレイアウトが一番しっくり来てて他のレイアウトがしっくり来なかったので🥺）

iOSの設定画面から対象アプリを選択すると、「謝辞」セクションが表示されるようになるので、謝辞セクションから下記画面へ遷移することができるようになります。

| ライブラリのライセンス一覧 | 各ライブラリのライセンスページ |
|:-:|:-:|
| ![163102442-bb08d148-625e-439a-86c2-b3f433e11c2f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/ea1161b7-ee73-d782-bef6-6a3db4011abe.png) | ![163102488-b39bf74f-ea6f-4b2f-86ee-018996dbbb59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110131/64887b29-4dae-9a70-2ed0-3ac42b66d20c.png) |

# 使い方 / Usage
## dart_license_plistの有効化
dartコマンドを使って `dart_license_plist` を有効化します。
```
$ dart pub global activate dart_license_plist
Resolving dependencies...
...
Downloading dart_license_plist <latest_version>...
Building package executables...
Built dart_license_plist:dart_license_plist.
Activated dart_license_plist <latest_version>.
```

## Settings.bundleファイルの作成
※ すでにSettings.bundleが作成されている場合には、実行不要です。

ライセンス一覧生成前に、iOSでは設定画面に謝辞セクションを表示させるために必要な、`Settings.bundle` ファイルを作成します。このファイルはXcodeから作成する必要があります。

Flutterプロジェクトの`ios`フォルダにある`Runner.xcworkspace`を開き、`ios/Runner`フォルダにSettings.bundleを作成します。

**File** → **New** → **File...** → Select **Settings.bundle**

Settings.bundleを作成すると、bundle内に`Root.plist`というファイルが存在しますが、デフォルト状態だとテンプレートが記入されているので、以下のように書き換えておきます。

```xml:Root.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>StringsTable</key>
    <string>Root</string>
    <key>PreferenceSpecifiers</key>
    <array>
    </array>
  </dict>
</plist>
```

## ライセンスPlistの生成
`dart_license_plist`はFlutterプロジェクトのプロジェクト直下で実行します。
このコマンドを実行すると、上記で生成した`Settings.bundle`内にファイルを生成したりします。

設定画面に「謝辞」セクションを表示するために、`Root.plist`を編集する処理も含まれています。

```
$ dart pub global run dart_license_plist
```

実行するとプロジェクト直下にある`pubspec.lock`を元に使用しているライブラリを取得して、ライセンスデータを取得しに行きます。 `Generate Finished`が表示されたらplist生成の完了です。

取得に失敗したパッケージに関しては、最後にエラーとしてパッケージ名が一覧で表示されます。

```
[INFO] Fetching _fe_analyzer_shared data... (URL: https://pub.dev/packages/_fe_analyzer_shared)
[INFO] _fe_analyzer_shared's license url: https://pub.dev/packages/_fe_analyzer_shared/license
...
[INFO] Generating xdg_directories.plist...
[INFO] Generating xml.plist...
[INFO] Generating yaml.plist...
[INFO] Generate Finished.
```

実行後の`Settings.bundle`内の構成は以下のようになっているかと思います。
```
Settings.bundle
├── Root.plist
├── dev.nomunomu0504.dart_license_plist
│   ├── flutter.plist
│   ├── dio.plist
│   └── ...
└── dev.nomunomu0504.dart_license_plist.plist
```

Flutterアプリを再Buildして端末にインストールすると、設定画面から謝辞およびライセンスを確認することができます。

## 実行時のオプション
実行時のオプションとして指定できるのは、以下の項目になります。
| option | value | description |
|:-:|:-:|:-:|
| --version, -v   | - | dart_license_plistのversionを確認できます。<br>最新バージョンが存在した場合には、updateを行うこともできます。 |
| --verbose | - | デフォルトはINFO, ERRORのログのみですが、<br>verboseオプションを使うことで、DEBUGログも表示できるようになります。  |
| --custom-license-yaml=value  | yaml path (string) | plist生成時の設定および、カスタムライセンスの設定等を記述したyamlファイルのパスを指定できます。 |

### --custom-license-yamlオプション
custom-license-yamlで設定できる項目として、現状ではライセンス一覧に表示しないパッケージを指定できる`exclude`と、カスタムライブラリを設定できる`packages`の２つになります。

yamlファイルのテンプレートはこんな感じになります。
```yaml:custom_license.yaml
exclude:
  <fetch_exclude_package_name>:
  <fetch_exclude_package_name>:
  <fetch_exclude_package_name>:
  ...

packages:
  <custom_license_package_name>:
    license: |
      <custom_license_text>

  <custom_license_package_name>:
    license: |
      <custom_license_text>

  <custom_license_package_name>:
    license: |
      <custom_license_text>
```

設定ファイルが読み込まれている場合、コマンド実行時に読み込んでいるデータが表示されます。
```
$ dart pub global run dart_license_plist --custom-license-yaml=.custom_license.yaml
[INFO] -----
[INFO] Exclude package name list            ★★　excludeで設定されているパッケージ名一覧
[INFO] flutter_test
flutter_web_plugins
[INFO] -----
[INFO] Custom license package name list     ★★ pakcagesで設定されているカスタムライブラリ一覧
[INFO] flutter
[INFO] -----
[INFO] Fetching _fe_analyzer_shared data... (URL: https://pub.dev/packages/_fe_analyzer_shared)
...
```

excludeとpackagesに同じパッケージが設定されていると、エラーが表示されますので確認して修正してください。

#### exclude
excludeには、ライセンスデータのフェッチをスキップするパッケージ名を指定します。
```yaml:custom_license.yaml
exclude:
  flutter:
  flutter_web_plugins:
```

設定されているパッケージのライセンスデータを取得する際に、スキップされるようになります。
```
[INFO] flutter_test is setting exclude. Fetch Skipping...
[INFO] flutter_web_plugins is setting exclude. Fetch Skipping...
```

#### packages
packagesでは、パッケージとして使っていないがライセンスとして載せたい場合に設定すれば、ライセンス一覧に表示できるようになります。
flutterはpub.devにライセンス情報はなく、Githubのライセンスを掲載する必要があります。
※ 本当はここらへんも自動でできるようになればいいんですが、実装できていません🙇‍♂

ここで設定されているライセンス情報は、pub.devとかから取得したライセンス情報よりも優先して利用されます。
```yaml:custom_license.yaml
packages:
  flutter:
    license: |
      Copyright 2014 The Flutter Authors. All rights reserved.

      Redistribution and use in source and binary forms, with or without modification,
      are permitted provided that the following conditions are met:

          * Redistributions of source code must retain the above copyright
            notice, this list of conditions and the following disclaimer.
          * Redistributions in binary form must reproduce the above
            copyright notice, this list of conditions and the following
            disclaimer in the documentation and/or other materials provided
            with the distribution.
          * Neither the name of Google Inc. nor the names of its
            contributors may be used to endorse or promote products derived
            from this software without specific prior written permission.

      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
      ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
      ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

```