最初に断っておきますが、僕自身はOSSのライセンスを理解しようとし、尊重していますが、ライセンスそのものの詳細に詳しいわけではないのでもしかしたら間違っていることがあるかもしれません。その際は優しく指摘してください。優しくね。
昨今、アプリケーションを開発するにはWebであれモバイルであれ、オープンソース(OSS)のライブラリを利用することが多いかと思います。
その際に問題になってくるのが各ライブラリのライセンス表記でして、多くの場合はそのライブラリを利用して開発したものに関して著作権表記等を求められるライセンスで配布されていることが多いと思います。比較的制限のゆるいとされているMITライセンスなんかもそうですね。
WebなんかだとJSのソース見れるのでどこかに記載されていれば問題ないのかと思います。一方でiOSやAndroidといったいわゆるネイティブアプリというのはそうはいかないよねってことでライセンス一覧のページなりをアプリ内で表示できるように用意していることが多いです。
というわけで、用意していこうと思うのですが一から自分で調べて用意するのも大変です。iOSとかAndroid向けのツールはいろいろとあるのですが自分の環境はReact Nativeです。なので今回はReact Nativeで同じようなことができるツールを探して試してみます。
候補
npmで入れているものをチェックして何らかの方法で出力してくれるものがいいな、ということでreact native oss license generator
とかで検索してみると思った以上に少ない。
とりあえず出てきたのはこの3種類くらい。
react-native-oss-license - npm
license-checkerが一番ダウンロード数が多いみたいだけど、最終更新が2年前とちょっと古い。次にダウンロード数が多いのはnpm-license-crawlerでこれも最後に更新されたのが2年前。react-native-oss-licenseはダウンロード数は一番少ないのだけれども最後の更新は4ヶ月前。
なお、react-native-oss-licenseについては作者のページがQiitaにあった。
React Native用のOSSライセンス表記生成ツールを作った - Qiita
さて、どれにするか悩ましいけどダウンロード数が一番多いやつか、更新が新しいものかのどちらかにすることにしよう。というわけでlicense-checkerかreact-native-oss-licenseを比較。
license-checker
- 2021年6月29日時点での週間ダウンロード数は233,388
- node_modulesをなめてすべてのpackage.jsonをチェック、SPDX形式のライセンスが含まれてればそれを使い、なければ
LICENSE
,LICENCE
,COPYING
,README
といったファイルを見る - ファイルを直接生成するのではなくJSONファイルを生成
- したがってそれを読み込んで表示する画面を用意する必要がある
react-native-oss-license
- 2021年6月29日時点での週間ダウンロード数は790
- package.jsonから利用しているパッケージの情報を取得し、node_modules以下からLICENSEファイルを取得
- iOSはsettings-bundle形式、Androidはlicense-tools-plugin形式もしくはabout-libraries形式で出力することが可能。自分でマージする必要あり
- JSON出力も可能
どちらにするか
今のところネイティブなライブラリは使っていないのでiOS、Androidでの出力は不要なので個々の形式に合わせて出力するのではなく、JSONで出力して両プラットフォーム向けの画面を用意することにします。
そうするとどちらもJSON出力可能なので、長いものに巻かれようってことで使われている数が多いliense-checkerを使うことにします。
早速やってみる
ますはインストール。
yarn global add license-checker
実行します。
license-checker --production --json --out ./licenses.json
--production
でdev dependenciesは取り除きます。実はCSV形式でも出力できるのですが--json
でJSON形式を指定します。そして--out
で出力先のファイルを指定します。ここではカレントディレクトリにlinceses.json
というファイル名で保存します。
こんな感じで出力されました。
{ "@babel/code-frame@7.10.4": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@expo/json-file/node_modules/@babel/code-frame", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@expo/json-file/node_modules/@babel/code-frame/LICENSE" }, "@babel/code-frame@7.12.11": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/eslint/node_modules/@babel/code-frame", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/eslint/node_modules/@babel/code-frame/LICENSE" }, "@babel/code-frame@7.12.13": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/code-frame", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/code-frame/LICENSE" }, "@babel/compat-data@7.14.0": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "The Babel Team", "url": "https://babel.dev/team", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/compat-data", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/compat-data/LICENSE" }, 以下略
インストールされている異なるライブラリがそれぞれ依存している同じライブラリであってもそれぞれ別のバージョンに依存していると各バージョンが出力されてしまい、エグい量になるのでオプションとして--direct
をつけて再実行してみます。
{ "@babel/code-frame@7.12.13": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/code-frame", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/code-frame/LICENSE" }, "@babel/compat-data@7.14.0": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "The Babel Team", "url": "https://babel.dev/team", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/compat-data", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/compat-data/LICENSE" }, "@babel/core@7.14.0": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/core", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/core/LICENSE" }, "@babel/generator@7.14.1": { "licenses": "MIT", "repository": "https://github.com/babel/babel", "publisher": "Sebastian McKenzie", "email": "sebmck@gmail.com", "path": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/generator", "licenseFile": "/workspaces/xxxxxxxxxxxx/node_modules/@babel/generator/LICENSE" }, 以下略
うーん、それでも結構な量になるな。7000行超えてる。
ていうかこれbabelとかがdependenciesに含まれてるからか。でもpackage.jsonではdev dependenciesに指定してるんだけどな。 確認したら--production
が効いてないのかな?--production
がちゃんと有効になった状態でこれだった。
え、一般的にこんなに多いのかな。。。
と思いつつもまずはこのJSONを読み込んで表示する画面を先に作ることにする。
なお、表示にあたってライセンスの中身も出力したかったのでフォーマット指定を行うことにした。以下のようなファイルを用意する。名前はなんでもいいがcustomFormat.json
とした。
{ "name": "", "version": "", "description": "", "licenses": "", "copyright": "", "licenseText": "" }
このフォーマットを指定してコマンドを実行する。
license-checker --production --direct --customPath ./src/customFormat.json --json --out ./src/licenses.json
ライセンス情報のJSONを読み込んで表示する
ぶっちゃけここは好きに作ればいい。ここではひとまず1枚の画面にベタっと表示するようにした。
import { Container } from 'native-base' import licenseFile from '../../licenses.json' import { Text } from 'native-base' import { StyledScrollView, StyledView, NameText } from './styled' export const LicenseScreen: React.FC = () => { const licenseKeys = Object.keys(licenseFile) return ( <Container> <StyledScrollView> {licenseKeys.map((value) => { const license = licenseFile[value].licenses const publisher = licenseFile[value].publisher const licenseText = licenseFile[value].licenseText const copyright = licenseFile[value].copyright return ( <StyledView> <NameText> {value} published by {publisher} </NameText> <Text>{licenseText}</Text> <Text>{copyright}</Text> </StyledView> ) })} </StyledScrollView> </Container> ) } export default LicenseScreen
styleは別にstyled.ts
として以下のように用意している。
import styled from 'styled-components/native' export const StyledScrollView = styled.ScrollView.attrs(() => ({ contentContainerStyle: { alignItems: 'center', justifyContent: 'center', }, }))`` export const StyledView = styled.View` margin-top: 10px; ` export const NameText = styled.Text` font-size: 20px; font-weight: bold; `
というわけでこんな感じでできあがったけど、なんかダサいし重いのでもうちょっと考えよう。。。