0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Flutter】 Flutter Pigeon 完全入門 ─ 型安全なFlutter↔ネイティブ通信とその進化の歴史

Posted at

🕊️ はじめに:なぜPigeonが必要なのか?

「手書きのMethodChannel時代に終止符を打つ」
PigeonはFlutter通信を“宣言的”に再定義した、公式のIDL(Interface Definition Language)ツールだ。

Flutterでネイティブ機能を呼び出すには、通常 MethodChannel を使用します。
しかし、プロジェクトが大きくなるにつれ次のような問題が浮き彫りになります:

問題点 説明
メソッド名が文字列管理 タイポしてもコンパイルで検出できない
型が不一致 Dart ↔ Kotlin ↔ Swift 間で型ミスしても実行時エラー
3言語で同じ定義を手動維持 コード量と保守コストが爆増
テストが困難 仕様の「契約」が明示されない

この課題を解決するために、Flutterチームが設計したのが Pigeon(ピジョン) です。
Dartで一度インターフェースを書けば、Kotlin・Swiftのコードを自動生成できます。


Pigeonとは?

Pigeonは、Flutterアプリとネイティブコード間の通信を型安全に自動生成するツールです。

  • IDL(Interface Definition Language) 形式で通信契約を記述
  • Dart / Kotlin / Swift のコードを自動生成
  • ランタイム依存なし(すべてコンパイル時解決)
  • MethodChannelを内部で安全にラップ

1. セットアップ

pubspec.yamldev_dependencies に追加します。

dev_dependencies:
  pigeon: ^26.0.1

2. 通信定義を作る(IDL)

pigeons/battery.dart

import 'package:pigeon/pigeon.dart';

class BatteryInfo {
  int? level;
}

@HostApi() // Dart → ネイティブ
abstract class BatteryApi {
  BatteryInfo getBatteryLevel();
}

Dartで定義するだけ。これがすべてのプラットフォームの“契約書”になる。


3. コード生成

dart run pigeon \
  --input pigeons/battery.dart \
  --dart_out lib/pigeon/battery.g.dart \
  --kotlin_out android/src/main/kotlin/com/example/system_battery_info/Battery.kt \
  --kotlin_package com.example.system_battery_info \
  --swift_out ios/Classes/Battery.swift

4. 各プラットフォーム実装

Android(Kotlin)

class BatteryApiImpl(private val context: Context): BatteryApi {
    override fun getBatteryLevel(): BatteryInfo {
        val iFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
        val batteryStatus = context.registerReceiver(null, iFilter)
        val level = batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
        val scale = batteryStatus?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
        return BatteryInfo().apply { this.level = (level * 100) / scale }
    }
}

class SystemBatteryInfoPlugin : FlutterPlugin {
    override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        BatteryApi.setUp(binding.binaryMessenger, BatteryApiImpl(binding.applicationContext))
    }
    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        BatteryApi.setUp(binding.binaryMessenger, null)
    }
}

iOS(Swift)

public class BatteryApiImpl: BatteryApi {
    public func getBatteryLevel() throws -> BatteryInfo {
        UIDevice.current.isBatteryMonitoringEnabled = true
        let info = BatteryInfo()
        info.level = NSNumber(value: Int(UIDevice.current.batteryLevel * 100))
        return info
    }
}

public class SystemBatteryInfoPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    BatteryApiSetup.setUp(binaryMessenger: registrar.messenger(), api: BatteryApiImpl())
  }
}

Dart側で呼び出す

import 'pigeon/battery.g.dart';

final api = BatteryApi();

Future<void> main() async {
  final info = await api.getBatteryLevel();
  print('Battery level: ${info.level}%');
}

もうinvokeMethod()try/catchも不要。
型安全なAPIとして補完される。


双方向通信(@FlutterApi

Flutter側にイベントを返すことも可能です。

@FlutterApi()
abstract class BatteryListener {
  void onBatteryChanged(BatteryInfo info);
}

ネイティブから:

val listener = BatteryListener(binaryMessenger)
listener.onBatteryChanged(BatteryInfo().apply { level = 90 })

Pigeonのメリットまとめ

特徴 内容
型安全 Dart/Kotlin/Swift 間の型一致を保証
保守性 定義を1箇所に集約
パフォーマンス MethodChannelより高速(バイナリCodec使用)
双方向通信 @HostApi + @FlutterApi で可能
自動生成 すべての橋渡しコードをツールが生成
Null-safety完全対応 Dart 3.0以降のNull安全仕様と整合

Pigeonの歴史と進化

バージョン 進化
2018 Flutter初期 手書きMethodChannel時代
2020 v0.1 Pigeon登場(Dart→Native)
2021 v1.x @FlutterApi登場、双方向通信対応
2022 v3.x Null-safety / Enum / Nestedクラス対応
2023 v7.x Swift5/Kotlin1.8サポート
2024 v10+ Federated構成・@ConfigurePigeon対応
2025 現在 Desktop/Linux対応、CI統合容易化

名前の由来は “信鸽(pigeon)”。
「Flutter ↔ Native のメッセージを安全に届ける使者」という意味。


Pigeonの設計哲学

“コードを手で書くより、契約を定義するべき。”

Flutter開発が拡大するにつれ、手作業の通信コードはバグの温床になりました。
Pigeonは「宣言」だけで通信を完結させ、人間の手から橋梁ロジックを解放しました。

設計の三原則

  1. IDLで定義、コードは自動生成
  2. コンパイル時型チェック
  3. 実行時に文字列を使わない(ゼロ反射)

現在の活用例

  • Flutter公式プラグイン(camera, shared_preferences, connectivity_plus
  • Firebase、Agora、MapboxなどのSDK
  • 企業社内の業務アプリ(契約定義書として利用)

未来展望

Flutterチームが提案している次世代Pigeonは:

方向 説明
gRPC風IDL化 将来的にはprotobufのようにschemaベース通信へ
FFI統合 C/Rustバインディングとの統一生成
Web/Desktop対応 Pigeonで完全クロスプラットフォーム通信を実現
build_runner連携 コマンド不要の自動生成パイプライン化

通信構造図(Mermaid)


テストTips

class MockBatteryApi implements BatteryApi {
  @override
  Future<BatteryInfo> getBatteryLevel() async {
    return BatteryInfo()..level = 99;
  }
}
test('mocked battery api', () async {
  final mock = MockBatteryApi();
  final info = await mock.getBatteryLevel();
  expect(info.level, 99);
});

まとめ

Flutter開発は「文字列通信」から「契約通信」へ。
Pigeonはその変化の象徴だ。

たった1つのDart定義で、3言語が同じ約束を守る。
その時あなたのFlutterアプリは、真の多言語協調に到達する。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?