The examples here will cover basic usage. For a more thorough set of examples, check the core_tests pigeon file and platform test folder (shared_test_plugin_code and alternate_language_test_plugin especially).
Begin by configuring pigeon at the top of the .dart
input file.
In actual use, you would include only the languages
needed for your project.
@ConfigurePigeon(PigeonOptions(
dartOut: 'lib/src/messages.g.dart',
dartOptions: DartOptions(),
cppOptions: CppOptions(namespace: 'pigeon_example'),
cppHeaderOut: 'windows/runner/messages.g.h',
cppSourceOut: 'windows/runner/messages.g.cpp',
gobjectHeaderOut: 'linux/messages.g.h',
gobjectSourceOut: 'linux/messages.g.cc',
gobjectOptions: GObjectOptions(),
kotlinOut:
'android/app/src/main/kotlin/dev/flutter/pigeon_example_app/Messages.g.kt',
kotlinOptions: KotlinOptions(),
javaOut: 'android/app/src/main/java/io/flutter/plugins/Messages.java',
javaOptions: JavaOptions(),
swiftOut: 'ios/Runner/Messages.g.swift',
swiftOptions: SwiftOptions(),
objcHeaderOut: 'macos/Runner/messages.g.h',
objcSourceOut: 'macos/Runner/messages.g.m',
// Set this to a unique prefix for your plugin or application, per Objective-C naming conventions.
objcOptions: ObjcOptions(prefix: 'PGN'),
copyrightHeader: 'pigeons/copyright.txt',
dartPackageName: 'pigeon_example_package',
))
Then make a simple call to run pigeon on the Dart file containing your definitions.
dart run pigeon --input path/to/input.dart
This example gives an overview of how to use Pigeon to call into the host platform from Flutter.
This is the Pigeon file that describes the interface that will be used to call from Flutter to the host-platform.
enum Code { one, two }
class MessageData {
MessageData({required this.code, required this.data});
String? name;
String? description;
Code code;
Map<String, String> data;
}
@HostApi()
abstract class ExampleHostApi {
String getHostLanguage();
// These annotations create more idiomatic naming of methods in Objc and Swift.
@ObjCSelector('addNumber:toNumber:')
@SwiftFunction('add(_:to:)')
int add(int a, int b);
@async
bool sendMessage(MessageData message);
}
This is the code that will use the generated Dart code to make calls from Flutter to the host platform.
final ExampleHostApi _api = ExampleHostApi();
/// Calls host method `add` with provided arguments.
Future<int> add(int a, int b) async {
try {
return await _api.add(a, b);
} catch (e) {
// handle error.
return 0;
}
}
/// Sends message through host api using `MessageData` class
/// and api `sendMessage` method.
Future<bool> sendMessage(String messageText) {
final MessageData message = MessageData(
code: Code.one,
data: <String, String>{'header': 'this is a header'},
description: 'uri text',
);
try {
return _api.sendMessage(message);
} catch (e) {
// handle error.
return Future<bool>(() => true);
}
}
This is the code that will use the generated Swift code to receive calls from Flutter.
Unlike other languages, when throwing an error, use PigeonError
instead of FlutterError
, as FlutterError
does not conform to Swift.Error
.
private class PigeonApiImplementation: ExampleHostApi {
func getHostLanguage() throws -> String {
return "Swift"
}
func add(_ a: Int64, to b: Int64) throws -> Int64 {
if a < 0 || b < 0 {
throw PigeonError(code: "code", message: "message", details: "details")
}
return a + b
}
func sendMessage(message: MessageData, completion: @escaping (Result<Bool, Error>) -> Void) {
if message.code == Code.one {
completion(.failure(PigeonError(code: "code", message: "message", details: "details")))
return
}
completion(.success(true))
}
}
private class PigeonApiImplementation : ExampleHostApi {
override fun getHostLanguage(): String {
return "Kotlin"
}
override fun add(a: Long, b: Long): Long {
if (a < 0L || b < 0L) {
throw FlutterError("code", "message", "details")
}
return a + b
}
override fun sendMessage(message: MessageData, callback: (Result<Boolean>) -> Unit) {
if (message.code == Code.ONE) {
callback(Result.failure(FlutterError("code", "message", "details")))
return
}
callback(Result.success(true))
}
}
class PigeonApiImplementation : public ExampleHostApi {
public:
PigeonApiImplementation() {}
virtual ~PigeonApiImplementation() {}
ErrorOr<std::string> GetHostLanguage() override { return "C++"; }
ErrorOr<int64_t> Add(int64_t a, int64_t b) {
if (a < 0 || b < 0) {
return FlutterError("code", "message", "details");
}
return a + b;
}
void SendMessage(const MessageData& message,
std::function<void(ErrorOr<bool> reply)> result) {
if (message.code == Code.kOne) {
result(FlutterError("code", "message", "details"));
return;
}
result(true);
}
};
static PigeonExamplePackageExampleHostApiGetHostLanguageResponse*
handle_get_host_language(gpointer user_data) {
return pigeon_example_package_example_host_api_get_host_language_response_new(
"C++");
}
static PigeonExamplePackageExampleHostApiAddResponse* handle_add(
int64_t a, int64_t b, gpointer user_data) {
if (a < 0 || b < 0) {
g_autoptr(FlValue) details = fl_value_new_string("details");
return pigeon_example_package_example_host_api_add_response_new_error(
"code", "message", details);
}
return pigeon_example_package_example_host_api_add_response_new(a + b);
}
static void handle_send_message(
PigeonExamplePackageMessageData* message,
PigeonExamplePackageExampleHostApiResponseHandle* response_handle,
gpointer user_data) {
PigeonExamplePackageCode code =
pigeon_example_package_message_data_get_code(message);
if (code == PIGEON_EXAMPLE_PACKAGE_CODE_ONE) {
g_autoptr(FlValue) details = fl_value_new_string("details");
pigeon_example_package_example_host_api_respond_error_send_message(
response_handle, "code", "message", details);
return;
}
pigeon_example_package_example_host_api_respond_send_message(response_handle,
TRUE);
}
static PigeonExamplePackageExampleHostApiVTable example_host_api_vtable = {
.get_host_language = handle_get_host_language,
.add = handle_add,
.send_message = handle_send_message};
This example gives an overview of how to use Pigeon to call into the Flutter app from the host platform.
@FlutterApi()
abstract class MessageFlutterApi {
String flutterMethod(String? aString);
}
This is the code that will use the generated Dart code to handle calls made to Flutter from the host platform.
class _ExampleFlutterApi implements MessageFlutterApi {
@override
String flutterMethod(String? aString) {
return aString ?? '';
}
}
// ···
MessageFlutterApi.setUp(_ExampleFlutterApi());
private class PigeonFlutterApi {
var flutterAPI: MessageFlutterApi
init(binaryMessenger: FlutterBinaryMessenger) {
flutterAPI = MessageFlutterApi(binaryMessenger: binaryMessenger)
}
func callFlutterMethod(
aString aStringArg: String?, completion: @escaping (Result<String, Error>) -> Void
) {
flutterAPI.flutterMethod(aString: aStringArg) {
completion(.success($0))
}
}
}
private class PigeonFlutterApi {
var flutterApi: MessageFlutterApi? = null
constructor(binding: FlutterPlugin.FlutterPluginBinding) {
flutterApi = MessageFlutterApi(binding.getBinaryMessenger())
}
fun callFlutterMethod(aString: String, callback: (Result<String>) -> Unit) {
flutterApi!!.flutterMethod(aString) { echo -> callback(Result.success(echo)) }
}
}
void TestPlugin::CallFlutterMethod(
String aString, std::function<void(ErrorOr<int64_t> reply)> result) {
MessageFlutterApi->FlutterMethod(
aString, [result](String echo) { result(echo); },
[result](const FlutterError& error) { result(error); });
}
static void flutter_method_cb(GObject* object, GAsyncResult* result,
gpointer user_data) {
g_autoptr(GError) error = nullptr;
g_autoptr(
PigeonExamplePackageMessageFlutterApiFlutterMethodResponse) response =
pigeon_example_package_message_flutter_api_flutter_method_finish(
PIGEON_EXAMPLE_PACKAGE_MESSAGE_FLUTTER_API(object), result, &error);
if (response == nullptr) {
g_warning("Failed to call Flutter method: %s", error->message);
return;
}
g_printerr(
"Got result from Flutter method: %s\n",
pigeon_example_package_message_flutter_api_flutter_method_response_get_return_value(
response));
}
self->flutter_api =
pigeon_example_package_message_flutter_api_new(messenger, nullptr);
pigeon_example_package_message_flutter_api_flutter_method(
self->flutter_api, "hello", nullptr, flutter_method_cb, self);
A downloadable example of using Pigeon to create a Flutter Plugin with Swift and Kotlin can be found at gaaclarke/flutter_plugin_example.
A full example of using Pigeon for add-to-app with Swift on iOS can be found at samples/add_to_app/books.
A full real-world example can also be found in the video_player plugin.