diff --git a/shell/platform/darwin/BUILD.gn b/shell/platform/darwin/BUILD.gn index 23c8e4055acf7..b44fa982b890c 100644 --- a/shell/platform/darwin/BUILD.gn +++ b/shell/platform/darwin/BUILD.gn @@ -40,6 +40,7 @@ source_set("flutter_channels") { "//flutter/common", "//flutter/flow", "//flutter/fml", + "//flutter/lib/ui:ui", "//flutter/runtime", "//flutter/shell/common", "//third_party/skia", diff --git a/shell/platform/darwin/common/BUILD.gn b/shell/platform/darwin/common/BUILD.gn index 45a9e3092b2bc..cda3ca70c639b 100644 --- a/shell/platform/darwin/common/BUILD.gn +++ b/shell/platform/darwin/common/BUILD.gn @@ -20,6 +20,7 @@ source_set("common") { "//flutter/common", "//flutter/flow", "//flutter/fml", + "//flutter/lib/ui:ui", "//flutter/runtime", "//flutter/shell/common", "//third_party/dart/runtime:dart_api", diff --git a/shell/platform/darwin/common/buffer_conversions.h b/shell/platform/darwin/common/buffer_conversions.h index 60559b2dfe230..6d0616f1c50d2 100644 --- a/shell/platform/darwin/common/buffer_conversions.h +++ b/shell/platform/darwin/common/buffer_conversions.h @@ -10,16 +10,17 @@ #include #include "flutter/fml/mapping.h" +#import "flutter/lib/ui/window/platform_message.h" namespace flutter { -std::vector GetVectorFromNSData(NSData* data); +std::vector CopyNSDataToVector(NSData* data); -NSData* GetNSDataFromVector(const std::vector& buffer); +std::unique_ptr CovertNSDataToMapping(NSData* data); -std::unique_ptr GetMappingFromNSData(NSData* data); +NSData* ConvertMessageToNSData(fml::RefPtr message); -NSData* GetNSDataFromMapping(std::unique_ptr mapping); +NSData* ConvertMappingToNSData(std::unique_ptr mapping); } // namespace flutter diff --git a/shell/platform/darwin/common/buffer_conversions.mm b/shell/platform/darwin/common/buffer_conversions.mm index 69e81de46592b..c0a1c918dda38 100644 --- a/shell/platform/darwin/common/buffer_conversions.mm +++ b/shell/platform/darwin/common/buffer_conversions.mm @@ -3,24 +3,130 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/common/buffer_conversions.h" +#import "flutter/fml/platform/darwin/scoped_nsobject.h" + +namespace { +class NSDataMapping : public fml::Mapping { + public: + NSDataMapping(NSData* data) : data_([data retain]) {} + + size_t GetSize() const override { return [data_.get() length]; } + + const uint8_t* GetMapping() const override { + return static_cast([data_.get() bytes]); + } + + private: + fml::scoped_nsobject data_; +}; +} + +/// A proxy object that behaves like NSData represented in a Mapping. +/// This isn't a subclass of NSData because NSData is in a class cluster. +@interface FlutterMappingData : NSObject +@end + +@implementation FlutterMappingData { + NSData* _data; + std::unique_ptr _mapping; +} + ++ (NSData*)dataWithMapping:(std::unique_ptr)mapping { + return (NSData*)[[[FlutterMappingData alloc] initWithMapping:std::move(mapping)] autorelease]; +} + +- (instancetype)initWithMapping:(std::unique_ptr)mapping { + self = [super init]; + if (self) { + const void* rawData = mapping->GetMapping(); + + // Const cast is required because the NSData API requires it despite + // guarentees that the buffer won't be deleted or modified. + _data = [[NSData alloc] initWithBytesNoCopy:const_cast(rawData) + length:mapping->GetSize() + freeWhenDone:NO]; + + _mapping = std::move(mapping); + } + return self; +} + +- (void)dealloc { + [_data release]; + [super dealloc]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector { + return _data; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [NSData instancesRespondToSelector:aSelector]; +} +@end + +/// A proxy object that behaves like NSData represented in a PlatformMessage. +/// This isn't a subclass of NSData because NSData is in a class cluster. +@interface FlutterMessageData : NSObject +@end + +@implementation FlutterMessageData { + NSData* _data; + fml::RefPtr _platformMessage; +} + ++ (NSData*)dataWithMessage:(fml::RefPtr)platformMessage { + return (NSData*)[[[FlutterMessageData alloc] initWithMessage:std::move(platformMessage)] + autorelease]; +} + +- (instancetype)initWithMessage:(fml::RefPtr)platformMessage { + self = [super init]; + if (self) { + const void* rawData = platformMessage->data().data(); + + // Const cast is required because the NSData API requires it despite + // guarentees that the buffer won't be deleted or modified. + _data = [[NSData alloc] initWithBytesNoCopy:const_cast(rawData) + length:platformMessage->data().size() + freeWhenDone:NO]; + + _platformMessage = std::move(platformMessage); + } + return self; +} + +- (void)dealloc { + [_data release]; + [super dealloc]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector { + return _data; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [NSData instancesRespondToSelector:aSelector]; +} +@end namespace flutter { -std::vector GetVectorFromNSData(NSData* data) { +std::vector CopyNSDataToVector(NSData* data) { const uint8_t* bytes = reinterpret_cast(data.bytes); return std::vector(bytes, bytes + data.length); } -NSData* GetNSDataFromVector(const std::vector& buffer) { - return [NSData dataWithBytes:buffer.data() length:buffer.size()]; +std::unique_ptr CovertNSDataToMapping(NSData* data) { + return std::make_unique(data); } -std::unique_ptr GetMappingFromNSData(NSData* data) { - return std::make_unique(GetVectorFromNSData(data)); +NSData* ConvertMessageToNSData(fml::RefPtr message) { + return [FlutterMessageData dataWithMessage:std::move(message)]; } -NSData* GetNSDataFromMapping(std::unique_ptr mapping) { - return [NSData dataWithBytes:mapping->GetMapping() length:mapping->GetSize()]; +NSData* ConvertMappingToNSData(std::unique_ptr mapping) { + return [FlutterMappingData dataWithMapping:std::move(mapping)]; } } // namespace flutter diff --git a/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm b/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm index 27bbbce5c9435..46a5293fe2d58 100644 --- a/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm +++ b/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm @@ -16,7 +16,6 @@ + (instancetype)sharedInstance { } - (NSData*)encode:(id)message { - NSAssert(!message || [message isKindOfClass:[NSData class]], @""); return message; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index d5e3564ecffca..81ee1f3754f57 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -807,7 +807,7 @@ - (void)sendOnChannel:(NSString*)channel fml::RefPtr platformMessage = (message == nil) ? fml::MakeRefCounted(channel.UTF8String, response) : fml::MakeRefCounted( - channel.UTF8String, flutter::GetVectorFromNSData(message), response); + channel.UTF8String, flutter::CopyNSDataToVector(message), response); _shell->GetPlatformView()->DispatchPlatformMessage(platformMessage); } diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm index e7e09855c4625..4cfa1e2aad734 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm @@ -17,7 +17,8 @@ void PlatformMessageResponseDarwin::Complete(std::unique_ptr data) { fml::RefPtr self(this); platform_task_runner_->PostTask(fml::MakeCopyable([self, data = std::move(data)]() mutable { - self->callback_.get()(GetNSDataFromMapping(std::move(data))); + NSData* callbackData = ConvertMappingToNSData(std::move(data)); + self->callback_.get()(callbackData); })); } diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm index 8fb81cc4a9a28..ec47ca9aade96 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm @@ -22,12 +22,12 @@ FlutterBinaryMessageHandler handler = it->second; NSData* data = nil; if (message->hasData()) { - data = GetNSDataFromVector(message->data()); + data = ConvertMessageToNSData(std::move(message)); } handler(data, ^(NSData* reply) { if (completer) { if (reply) { - completer->Complete(GetMappingFromNSData(reply)); + completer->Complete(CovertNSDataToMapping(reply)); } else { completer->CompleteEmpty(); }