diff --git a/shell/platform/common/cpp/client_wrapper/include/flutter/basic_message_channel.h b/shell/platform/common/cpp/client_wrapper/include/flutter/basic_message_channel.h index df0371436b179..eda3de879ff63 100644 --- a/shell/platform/common/cpp/client_wrapper/include/flutter/basic_message_channel.h +++ b/shell/platform/common/cpp/client_wrapper/include/flutter/basic_message_channel.h @@ -52,8 +52,12 @@ class BasicMessageChannel { messenger_->Send(name_, raw_message->data(), raw_message->size()); } - // TODO: Add support for a version of Send expecting a reply once - // https://github.com/flutter/flutter/issues/18852 is fixed. + // Sends a message to the Flutter engine on this channel expecting a reply. + void Send(const T& message, BinaryReply reply) { + std::unique_ptr> raw_message = + codec_->EncodeMessage(message); + messenger_->Send(name_, raw_message->data(), raw_message->size(), reply); + } // Registers a handler that should be called any time a message is // received on this channel. diff --git a/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h b/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h index ae91941fedc6c..08d074c86e744 100644 --- a/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h +++ b/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h @@ -33,14 +33,16 @@ class BinaryMessenger { // Sends a binary message to the Flutter side on the specified channel, // expecting no reply. - // - // TODO: Consider adding absl as a dependency and using absl::Span. virtual void Send(const std::string& channel, const uint8_t* message, const size_t message_size) const = 0; - // TODO: Add support for a version of Send expecting a reply once - // https://github.com/flutter/flutter/issues/18852 is fixed. + // Sends a binary message to the Flutter side on the specified channel, + // expecting a reply. + virtual void Send(const std::string& channel, + const uint8_t* message, + const size_t message_size, + BinaryReply reply) const = 0; // Registers a message handler for incoming binary messages from the Flutter // side on the specified channel. diff --git a/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc b/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc index 46c117377b22e..cf28181ed4410 100644 --- a/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc +++ b/shell/platform/common/cpp/client_wrapper/plugin_registrar.cc @@ -4,12 +4,12 @@ #include "include/flutter/plugin_registrar.h" -#include "include/flutter/engine_method_result.h" -#include "include/flutter/method_channel.h" - #include #include +#include "include/flutter/engine_method_result.h" +#include "include/flutter/method_channel.h" + namespace flutter { namespace { @@ -67,6 +67,12 @@ class BinaryMessengerImpl : public BinaryMessenger { const uint8_t* message, const size_t message_size) const override; + // |flutter::BinaryMessenger| + void Send(const std::string& channel, + const uint8_t* message, + const size_t message_size, + BinaryReply reply) const override; + // |flutter::BinaryMessenger| void SetMessageHandler(const std::string& channel, BinaryMessageHandler handler) override; @@ -87,6 +93,35 @@ void BinaryMessengerImpl::Send(const std::string& channel, message_size); } +void BinaryMessengerImpl::Send(const std::string& channel, + const uint8_t* message, + const size_t message_size, + BinaryReply reply) const { + if (reply == nullptr) { + std::cerr << "Calling BinaryMessengerImpl::Send expecting a reply, but the " + "callback is null.\n"; + return; + } + struct Captures { + BinaryReply reply; + }; + auto captures = new Captures(); + captures->reply = reply; + + auto message_reply = [](const uint8_t* data, size_t data_size, + void* user_data) { + auto captures = reinterpret_cast(user_data); + captures->reply(data, data_size); + delete captures; + }; + bool result = FlutterDesktopMessengerSendWithReply( + messenger_, channel.c_str(), message, message_size, message_reply, + captures); + if (!result) { + delete captures; + } +} + void BinaryMessengerImpl::SetMessageHandler(const std::string& channel, BinaryMessageHandler handler) { if (!handler) { diff --git a/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc b/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc index c4e5de5b46b50..22ca10ea58f27 100644 --- a/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc +++ b/shell/platform/common/cpp/client_wrapper/plugin_registrar_unittests.cc @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" - #include #include +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" #include "flutter/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h" #include "gtest/gtest.h" @@ -18,10 +17,19 @@ namespace { class TestApi : public testing::StubFlutterApi { public: // |flutter::testing::StubFlutterApi| - void MessengerSend(const char* channel, + bool MessengerSend(const char* channel, const uint8_t* message, const size_t message_size) override { last_data_sent_ = message; + return message_engine_result; + } + bool MessengerSendWithReply(const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data) override { + last_data_sent_ = message; + return message_engine_result; } const uint8_t* last_data_sent() { return last_data_sent_; } diff --git a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc index 55f4100b72efb..4bd6ddce01a39 100644 --- a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc +++ b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.cc @@ -52,13 +52,30 @@ void FlutterDesktopRegistrarEnableInputBlocking( } } -void FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, +bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, const char* channel, const uint8_t* message, const size_t message_size) { + bool result = false; if (s_stub_implementation) { - s_stub_implementation->MessengerSend(channel, message, message_size); + result = + s_stub_implementation->MessengerSend(channel, message, message_size); } + return result; +} + +bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data) { + bool result = false; + if (s_stub_implementation) { + result = s_stub_implementation->MessengerSendWithReply( + channel, message, message_size, reply, user_data); + } + return result; } void FlutterDesktopMessengerSendResponse( diff --git a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h index 64491405cb805..c5f9dbbb2a2a5 100644 --- a/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h +++ b/shell/platform/common/cpp/client_wrapper/testing/stub_flutter_api.h @@ -21,6 +21,10 @@ namespace testing { // from the actual library. class StubFlutterApi { public: + // Used by the callers to simulate a result from the engine when sending a + // message. + bool message_engine_result = true; + // Sets |stub| as the instance to which calls to the Flutter library C APIs // will be forwarded. static void SetTestStub(StubFlutterApi* stub); @@ -34,9 +38,20 @@ class StubFlutterApi { virtual void RegistrarEnableInputBlocking(const char* channel) {} // Called for FlutterDesktopMessengerSend. - virtual void MessengerSend(const char* channel, + virtual bool MessengerSend(const char* channel, const uint8_t* message, - const size_t message_size) {} + const size_t message_size) { + return message_engine_result; + } + + // Called for FlutterDesktopMessengerSendWithReply. + virtual bool MessengerSendWithReply(const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data) { + return message_engine_result; + } // Called for FlutterDesktopMessengerSendResponse. virtual void MessengerSendResponse( diff --git a/shell/platform/common/cpp/public/flutter_messenger.h b/shell/platform/common/cpp/public/flutter_messenger.h index ff9f43437708d..0a04bc8b5691d 100644 --- a/shell/platform/common/cpp/public/flutter_messenger.h +++ b/shell/platform/common/cpp/public/flutter_messenger.h @@ -21,6 +21,11 @@ typedef struct FlutterDesktopMessenger* FlutterDesktopMessengerRef; typedef struct _FlutterPlatformMessageResponseHandle FlutterDesktopMessageResponseHandle; +// The callback expected as a response of a binary message. +typedef void (*FlutterDesktopBinaryReply)(const uint8_t* data, + size_t data_size, + void* user_data); + // A message received from Flutter. typedef struct { // Size of this struct as created by Flutter. @@ -46,12 +51,20 @@ typedef void (*FlutterDesktopMessageCallback)( void* /* user data */); // Sends a binary message to the Flutter side on the specified channel. -FLUTTER_EXPORT void FlutterDesktopMessengerSend( +FLUTTER_EXPORT bool FlutterDesktopMessengerSend( FlutterDesktopMessengerRef messenger, const char* channel, const uint8_t* message, const size_t message_size); +FLUTTER_EXPORT bool FlutterDesktopMessengerSendWithReply( + FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data); + // Sends a reply to a FlutterDesktopMessage for the given response handle. // // Once this has been called, |handle| is invalid and must not be used again. diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 5913b50517513..e3259a6c93a2c 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -810,18 +810,47 @@ FlutterDesktopWindowRef FlutterDesktopRegistrarGetWindow( return registrar->window; } -void FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, - const char* channel, - const uint8_t* message, - const size_t message_size) { +bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data) { + FlutterPlatformMessageResponseHandle* response_handle = nullptr; + if (reply != nullptr && user_data != nullptr) { + FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle( + messenger->engine, reply, user_data, &response_handle); + if (result != kSuccess) { + std::cout << "Failed to create response handle\n"; + return false; + } + } + FlutterPlatformMessage platform_message = { sizeof(FlutterPlatformMessage), channel, message, message_size, + response_handle, }; - FlutterEngineSendPlatformMessage(messenger->engine, &platform_message); + FlutterEngineResult message_result = + FlutterEngineSendPlatformMessage(messenger->engine, &platform_message); + + if (response_handle != nullptr) { + FlutterPlatformMessageReleaseResponseHandle(messenger->engine, + response_handle); + } + + return message_result == kSuccess; +} + +bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size) { + return FlutterDesktopMessengerSendWithReply(messenger, channel, message, + message_size, nullptr, nullptr); } void FlutterDesktopMessengerSendResponse(