tree: b679b495be835240d6505fc7d40779285460d983 [path history] [tgz]
  1. bin/
  2. ci/
  3. doc/
  4. e2e_tests/
  5. example/
  6. lib/
  7. mock_handler_tester/
  8. pigeons/
  9. platform_tests/
  10. test/
  11. tool/
  12. .gitignore
  13. AUTHORS
  14. CHANGELOG.md
  15. CONTRIBUTING.md
  16. copyright_header.txt
  17. diff_tool.sh
  18. LICENSE
  19. pubspec.yaml
  20. README.md
  21. run_tests.sh
packages/pigeon/README.md

Pigeon

Pigeon is a code generator tool to make communication between Flutter and the host platform type-safe, easier and faster.

Supported Platforms

Currently Pigeon supports generating Objective-C and experimental Swift code for usage on iOS, Java and experimental Kotlin code for Android, and has experimental support for C++ for Windows. The Objective-C code is accessible to Swift and the Java code is accessible to Kotlin.

Runtime Requirements

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.

Usage

  1. Add Pigeon as a dev_dependency.
  2. Make a “.dart” file outside of your “lib” directory for defining the communication interface.
  3. Run pigeon on your “.dart” file to generate the required Dart and host-language code: flutter pub get then flutter pub run pigeon with suitable arguments (see example).
  4. Add the generated Dart code to ./lib for compilation.
  5. Implement the host-language code and add it to your build (see below).
  6. Call the generated Dart methods.

Flutter calling into iOS steps

  1. Add the generated Objective-C or Swift code to your Xcode project for compilation (e.g. ios/Runner.xcworkspace or .podspec).
  2. Implement the generated iOS protocol for handling the calls on iOS, set it up as the handler for the messages.

Note: Swift code generation for iOS is experimental while we get more usage and add more testing. Not all features may be supported.

Flutter calling into Android Steps

  1. Add the generated Java or Kotlin code to your ./android/app/src/main/java directory for compilation.
  2. Implement the generated Java or Kotlin interface for handling the calls on Android, set it up as the handler for the messages.

Note: Kotlin code generation for Android is experimental while we get more usage and add more testing and works just with Flutter 3.3.0 or later. Not all features may be supported.

Flutter calling into Windows Steps

  1. Add the generated C++ code to your ./windows directory for compilation, and to your windows/CMakeLists.txt file.
  2. Implement the generated C++ abstract class for handling the calls on Windows, set it up as the handler for the messages.

Note: Windows C++ is experimental while we get more usage and add more testing. Not all features may be supported.

Calling into Flutter from the host platform

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.

Rules for defining your communication interface

  1. The file should contain no method or function definitions, only declarations.
  2. Custom classes used by APIs are defined as classes with fields of the supported datatypes (see the supported Datatypes section).
  3. APIs should be defined as an 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.
  4. Method declarations on the API classes should have arguments and a return value whose types are defined in the file, are supported datatypes, or are void.
  5. Generics are supported, but can currently only be used with nullable types (example: List<int?>).

Supported Datatypes

Pigeon uses the StandardMessageCodec so it supports any datatype Platform Channels supports [documentation]. Nested datatypes are supported, too.

Features

Asynchronous Handlers

By default Pigeon will generate synchronous handlers for messages. If you want 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:

// Objc
@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: (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;
}

Null Safety (NNBD)

Pigeon supports generating null-safe code, but it doesn't yet support:

  1. Nullable generics type arguments
  2. Nullable enum arguments to methods

It does support:

  1. Nullable and Non-nullable class fields.
  2. Nullable return values
  3. Nullable method parameters

The default is to generate null-safe code but in order to generate non-null-safe code run Pigeon with the extra argument --no-dart_null_safety. For example: flutter pub run pigeon --input ./pigeons/messages.dart --no-dart_null_safety --dart_out stdout.

Enums

As of version 0.2.2 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();
}

Primitive Data-types

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);
}

TaskQueues

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);
}

Feedback

File an issue in flutter/flutter with the word ‘pigeon’ clearly in the title and cc @gaaclarke.