Add FlBasicMessageChannel (#18189)
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 425a315..8ce5b14 100755
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1185,6 +1185,7 @@
FILE: ../../../flutter/shell/platform/glfw/public/flutter_glfw.h
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
+FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger.cc
@@ -1207,6 +1208,7 @@
FILE: ../../../flutter/shell/platform/linux/fl_value.cc
FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_view.cc
+FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn
index cae44d2..5b3f865 100644
--- a/shell/platform/linux/BUILD.gn
+++ b/shell/platform/linux/BUILD.gn
@@ -44,6 +44,7 @@
}
_public_headers = [
+ "public/flutter_linux/fl_basic_message_channel.h",
"public/flutter_linux/fl_binary_codec.h",
"public/flutter_linux/fl_binary_messenger.h",
"public/flutter_linux/fl_dart_project.h",
@@ -64,6 +65,7 @@
public = _public_headers
sources = [
+ "fl_basic_message_channel.cc",
"fl_binary_codec.cc",
"fl_binary_messenger.cc",
"fl_dart_project.cc",
diff --git a/shell/platform/linux/fl_basic_message_channel.cc b/shell/platform/linux/fl_basic_message_channel.cc
new file mode 100644
index 0000000..5559c4a
--- /dev/null
+++ b/shell/platform/linux/fl_basic_message_channel.cc
@@ -0,0 +1,206 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h"
+
+#include <gmodule.h>
+
+struct _FlBasicMessageChannel {
+ GObject parent_instance;
+
+ // Messenger to communicate on
+ FlBinaryMessenger* messenger;
+
+ // Channel name
+ gchar* name;
+
+ // Codec to en/decode messages
+ FlMessageCodec* codec;
+
+ // Function called when a message is received
+ FlBasicMessageChannelMessageHandler message_handler;
+ gpointer message_handler_data;
+};
+
+// Wrap the binary messenger handle for type safety and to make the API
+// consistent
+struct _FlBasicMessageChannelResponseHandle {
+ FlBinaryMessengerResponseHandle* response_handle;
+};
+
+static FlBasicMessageChannelResponseHandle* response_handle_new(
+ FlBinaryMessengerResponseHandle* response_handle) {
+ FlBasicMessageChannelResponseHandle* handle =
+ static_cast<FlBasicMessageChannelResponseHandle*>(
+ g_malloc0(sizeof(FlBasicMessageChannelResponseHandle)));
+ handle->response_handle = response_handle;
+
+ return handle;
+}
+
+static void response_handle_free(FlBasicMessageChannelResponseHandle* handle) {
+ g_free(handle);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlBasicMessageChannelResponseHandle,
+ response_handle_free);
+
+// Added here to stop the compiler from optimising this function away
+G_MODULE_EXPORT GType fl_basic_message_channel_get_type();
+
+G_DEFINE_TYPE(FlBasicMessageChannel, fl_basic_message_channel, G_TYPE_OBJECT)
+
+// Called when a binary message is received on this channel
+static void message_cb(FlBinaryMessenger* messenger,
+ const gchar* channel,
+ GBytes* message,
+ FlBinaryMessengerResponseHandle* response_handle,
+ gpointer user_data) {
+ FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(user_data);
+
+ if (self->message_handler == nullptr) {
+ fl_binary_messenger_send_response(messenger, response_handle, nullptr,
+ nullptr);
+ return;
+ }
+
+ g_autoptr(GError) error = nullptr;
+ g_autoptr(FlValue) message_value =
+ fl_message_codec_decode_message(self->codec, message, &error);
+ if (message_value == nullptr) {
+ g_warning("Failed to decode message: %s", error->message);
+ fl_binary_messenger_send_response(messenger, response_handle, nullptr,
+ nullptr);
+ }
+
+ self->message_handler(self, message_value,
+ response_handle_new(response_handle),
+ self->message_handler_data);
+}
+
+// Called when a response is received to a sent message
+static void message_response_cb(GObject* object,
+ GAsyncResult* result,
+ gpointer user_data) {
+ GTask* task = G_TASK(user_data);
+ g_task_return_pointer(task, result, g_object_unref);
+}
+
+static void fl_basic_message_channel_dispose(GObject* object) {
+ FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(object);
+
+ if (self->messenger != nullptr)
+ fl_binary_messenger_set_message_handler_on_channel(
+ self->messenger, self->name, nullptr, nullptr);
+
+ g_clear_object(&self->messenger);
+ g_clear_pointer(&self->name, g_free);
+ g_clear_object(&self->codec);
+
+ G_OBJECT_CLASS(fl_basic_message_channel_parent_class)->dispose(object);
+}
+
+static void fl_basic_message_channel_class_init(
+ FlBasicMessageChannelClass* klass) {
+ G_OBJECT_CLASS(klass)->dispose = fl_basic_message_channel_dispose;
+}
+
+static void fl_basic_message_channel_init(FlBasicMessageChannel* self) {}
+
+G_MODULE_EXPORT FlBasicMessageChannel* fl_basic_message_channel_new(
+ FlBinaryMessenger* messenger,
+ const gchar* name,
+ FlMessageCodec* codec) {
+ g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
+ g_return_val_if_fail(name != nullptr, nullptr);
+ g_return_val_if_fail(FL_IS_MESSAGE_CODEC(codec), nullptr);
+
+ FlBasicMessageChannel* self = FL_BASIC_MESSAGE_CHANNEL(
+ g_object_new(fl_basic_message_channel_get_type(), nullptr));
+
+ self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
+ self->name = g_strdup(name);
+ self->codec = FL_MESSAGE_CODEC(g_object_ref(codec));
+
+ fl_binary_messenger_set_message_handler_on_channel(
+ self->messenger, self->name, message_cb, self);
+
+ return self;
+}
+
+G_MODULE_EXPORT void fl_basic_message_channel_set_message_handler(
+ FlBasicMessageChannel* self,
+ FlBasicMessageChannelMessageHandler handler,
+ gpointer user_data) {
+ g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));
+
+ self->message_handler = handler;
+ self->message_handler_data = user_data;
+}
+
+G_MODULE_EXPORT gboolean fl_basic_message_channel_respond(
+ FlBasicMessageChannel* self,
+ FlBasicMessageChannelResponseHandle* response_handle,
+ FlValue* message,
+ GError** error) {
+ g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), FALSE);
+ g_return_val_if_fail(response_handle != nullptr, FALSE);
+
+ // Take reference to ensure it is freed
+ g_autoptr(FlBasicMessageChannelResponseHandle) owned_response_handle =
+ response_handle;
+
+ g_autoptr(GBytes) data =
+ fl_message_codec_encode_message(self->codec, message, error);
+ if (data == nullptr)
+ return FALSE;
+
+ return fl_binary_messenger_send_response(
+ self->messenger, owned_response_handle->response_handle, data, error);
+}
+
+G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel* self,
+ FlValue* message,
+ GCancellable* cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data) {
+ g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));
+ g_return_if_fail(message != nullptr);
+
+ g_autoptr(GTask) task =
+ callback != nullptr ? g_task_new(self, cancellable, callback, user_data)
+ : nullptr;
+
+ g_autoptr(GError) error = nullptr;
+ g_autoptr(GBytes) data =
+ fl_message_codec_encode_message(self->codec, message, &error);
+ if (data == nullptr) {
+ if (task != nullptr)
+ g_task_return_error(task, error);
+ return;
+ }
+
+ fl_binary_messenger_send_on_channel(
+ self->messenger, self->name, data, cancellable,
+ callback != nullptr ? message_response_cb : nullptr,
+ g_steal_pointer(&task));
+}
+
+G_MODULE_EXPORT FlValue* fl_basic_message_channel_send_on_channel_finish(
+ FlBasicMessageChannel* self,
+ GAsyncResult* result,
+ GError** error) {
+ g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), nullptr);
+ g_return_val_if_fail(g_task_is_valid(result, self), nullptr);
+
+ g_autoptr(GTask) task = G_TASK(result);
+ GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr));
+
+ g_autoptr(GBytes) message =
+ fl_binary_messenger_send_on_channel_finish(self->messenger, r, error);
+ if (message == nullptr)
+ return nullptr;
+
+ return fl_message_codec_decode_message(self->codec, message, error);
+}
diff --git a/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h b/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
new file mode 100644
index 0000000..a26332b
--- /dev/null
+++ b/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h
@@ -0,0 +1,143 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_
+#define FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_
+
+#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
+#error "Only <flutter_linux/flutter_linux.h> can be included directly."
+#endif
+
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include "fl_binary_messenger.h"
+#include "fl_message_codec.h"
+
+G_BEGIN_DECLS
+
+G_DECLARE_FINAL_TYPE(FlBasicMessageChannel,
+ fl_basic_message_channel,
+ FL,
+ BASIC_MESSAGE_CHANNEL,
+ GObject)
+
+/**
+ * FlBasicMessageChannel:
+ *
+ * #FlBasicMessageChannel is an object that allows sending and receiving
+ * messages to/from Dart code over platform channels.
+ *
+ * #FlBasicMessageChannel matches the BasicMessageChannel class in the Flutter
+ * services library.
+ */
+
+/**
+ * FlBasicMessageChannelResponseHandle:
+ *
+ * A handle used to respond to messages.
+ */
+typedef struct _FlBasicMessageChannelResponseHandle
+ FlBasicMessageChannelResponseHandle;
+
+/**
+ * FlBasicMessageChannelMessageHandler:
+ * @channel: a #FlBasicMessageChannel
+ * @message: message received
+ * @response_handle: (transfer full): a handle to respond to the message with
+ * @user_data: (closure): data provided when registering this handler
+ *
+ * Function called when a message is received.
+ */
+typedef void (*FlBasicMessageChannelMessageHandler)(
+ FlBasicMessageChannel* channel,
+ FlValue* message,
+ FlBasicMessageChannelResponseHandle* response_handle,
+ gpointer user_data);
+
+/**
+ * fl_basic_message_channel_new:
+ * @messenger: a #FlBinaryMessenger
+ * @name: a channel name
+ * @codec: the message codec
+ *
+ * Create a new basic message channel. @codec must match the codec used on the
+ * Dart end of the channel.
+ *
+ * Returns: a new #FlBasicMessageChannel.
+ */
+FlBasicMessageChannel* fl_basic_message_channel_new(
+ FlBinaryMessenger* messenger,
+ const gchar* name,
+ FlMessageCodec* codec);
+
+/**
+ * fl_basic_message_channel_set_message_handler:
+ * @channel: a #FlBasicMessageChannel
+ * @handler: (allow-none): function to call when a message is received on this
+ * channel or %NULL to disable the handler.
+ * @user_data: (closure): user data to pass to @handler
+ *
+ * Set the function called when a message is received.
+ */
+void fl_basic_message_channel_set_message_handler(
+ FlBasicMessageChannel* channel,
+ FlBasicMessageChannelMessageHandler handler,
+ gpointer user_data);
+
+/**
+ * fl_basic_message_channel_send_response:
+ * @channel: a #FlBasicMessageChannel
+ * @response_handle: (transfer full): handle that was provided in a
+ * #FlBasicMessageChannelMessageHandler
+ * @response: (allow-none): response to send or %NULL for an empty response
+ * @error: (allow-none): #GError location to store the error occurring, or %NULL
+ * to ignore
+ *
+ * Respond to a message.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean fl_basic_message_channel_send_response(
+ FlBasicMessageChannel* channel,
+ FlBasicMessageChannelResponseHandle* response_handle,
+ FlValue* response,
+ GError** error);
+
+/**
+ * fl_basic_message_channel_send:
+ * @channel: a #FlBasicMessageChannel
+ * @message: message to send, must match what the #FlMessageCodec supports
+ * @cancellable: (allow-none): a #GCancellable or %NULL
+ * @callback: (scope async): (allow-none): a #GAsyncReadyCallback to call when
+ * the request is satisfied or %NULL to ignore the response.
+ * @user_data: (closure): user data to pass to @callback
+ *
+ * Asynchronously send a message.
+ */
+void fl_basic_message_channel_send(FlBasicMessageChannel* channel,
+ FlValue* message,
+ GCancellable* cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+/**
+ * fl_basic_message_channel_send_finish:
+ * @channel: a #FlBasicMessageChannel
+ * @result: a #GAsyncResult
+ * @error: (allow-none): #GError location to store the error occurring, or %NULL
+ * to ignore.
+ *
+ * Complete request started with fl_basic_message_channel_send().
+ *
+ * Returns: message response on success or %NULL on error.
+ */
+FlValue* fl_basic_message_channel_send_on_channel_finish(
+ FlBasicMessageChannel* channel,
+ GAsyncResult* result,
+ GError** error);
+
+G_END_DECLS
+
+#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_BASIC_MESSAGE_CHANNEL_H_
diff --git a/shell/platform/linux/public/flutter_linux/flutter_linux.h b/shell/platform/linux/public/flutter_linux/flutter_linux.h
index 62449e8..cb869b0 100644
--- a/shell/platform/linux/public/flutter_linux/flutter_linux.h
+++ b/shell/platform/linux/public/flutter_linux/flutter_linux.h
@@ -7,6 +7,7 @@
#define __FLUTTER_LINUX_INSIDE__
+#include <flutter_linux/fl_basic_message_channel.h>
#include <flutter_linux/fl_binary_codec.h>
#include <flutter_linux/fl_binary_messenger.h>
#include <flutter_linux/fl_dart_project.h>