【Flutter】パッケージ/ライブラリ/プラグインの違いをわかりやすく解説

Flutter

こんにちは、教育系エンジニアのひらまつ(@hiramatsuu)です。

ひらまつの簡単な自己紹介

書籍「ゼロからわかる Linuxコマンド200本ノック(技術評論社)」の著者。Udemy受講者8万人。
プログラミング教育をメインに活動するエンジニアとして、動画教材の作成・技術書の執筆・学習アプリの開発などを行なっています(詳しくはこちら)。

本記事では、Flutter開発における用語、パッケージ・ライブラリ・プラグインについて解説します。

これらの用語は、違いがわかりづらく、混同しやすいので、本記事を読んで、正確に理解できるようになりましょう。

簡単なまとめ

  • ライブラリ(library)は、Dartファイルのこと。基本的には、1つのDartファイルが、1つのライブラリになるが、2つ以上のDartファイルが1つのライブラリになることもある。
  • パッケージ(package)は、ライブラリを他者に共有するために使われる配布形式。パッケージのlibディレクトリ内に、ライブラリが格納されている。
  • プラグイン(plugin)は、パッケージの一種で、プラットフォーム固有の機能を使うことができるもの。プラグインの中には、KotlinやSwiftなど、プラットフォーム固有の機能にアクセスするための、コードが含まれる。

ライブラリ(library)とは

ライブラリ(library)は、Dartファイルのこと。基本的には、1つのDartファイルが、1つのライブラリになるが、2つ以上のDartファイルが1つのライブラリになることもある。

ライブラリのスコープ

ライブラリは、コンパイルの単位で、ライブラリごとにプライベートなスコープを持つ。そのため、importせずに、ライブラリの外から、機能にアクセスすることはできない。

例えば、lib1.dartとlib2.dartという、2つのライブラリがあるとする。以下のように、lib2.dartで、lib1.dartの機能を使おうとしても、エラーになる。

lib1.dart

void hoge() {
  print("Hello!");
}

lib2.dart

void foo() {
  hoge(); // lib1.dartの関数なのでエラーになる
}

別のライブラリの機能を使うには、import(もしくはexport)が必要。上記2つのファイルが、同じディレクトリにある場合、相対パスで次のようにimportする。

lib2.dart

import 'lib1.dart';

void foo() {
  hoge(); // importしているので、lib1.dartの関数が使える
}

複数ファイルを1つのライブラリにする(非推奨)

基本的には、1つのDartファイルが、1つのライブラリになるが、「part」「part of」ディレクティブを使うことで、複数のDartファイルを1つのライブラリとして扱うこともできる

例えば、以下のようにすると、lib1.dartとlib2.dartを1つのライブラリにすることができる。

lib1.dart

// lib2.dartがこのライブラリの一部であることを宣言
part 'lib2.dart';

void hoge() {
  print("Hello!");
}

lib2.dart

// このファイルがlib1.dartの一部であることを宣言
part of 'lib1.dart';

void foo() {
  hoge(); // 同一ライブラリなので、importせずにhoge()を使用可能
}

ただし、partとpart ofは、すでに非推奨になっていることに注意。複数ファイルを同一のライブラリにするのではなく、importやexportを使って、別のライブラリの機能にアクセスすることが推奨されている

ライブラリの配布方法

ライブラリは、基本的にはパッケージという形式で配布されるが、Dart SDKに含まれているライブラリもある。Dart SDKの中に含まれるライブラリを、Dart’s core librariesといい、dart:coredart:asyncなどがある。Dart’s core librariesは、明示的にimportせずとも使用することができる

例えば、print()は、dart:coreに含まれる関数。

lib1.dart

void hoge() {
  print("Hello!"); // dart:coreライブラリの機能なので、import不要で使える
}

パッケージ(package)とは

パッケージ(package)とは、ライブラリなどを、他者に共有するための配布形式1パッケージによって共有されるのは、ライブラリだけではなく、コマンドラインツールなども含まれる。

パッケージのディレクトリ構成

パッケージの実体は、1つのディレクトリであり、すべてのパッケージは、pubspec.yamlファイルをルートに持つ。pubspec.yamlについて、より詳しくはこちらの記事を参照。

パッケージのディレクトリ内には、pubspec.yamlの他に、ライブラリを格納するlibディレクトリや、公開するコマンドラインツールを格納するbinディレクトリなどがある。パッケージのディレクトリ構成について、より詳しくはこちらの記事を参照。

