モチベーション
React Nativeを利用した開発で利用しているライブラリをAndroid, iOSごとにjson形式でまとめて、React NativeのViewから表示させたい。この仕組みを、できるところは自動化をさせたい。その手順や躓きポイントをまとめた。
この記事について
Unipos Advent Calendar 2022の2日目の記事です。
用意するもの
ライセンス出力で利用
※LicenseToolsPluginはアーカイブされているため、現在だとAboutLibrariesを利用する方がよさそう。
自動化で利用
- Node.js
- Ruby
- sed
- jq
- plutil
- echo
- macOS
手順
CLIでreact-native-oss-license
を動かしただけでは、ラインセンスを独自の形式でアプリに表示するまでの道のりが大きく、躓きそうなポイントがいくつかある。自分なりに、できるだけどうすると自動化できそうかを手順としてまとめた。
Android, iOSでそれぞれ手順が異なる。以下に、大まかな手順を記す。
Android
- JS側からライセンス情報をyaml形式で出力
- 1.で出力したyamlから、ライセンス情報を出力したyaml形式に則った形式で、
#LICENSE#
や#COPYRIGHT_HOLDER
など抜けているところをググって埋めた状態のyamlを作成しておく - 1.2.のyamlを合体させたyamlを作成する (
JS.yaml
とする) - Android側からライセンス情報をyaml形式で出力
- 4.で出力したyamlから、ライセンス情報を出力したyaml形式に則った形式で、
#LICENSE#
や#COPYRIGHT_HOLDER
など抜けているところをググって埋めた状態のyamlを作成しておく - 4.5.のyamlを合体させたyamlを作成する (
Android.yaml
とする) - JS.yamlとAndroid.yamlを合体させる (
JS&Android.yaml
とする) -
LicenseToolsPlugin
のコマンドでライセンス情報が正しく入力できている確認する -
JS&Android.yaml
からjsonに変換する (android.json
とする) -
android.json
をjsxで読み込み、FlatList
に表示する。
iOS
- JS側からライセンス情報をplist形式で出力
- 1.で出力したplistから、ライセンス情報を出力したyaml形式に則った形式で、
#LICENSE#
や#COPYRIGHT_HOLDER
など抜けているところをググって埋めた状態のyamlを作成しておく - 2.3.のplistを合体させる (
JS.plist
とする) - iOS側からライセンス情報をyaml形式で出力 (
iOS.plist
とする) -
JS.plist
をjsonにする (JS.json
とする) -
iOS.plist
をjsonにする (iOS.json
とする) -
JS.json
とiOS.json
を合体させる (ios.json
とする) -
ios.json
をjsx
で読み込み、FlatList
に表示する
手順の自動化で詰まりそうなポイント
上記の手順を実際に行うにはそれなりの労力が必要になる。自動化できる部分は自動化させたい。react-native-oss-license
にはどうすればライセンスを出力できるのかがまとまっている。ただ、それだけだと自動化するときに難しいところもある。そのため、自動化するときに、自分が躓いてしまったポイントをまとめた。
#LICENSE#
や#COPYRIGHT_HOLDER
など抜けているところ埋めるって辛くない?
これは大変じゃないかと思うが、実際大変。ライブラリによってはライセンスがあるものの、サーバーからダウンロードしてきたファイルの中にライセンスの記入が含まれていないものが数多く存在する。そのようなライブラリの#LICENSE#
や#COPYRIGHT_HOLDER
の項目を1つ1つググって埋めていくという手作業が必要になる。これはどうしようもないように思っている。
ライブラリの更新時にできるだけ再度同じ調査をしたくないので、初回、調べた内容を、CLIで出力されたyaml形式と同じ形で記入する。
下記のようなフォーマットでライセンスは出力される。
- artifact: example:+
copyrightHolder: #COPYRIGHT_HOLDER
license: #LICENSE#
licenseUrl: https://example.com
url: https://example.com
下記のように変更した状態のyamlを作成しておく。
- artifact: example:+
copyrightHolder: example
license: example
licenseUrl: https://example.com
url: https://example.com
次回以降は、この埋めた状態のyamlを、ライセンス出力のyamlと合成することで、もう一度ググるという必要がだいぶ減る。
LicenseToolsPlugin
の未対応のライセンスが存在する
ライセンスも日夜、新しいものが登場する。そのようなライセンスを持つライブラリを利用すると、LicenseToolsPlugin
ではエラーになる。
例えば下記のように表示されることがある。
* What went wrong:
Execution failed for task ':app:generateLicensePage'.
> java.io.FileNotFoundException: File not found: template/licenses/Unlicense.html
Unlicenseというライセンス形態を利用できないと表示される(意訳)。
作成したyamlが正しいかどうかを確認するために、generateLicensePage
を実行しているとする。この場合は、このライセンスを持つライブラリの部分をgenerateLicensePage
の実行時のみコメントアウトすることで対処できる。そして、generateLicensePage
が終わり次第、コメントアウトした部分をアンコメントする。
(※LicenseToolsPluginをforkしてUnlicenseにも対応させれば......)
コメントアウトには、JSからsed
コマンドを利用した。
`sed -i '' -e '/${artifact名}/,+${artifact名からそのライブラリの部分を示す行数}s/^/#/' ${yamlファイルのパス}`
アンコメントにも、JSからsed
コマンドを利用した。
`sed -i '' -e '/${artifact名}/,+${artifact名からそのライブラリの部分を示す行数}s/#//' ${yamlファイルのパス}`
yamlをjsonにするには?
jsxでライブラリのライセンスを表示させたかったのでyamlをjsonにしたい。そのため、JS側からruby
とjq
を利用して、yamlからjsonに変換した。最終的に作成されるjsonにfomatをかける意味でjqを利用していた。下記コマンドを実行した後に、writeFile
でコマンドの中身を書き込み、jsonファイルを作成した。
`ruby -rjson -ryaml -e 'print YAML.load(STDIN.read).to_json' < ${yamlファイルのパス} | jq .`
./gradlew checkLicenses
の実行結果に余計な文章も混じる
./gradlew checkLicenses
を実行すると、Android側のライセンス情報をyaml形式でshellに出力してくれる。だが、コマンドのログには、yaml以外の部分も存在していて、そのままだと取り扱いづらい。
書きのように出力される。
何らかの文字列がたくさん
何らかの文字列がたくさん
- artifact: example:+
copyrightHolder: example
license: example
licenseUrl: https://example.com
url: https://example.com
何らかの文字列がたくさん
何らかの文字列がたくさん
そこで、JS側でsedを使って、yaml形式の部分だけを抜き取った。
`echo -e "${./gradlew checkLicensesの結果}" | sed -n -E -e '/- .*:.*| .*:.*/p'`
- .*:.*
にて、- artifact: example:+
部分を抜き出し、 .*:.*
部分で、 copyrightHolder: example
のような部分を抜き出した。
試したこととして、js-yamlを利用した。結果として、yaml記法に則っていない部分があると、js-yaml
ではエラーになってしまうようで、代理でsedコマンドを利用するように変更した。
plistからjsonにどうやって変換するの?
macOSにはplutilというコマンドが同梱されているようだったので、このコマンドをJS側から利用することにした。
`plutil -convert json ${plistファイルのパス} -o -`
JSXでjsonって読み込めるの?
普通に読み込めるみたい。そのままimportすると利用できるようだった。
import {License} from 'license.json';
TypeScriptとTSXを利用している場合は、型定義をしておくことで、importしたときに型がついた状態で、TSX上で操作できる。
declare module '*/license.json' {
export type License = {
artifact: string;
省略
};
const Licenses: License[];
export default Licenses;
}
まとめ
React Nativeを利用した開発で、ライブラリのライセンスをjsonとしてまとめて、JSXで表示するまでのざっくり手順をまとめた。その際に躓きそうな手順もまとめた。OTA (Over The Air) を利用していた都合上、Android側やiOS側のネイティブコードに変更がないようにしたかったので、jsonにまとめるという方式を取った。しかし、実際、大変だった。
LicenseToolsPlugin
はアーカイブになったため、AboutLibraries
に置きかえる作業をしなければ......
最後に、ライブラリの作成者様方に感謝を。react-native-oss-license
やLicenseToolsPlugin
、LicensePlist
などがなければ、もっと膨大な作業が発生したと思う。ありがとうございました。