diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 11c05c86dad0d..fcce64bad2c3e 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -823,7 +823,7 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( SAFE_ACCESS(flutter_message, response_handle, nullptr); fml::RefPtr response; - if (response_handle->message) { + if (response_handle && response_handle->message) { response = response_handle->message->response(); } diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 3ec683f17d83d..348ce046e7b30 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:ui'; +import 'dart:convert'; void main() {} @@ -45,6 +46,7 @@ Float64List kTestTransform = () { }(); void signalNativeTest() native 'SignalNativeTest'; +void signalNativeMessage(String message) native 'SignalNativeMessage'; void notifySemanticsEnabled(bool enabled) native 'NotifySemanticsEnabled'; void notifyAccessibilityFeatures(bool reduceMotion) native 'NotifyAccessibilityFeatures'; void notifySemanticsAction(int nodeId, int action, List data) native 'NotifySemanticsAction'; @@ -153,3 +155,15 @@ void platform_messages_response() { }; signalNativeTest(); } + +@pragma('vm:entry-point') +void platform_messages_no_response() { + window.onPlatformMessage = (String name, ByteData data, PlatformMessageResponseCallback callback) { + var list = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + signalNativeMessage(utf8.decode(list)); + // This does nothing because no one is listening on the other side. But complete the loop anyway + // to make sure all null checking on response handles in the engine is in place. + callback(data); + }; + signalNativeTest(); +} diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index c5f1551052a77..7771d4a44eafb 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -16,6 +16,7 @@ #include "flutter/shell/platform/embedder/tests/embedder_config_builder.h" #include "flutter/shell/platform/embedder/tests/embedder_test.h" #include "flutter/testing/testing.h" +#include "third_party/tonic/converter/dart_converter.h" namespace flutter { namespace testing { @@ -352,5 +353,52 @@ TEST_F(EmbedderTest, PlatformMessagesCanReceiveResponse) { captures.latch.Wait(); } +//------------------------------------------------------------------------------ +/// Tests that a platform message can be sent with no response handle. Instead +/// of the platform message integrity checked via a response handle, a native +/// callback with the response is invoked to assert integrity. +/// +TEST_F(EmbedderTest, PlatformMessagesCanBeSentWithoutResponseHandles) { + auto& context = GetEmbedderContext(); + EmbedderConfigBuilder builder(context); + + builder.SetDartEntrypoint("platform_messages_no_response"); + + const std::string message_data = "Hello but don't call me back."; + + fml::AutoResetWaitableEvent ready, message; + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&ready](Dart_NativeArguments args) { ready.Signal(); })); + context.AddNativeCallback( + "SignalNativeMessage", + CREATE_NATIVE_ENTRY( + ([&message, &message_data](Dart_NativeArguments args) { + auto received_message = tonic::DartConverter::FromDart( + Dart_GetNativeArgument(args, 0)); + ASSERT_EQ(received_message, message_data); + message.Signal(); + }))); + + auto engine = builder.LaunchEngine(); + + ASSERT_TRUE(engine.is_valid()); + ready.Wait(); + + FlutterPlatformMessage platform_message = {}; + platform_message.struct_size = sizeof(FlutterPlatformMessage); + platform_message.channel = "test_channel"; + platform_message.message = + reinterpret_cast(message_data.data()); + platform_message.message_size = message_data.size(); + platform_message.response_handle = nullptr; // No response needed. + + auto result = + FlutterEngineSendPlatformMessage(engine.get(), &platform_message); + ASSERT_EQ(result, kSuccess); + message.Wait(); +} + } // namespace testing } // namespace flutter