パッケージの、libディレクトリの直下に入っているのが、ユーザーにAPIが公開されるライブラリ。APIが公開されない、実装を担うライブラリは、lib/srcディレクトリに入れる慣例がある。

メインライブラリ(main library)とミニライブラリ(mini library)

パッケージのlibディレクトリ直下には、パッケージ名と同名のDartファイルがある(fooパッケージなら、lib/foo.dartファイルを持つ)。このライブラリは、メインライブラリ(main library)と呼ばれることもある。

多くのメインライブラリでは、lib/src内にある、実装を担うライブラリを、exportしている。exportディレクティブは、指定したライブラリのAPIを公開して、exportディレクティブが書かれたファイルをimportするだけで、exportしたライブラリのAPIすべてを使えるようにするための機能

例えば、実在するshelfパッケージのメインライブラリ(lib/shelf.dart)は、次のような実装になっている。

lib/shelf.dart

export 'src/cascade.dart' show Cascade;
export 'src/handler.dart' show Handler;
export 'src/hijack_exception.dart' show HijackException;
export 'src/middleware.dart' show Middleware, createMiddleware;
export 'src/middleware/add_chunked_encoding.dart' show addChunkedEncoding;
export 'src/middleware/logger.dart' show logRequests;
export 'src/middleware_extensions.dart' show MiddlewareExtensions;
export 'src/pipeline.dart' show Pipeline;
export 'src/request.dart' show Request;
export 'src/response.dart' show Response;
export 'src/server.dart' show Server;
export 'src/server_handler.dart' show ServerHandler;

exportに加えて「show クラス名/関数名」とすることで、ライブラリに含まれるすべてのAPIを公開する代わりに、ここで指定したAPIだけを公開することができる。なので「export ‘src/cascade.dart’ show Cascade;」では、「cascade.dartのうち、CascadeクラスのみのAPIを公開する」という意味になる。

このようにすることで、shelfパッケージのユーザーは、

import 'package:shelf/shelf.dart';

というように、shelf.dartをimportするだけで、shalfパッケージのlib/srcディレクトリに入っている、ライブラリの機能もを使えるようになる

このように、実装を担うライブラリを、メインライブラリ内でexportすることによって、ユーザーはメインライブラリだけをimportするだけで、パッケージの多くの機能を使えるようになる

ライブラリは、それぞれを小さく作る方が、保守しやすい。そのため、1つの大きなライブラリを作るのではなく、exportやimportを使って、複数の小さなライブラリ(mini libraries)を作ることが、推奨されている。

プラグイン(plugin)とは

プラグイン(plugin)は、パッケージの一種で、プラットフォーム固有の機能を使うことができるもの。正式名称は「プラグインパッケージ」だが、「プラグイン」と基本的に呼ばれる。

プラグインの中には、KotlinやSwiftなど、プラットフォーム固有の機能にアクセスするための、コードが含まれる。例えば、デバイスのカメラを使うには、cameraプラグインが必要。

プラグインを新たに利用するためには、Hot ReloadやHot Restartではなく、Full Restartする必要がある。これは、Hot ReloadとHot Restartは、Dartコードのアップデートしかしないため。

補足

libraryディレクティブ

libraryディレクティブは、ライブラリレベルのdoc commentsやmetadata annotationを指定する用途で使う2

例えば、asyncパッケージのlib/async.dartの上部には、次のようなdoc commentsの記述がある。

lib/async.dart

/// Utilities that expand on the asynchronous features of the `dart:async`
/// library.
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=r0tHiCjW2w0}
library async;

また、libraryディレクティブの有無によらず、あらゆるDartファイルはライブラリであることに注意。ライブラリレベルのdoc commentsを記載しないなら、libraryディレクティブは不要。

アプリケーションパッケージ

パッケージの種類の一つとして、アプリケーションパッケージもある。

アプリケーションパッケージ(application package)とは、Flutterアプリのような、他のパッケージから依存されないパッケージのこと。アプリケーションパッケージは、エンドユーザーから直接利用される。

アプリケーションパッケージのlockfileは、バージョン管理が必要。より詳しくはこちらの記事を参照。

その他の情報

Flutter開発についての、他の記事はこちらを参照。

Flutter
「Flutter」の記事一覧です。

参考文献

Glossary of package terms
A glossary of terms relating to Dart's package management tool, pub.
Using packages
How to use packages in your Flutter app.
Effective Dart: Usage
Guidelines for using language features to write maintainable code.

脚注

  1. https://dart.dev/guides/libraries/create-packages ↩︎
  2. https://dart.dev/language/libraries#library-directive ↩︎
タイトルとURLをコピーしました