Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier and faster.
Currently Pigeon supports generating:
Pigeon generates all the code that is needed to communicate between Flutter and the host platform, there is no extra runtime requirement. A plugin author doesn't need to worry about conflicting versions of Pigeon.
dev_dependency
.flutter pub get
then flutter pub run pigeon
with suitable arguments (see example)../lib
for compilation.ios/Runner.xcworkspace
or .podspec
)../android/app/src/main/java
directory for compilation../windows
directory for compilation, and to your windows/CMakeLists.txt
file.macos/Runner.xcworkspace
or .podspec
).Flutter also supports calling in the opposite direction. The steps are similar but reversed. For more information look at the annotation @FlutterApi()
which denotes APIs that live in Flutter but are invoked from the host platform.
abstract class
with either HostApi()
or FlutterApi()
as metadata. The former being for procedures that are defined on the host platform and the latter for procedures that are defined in Dart.void
.List<int?>
).Pigeon uses the StandardMessageCodec
so it supports any datatype Platform Channels supports [documentation]. Nested datatypes are supported, too.
By default Pigeon will generate synchronous handlers for messages and asynchronous methods. If you want a handler to be able to respond to a message asynchronously you can use the @async annotation as of version 0.1.20.
Example:
class Value { int? number; } @HostApi() abstract class Api2Host { @async Value calculate(Value value); }
Generates:
// Objective-C @protocol Api2Host -(void)calculate:(nullable Value *)input completion:(void(^)(Value *_Nullable, FlutterError *_Nullable))completion; @end
// Swift /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ protocol Api2Host { func calculate(value: Value, completion: @escaping (Value) -> Void) }
// Java public interface Result<T> { void success(T result); } /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ public interface Api2Host { void calculate(Value arg, Result<Value> result); }
// Kotlin /** Generated interface from Pigeon that represents a handler of messages from Flutter.*/ interface Api2Host { fun calculate(value: Value, callback: (Result<Value>) -> Unit) }
// C++ /** Generated class from Pigeon that represents a handler of messages from Flutter.*/ class Api2Host { public: virtual void calculate(Value value, flutter::MessageReply<Value> result) = 0; }
Pigeon supports generating null-safe code, but it doesn't yet support:
Pigeon supports enum generation in class fields. For example:
enum State { pending, success, error, } class StateResult { String? errorMessage; State? state; } @HostApi() abstract class Api { StateResult queryState(); }
Prior to version 1.0 all arguments to API methods had to be wrapped in a class, now they can be used directly. For example:
@HostApi() abstract class Api { Map<String?, int?> makeMap(List<String?> keys, List<String?> values); }
When targeting a Flutter version that supports the TaskQueue API the threading model for handling HostApi methods can be selected with the TaskQueue
annotation:
@HostApi() abstract class Api2Host { @TaskQueue(type: TaskQueueType.serialBackgroundThread) int add(int x, int y); }
All Host API exceptions are translated into Flutter PlatformException
.
To pass custom details into PlatformException
for error handling, use FlutterError
in your Host API. For example:
// Kotlin class MyApi : GeneratedApi { // For synchronous methods override fun doSomething() { throw FlutterError('error_code', 'message', 'details') } // For async methods override fun doSomethingAsync(callback: (Result<Unit>) -> Unit) { callback(Result.failure(FlutterError('error_code', 'message', 'details')) } }
Likewise, Host API errors can be sent using the provided FlutterError
class (translated into PlatformException
).
For synchronous methods:
error
argument to a FlutterError
reference.FlutterError
directly (for void methods) or within an ErrorOr
instance.For async methods:
FlutterError
through the provided callback.Then you can implement error handling on the Flutter side:
// Dart void doSomething() { try { myApi.doSomething() } catch (PlatformException e) { if (e.code == 'error_code') { // Perform custom error handling assert(e.message == 'message') assert(e.details == 'details') } } }
File an issue in flutter/flutter with the word “pigeon” in the title.