Skip to content

Latest commit

 

History

History
368 lines (306 loc) · 10.8 KB

File metadata and controls

368 lines (306 loc) · 10.8 KB

Pigeon Examples

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).

Invocation

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

HostApi Example

This example gives an overview of how to use Pigeon to call into the host platform from Flutter.

Dart input

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

Dart

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

Swift

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

Kotlin

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

C++

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

GObject

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

FlutterApi Example

This example gives an overview of how to use Pigeon to call into the Flutter app from the host platform.

Dart input

@FlutterApi()
abstract class MessageFlutterApi {
  String flutterMethod(String? aString);
}

Dart

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

Swift

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

Kotlin

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

C++

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

GObject

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

Swift / Kotlin Plugin Example

A downloadable example of using Pigeon to create a Flutter Plugin with Swift and Kotlin can be found at gaaclarke/flutter_plugin_example.

Swift / Kotlin Add-to-app Example

A full example of using Pigeon for add-to-app with Swift on iOS can be found at samples/add_to_app/books.

Video player plugin

A full real-world example can also be found in the video_player plugin.