iOS Background Platform Channels (flutter/engine#29665)
This commit is contained in:
@@ -1157,8 +1157,6 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/connection_col
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/connection_collection_test.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h
|
||||
@@ -1190,6 +1188,9 @@ FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/ios_switchable_gl_context.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/ios_switchable_gl_context.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/platform_message_handler_ios_test.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h
|
||||
|
||||
@@ -31,6 +31,8 @@ typedef void (^FlutterBinaryMessageHandler)(NSData* _Nullable message, FlutterBi
|
||||
|
||||
typedef int64_t FlutterBinaryMessengerConnection;
|
||||
|
||||
@protocol FlutterTaskQueue;
|
||||
|
||||
/**
|
||||
* A facility for communicating with the Flutter side using asynchronous message
|
||||
* passing with binary messages.
|
||||
@@ -44,6 +46,16 @@ typedef int64_t FlutterBinaryMessengerConnection;
|
||||
*/
|
||||
FLUTTER_DARWIN_EXPORT
|
||||
@protocol FlutterBinaryMessenger <NSObject>
|
||||
/// TODO(gaaclarke): Remove optional when macos supports Background Platform Channels.
|
||||
@optional
|
||||
- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue;
|
||||
|
||||
- (FlutterBinaryMessengerConnection)
|
||||
setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue;
|
||||
|
||||
@required
|
||||
/**
|
||||
* Sends a binary message to the Flutter side on the specified channel, expecting
|
||||
* no reply.
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#import "FlutterBinaryMessenger.h"
|
||||
#import "FlutterCodecs.h"
|
||||
|
||||
@protocol FlutterTaskQueue;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* A message reply callback.
|
||||
@@ -24,7 +26,8 @@ typedef void (^FlutterReply)(id _Nullable reply);
|
||||
* asynchronous replies back to Flutter.
|
||||
*
|
||||
* @param message The message.
|
||||
* @param callback A callback for submitting a reply to the sender.
|
||||
* @param callback A callback for submitting a reply to the sender which can be invoked from any
|
||||
* thread.
|
||||
*/
|
||||
typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback);
|
||||
|
||||
@@ -88,6 +91,27 @@ FLUTTER_DARWIN_EXPORT
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMessageCodec>*)codec;
|
||||
|
||||
/**
|
||||
* Initializes a `FlutterBasicMessageChannel` with the specified name, binary
|
||||
* messenger, and message codec.
|
||||
*
|
||||
* The channel name logically identifies the channel; identically named channels
|
||||
* interfere with each other's communication.
|
||||
*
|
||||
* The binary messenger is a facility for sending raw, binary messages to the
|
||||
* Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`.
|
||||
*
|
||||
* @param name The channel name.
|
||||
* @param messenger The binary messenger.
|
||||
* @param codec The message codec.
|
||||
* @param taskQueue The FlutterTaskQueue that executes the handler (see
|
||||
-[FlutterBinaryMessenger makeBackgroundTaskQueue]).
|
||||
*/
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMessageCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue;
|
||||
|
||||
/**
|
||||
* Sends the specified message to the Flutter side, ignoring any reply.
|
||||
*
|
||||
@@ -142,7 +166,7 @@ typedef void (^FlutterResult)(id _Nullable result);
|
||||
* Invoke the callback with a `FlutterError` to indicate that the call failed.
|
||||
* Invoke the callback with `FlutterMethodNotImplemented` to indicate that the
|
||||
* method was unknown. Any other values, including `nil`, are interpreted as
|
||||
* successful results.
|
||||
* successful results. This can be invoked from any thread.
|
||||
*/
|
||||
typedef void (^FlutterMethodCallHandler)(FlutterMethodCall* call, FlutterResult result);
|
||||
|
||||
@@ -213,6 +237,27 @@ FLUTTER_DARWIN_EXPORT
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec;
|
||||
|
||||
/**
|
||||
* Initializes a `FlutterMethodChannel` with the specified name, binary messenger,
|
||||
* method codec, and task queue.
|
||||
*
|
||||
* The channel name logically identifies the channel; identically named channels
|
||||
* interfere with each other's communication.
|
||||
*
|
||||
* The binary messenger is a facility for sending raw, binary messages to the
|
||||
* Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`.
|
||||
*
|
||||
* @param name The channel name.
|
||||
* @param messenger The binary messenger.
|
||||
* @param codec The method codec.
|
||||
* @param taskQueue The FlutterTaskQueue that executes the handler (see
|
||||
-[FlutterBinaryMessenger makeBackgroundTaskQueue]).
|
||||
*/
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue;
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* Invokes the specified Flutter method with the specified arguments, expecting
|
||||
@@ -371,6 +416,27 @@ FLUTTER_DARWIN_EXPORT
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec;
|
||||
|
||||
/**
|
||||
* Initializes a `FlutterEventChannel` with the specified name, binary messenger,
|
||||
* method codec and task queue.
|
||||
*
|
||||
* The channel name logically identifies the channel; identically named channels
|
||||
* interfere with each other's communication.
|
||||
*
|
||||
* The binary messenger is a facility for sending raw, binary messages to the
|
||||
* Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`.
|
||||
*
|
||||
* @param name The channel name.
|
||||
* @param messenger The binary messenger.
|
||||
* @param codec The method codec.
|
||||
* @param taskQueue The FlutterTaskQueue that executes the handler (see
|
||||
-[FlutterBinaryMessenger makeBackgroundTaskQueue]).
|
||||
*/
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue;
|
||||
/**
|
||||
* Registers a handler for stream setup requests from the Flutter side.
|
||||
*
|
||||
|
||||
@@ -16,11 +16,30 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
[binaryMessenger sendOnChannel:FlutterChannelBuffersChannel message:message];
|
||||
}
|
||||
|
||||
static FlutterBinaryMessengerConnection SetMessageHandler(
|
||||
NSObject<FlutterBinaryMessenger>* messenger,
|
||||
NSString* name,
|
||||
FlutterBinaryMessageHandler handler,
|
||||
NSObject<FlutterTaskQueue>* taskQueue) {
|
||||
if (taskQueue) {
|
||||
NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:
|
||||
binaryMessageHandler:taskQueue:)],
|
||||
@"");
|
||||
return [messenger setMessageHandlerOnChannel:name
|
||||
binaryMessageHandler:handler
|
||||
taskQueue:taskQueue];
|
||||
} else {
|
||||
return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation FlutterBasicMessageChannel {
|
||||
NSObject<FlutterBinaryMessenger>* _messenger;
|
||||
NSString* _name;
|
||||
NSObject<FlutterMessageCodec>* _codec;
|
||||
FlutterBinaryMessengerConnection _connection;
|
||||
NSObject<FlutterTaskQueue>* _taskQueue;
|
||||
}
|
||||
+ (instancetype)messageChannelWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
@@ -40,11 +59,20 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMessageCodec>*)codec {
|
||||
self = [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMessageCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
|
||||
self = [super init];
|
||||
NSAssert(self, @"Super init cannot be nil");
|
||||
_name = [name retain];
|
||||
_messenger = [messenger retain];
|
||||
_codec = [codec retain];
|
||||
_taskQueue = [taskQueue retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -52,6 +80,7 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
[_name release];
|
||||
[_messenger release];
|
||||
[_codec release];
|
||||
[_taskQueue release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -85,7 +114,7 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
callback([codec encode:reply]);
|
||||
});
|
||||
};
|
||||
_connection = [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
|
||||
_connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
|
||||
}
|
||||
|
||||
- (void)resizeChannelBuffer:(NSInteger)newSize {
|
||||
@@ -96,6 +125,7 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
|
||||
#pragma mark - Method channel
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation FlutterError
|
||||
+ (instancetype)errorWithCode:(NSString*)code message:(NSString*)message details:(id)details {
|
||||
return [[[FlutterError alloc] initWithCode:code message:message details:details] autorelease];
|
||||
@@ -136,6 +166,7 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
}
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation FlutterMethodCall
|
||||
+ (instancetype)methodCallWithMethodName:(NSString*)method arguments:(id)arguments {
|
||||
return [[[FlutterMethodCall alloc] initWithMethodName:method arguments:arguments] autorelease];
|
||||
@@ -175,11 +206,13 @@ static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenge
|
||||
|
||||
NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation FlutterMethodChannel {
|
||||
NSObject<FlutterBinaryMessenger>* _messenger;
|
||||
NSString* _name;
|
||||
NSObject<FlutterMethodCodec>* _codec;
|
||||
FlutterBinaryMessengerConnection _connection;
|
||||
NSObject<FlutterTaskQueue>* _taskQueue;
|
||||
}
|
||||
|
||||
+ (instancetype)methodChannelWithName:(NSString*)name
|
||||
@@ -198,11 +231,19 @@ NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec {
|
||||
self = [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
|
||||
return self;
|
||||
}
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
|
||||
self = [super init];
|
||||
NSAssert(self, @"Super init cannot be nil");
|
||||
_name = [name retain];
|
||||
_messenger = [messenger retain];
|
||||
_codec = [codec retain];
|
||||
_taskQueue = [taskQueue retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -210,6 +251,7 @@ NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
|
||||
[_name release];
|
||||
[_messenger release];
|
||||
[_codec release];
|
||||
[_taskQueue release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -256,7 +298,7 @@ NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
|
||||
}
|
||||
});
|
||||
};
|
||||
_connection = [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
|
||||
_connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
|
||||
}
|
||||
|
||||
- (void)resizeChannelBuffer:(NSInteger)newSize {
|
||||
@@ -269,10 +311,13 @@ NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
|
||||
|
||||
NSObject const* FlutterEndOfEventStream = [[NSObject alloc] init];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation FlutterEventChannel {
|
||||
NSObject<FlutterBinaryMessenger>* _messenger;
|
||||
NSString* _name;
|
||||
NSObject<FlutterMethodCodec>* _codec;
|
||||
NSObject<FlutterTaskQueue>* _taskQueue;
|
||||
FlutterBinaryMessengerConnection _connection;
|
||||
}
|
||||
+ (instancetype)eventChannelWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
@@ -290,11 +335,19 @@ NSObject const* FlutterEndOfEventStream = [[NSObject alloc] init];
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec {
|
||||
return [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString*)name
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
|
||||
codec:(NSObject<FlutterMethodCodec>*)codec
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
|
||||
self = [super init];
|
||||
NSAssert(self, @"Super init cannot be nil");
|
||||
_name = [name retain];
|
||||
_messenger = [messenger retain];
|
||||
_codec = [codec retain];
|
||||
_taskQueue = [taskQueue retain];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -302,13 +355,16 @@ NSObject const* FlutterEndOfEventStream = [[NSObject alloc] init];
|
||||
[_name release];
|
||||
[_codec release];
|
||||
[_messenger release];
|
||||
[_taskQueue release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
static void SetStreamHandlerMessageHandlerOnChannel(NSObject<FlutterStreamHandler>* handler,
|
||||
NSString* name,
|
||||
NSObject<FlutterBinaryMessenger>* messenger,
|
||||
NSObject<FlutterMethodCodec>* codec) {
|
||||
static FlutterBinaryMessengerConnection SetStreamHandlerMessageHandlerOnChannel(
|
||||
NSObject<FlutterStreamHandler>* handler,
|
||||
NSString* name,
|
||||
NSObject<FlutterBinaryMessenger>* messenger,
|
||||
NSObject<FlutterMethodCodec>* codec,
|
||||
NSObject<FlutterTaskQueue>* taskQueue) {
|
||||
__block FlutterEventSink currentSink = nil;
|
||||
FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
|
||||
FlutterMethodCall* call = [codec decodeMethodCall:message];
|
||||
@@ -354,14 +410,16 @@ static void SetStreamHandlerMessageHandlerOnChannel(NSObject<FlutterStreamHandle
|
||||
callback(nil);
|
||||
}
|
||||
};
|
||||
[messenger setMessageHandlerOnChannel:name binaryMessageHandler:messageHandler];
|
||||
return SetMessageHandler(messenger, name, messageHandler, taskQueue);
|
||||
}
|
||||
|
||||
- (void)setStreamHandler:(NSObject<FlutterStreamHandler>*)handler {
|
||||
if (!handler) {
|
||||
[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
|
||||
[_messenger cleanUpConnection:_connection];
|
||||
_connection = 0;
|
||||
return;
|
||||
}
|
||||
SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec);
|
||||
_connection =
|
||||
SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec, _taskQueue);
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
OCMStub([codec encodeMethodCall:[OCMArg any]]).andReturn(encodedMethodCall);
|
||||
FlutterMethodCallHandler handler =
|
||||
^(FlutterMethodCall* _Nonnull call, FlutterResult _Nonnull result) {
|
||||
NSLog(@"hey");
|
||||
};
|
||||
[channel setMethodCallHandler:handler];
|
||||
OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
@@ -175,7 +174,6 @@
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:codec];
|
||||
FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) {
|
||||
NSLog(@"hey");
|
||||
};
|
||||
OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg any]])
|
||||
@@ -211,4 +209,78 @@
|
||||
OCMVerify([binaryMessenger cleanUpConnection:connection]);
|
||||
}
|
||||
|
||||
- (void)testBasicMessageChannelTaskQueue {
|
||||
NSString* channelName = @"foo";
|
||||
FlutterBinaryMessengerConnection connection = 123;
|
||||
id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
|
||||
id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
|
||||
id taskQueue = OCMClassMock([NSObject class]);
|
||||
FlutterBasicMessageChannel* channel =
|
||||
[[FlutterBasicMessageChannel alloc] initWithName:channelName
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:codec
|
||||
taskQueue:taskQueue];
|
||||
FlutterMessageHandler handler = ^(id _Nullable message, FlutterReply callback) {
|
||||
};
|
||||
OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg any]
|
||||
taskQueue:taskQueue])
|
||||
.andReturn(connection);
|
||||
[channel setMessageHandler:handler];
|
||||
OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg isNotNil]
|
||||
taskQueue:taskQueue]);
|
||||
[channel setMessageHandler:nil];
|
||||
OCMVerify([binaryMessenger cleanUpConnection:connection]);
|
||||
}
|
||||
|
||||
- (void)testMethodChannelTaskQueue {
|
||||
NSString* channelName = @"foo";
|
||||
FlutterBinaryMessengerConnection connection = 123;
|
||||
id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
|
||||
id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
|
||||
id taskQueue = OCMClassMock([NSObject class]);
|
||||
FlutterMethodChannel* channel = [[FlutterMethodChannel alloc] initWithName:channelName
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:codec
|
||||
taskQueue:taskQueue];
|
||||
XCTAssertNotNil(channel);
|
||||
FlutterMethodCallHandler handler = ^(FlutterMethodCall* call, FlutterResult result) {
|
||||
};
|
||||
OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg any]
|
||||
taskQueue:taskQueue])
|
||||
.andReturn(connection);
|
||||
[channel setMethodCallHandler:handler];
|
||||
OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg isNotNil]
|
||||
taskQueue:taskQueue]);
|
||||
[channel setMethodCallHandler:nil];
|
||||
OCMVerify([binaryMessenger cleanUpConnection:connection]);
|
||||
}
|
||||
|
||||
- (void)testEventChannelTaskQueue {
|
||||
NSString* channelName = @"foo";
|
||||
FlutterBinaryMessengerConnection connection = 123;
|
||||
id binaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
|
||||
id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
|
||||
id taskQueue = OCMClassMock([NSObject class]);
|
||||
id handler = OCMProtocolMock(@protocol(FlutterStreamHandler));
|
||||
FlutterEventChannel* channel = [[FlutterEventChannel alloc] initWithName:channelName
|
||||
binaryMessenger:binaryMessenger
|
||||
codec:codec
|
||||
taskQueue:taskQueue];
|
||||
XCTAssertNotNil(channel);
|
||||
OCMStub([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg any]
|
||||
taskQueue:taskQueue])
|
||||
.andReturn(connection);
|
||||
[channel setStreamHandler:handler];
|
||||
OCMVerify([binaryMessenger setMessageHandlerOnChannel:channelName
|
||||
binaryMessageHandler:[OCMArg isNotNil]
|
||||
taskQueue:taskQueue]);
|
||||
[channel setStreamHandler:nil];
|
||||
OCMVerify([binaryMessenger cleanUpConnection:connection]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -100,8 +100,6 @@ source_set("flutter_framework_source") {
|
||||
"framework/Source/connection_collection.mm",
|
||||
"framework/Source/platform_message_response_darwin.h",
|
||||
"framework/Source/platform_message_response_darwin.mm",
|
||||
"framework/Source/platform_message_router.h",
|
||||
"framework/Source/platform_message_router.mm",
|
||||
"framework/Source/profiler_metrics_ios.h",
|
||||
"framework/Source/profiler_metrics_ios.mm",
|
||||
"framework/Source/vsync_waiter_ios.h",
|
||||
@@ -126,6 +124,8 @@ source_set("flutter_framework_source") {
|
||||
"ios_surface_software.mm",
|
||||
"ios_switchable_gl_context.h",
|
||||
"ios_switchable_gl_context.mm",
|
||||
"platform_message_handler_ios.h",
|
||||
"platform_message_handler_ios.mm",
|
||||
"platform_view_ios.h",
|
||||
"platform_view_ios.mm",
|
||||
"rendering_api_selection.h",
|
||||
@@ -205,9 +205,12 @@ source_set("ios_test_flutter_mrc") {
|
||||
"framework/Source/FlutterPlatformViewsTest.mm",
|
||||
"framework/Source/FlutterViewTest.mm",
|
||||
"framework/Source/accessibility_bridge_test.mm",
|
||||
"platform_message_handler_ios_test.mm",
|
||||
]
|
||||
deps = [
|
||||
":flutter_framework_source",
|
||||
"//flutter/common:common",
|
||||
"//flutter/shell/common:common",
|
||||
"//flutter/shell/platform/darwin/common:framework_shared",
|
||||
"//flutter/shell/platform/embedder:embedder_as_internal_library",
|
||||
"//flutter/third_party/tonic",
|
||||
|
||||
@@ -35,6 +35,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
|
||||
if (self.parent) {
|
||||
return [self.parent makeBackgroundTaskQueue];
|
||||
} else {
|
||||
return nil;
|
||||
};
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:
|
||||
(FlutterBinaryMessageHandler)handler {
|
||||
@@ -46,6 +54,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:(FlutterBinaryMessageHandler)handler
|
||||
taskQueue:
|
||||
(NSObject<FlutterTaskQueue>*)taskQueue {
|
||||
if (self.parent) {
|
||||
return [self.parent setMessageHandlerOnChannel:channel
|
||||
binaryMessageHandler:handler
|
||||
taskQueue:taskQueue];
|
||||
} else {
|
||||
FML_LOG(WARNING) << "Communicating on a dead channel.";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
|
||||
if (self.parent) {
|
||||
return [self.parent cleanUpConnection:connection];
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
@protocol FlutterTaskQueue <NSObject>
|
||||
@end
|
||||
|
||||
@interface FlutterBinaryMessengerRelayTest : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -52,4 +55,26 @@ FLUTTER_ASSERT_ARC
|
||||
[relay sendOnChannel:channel message:message binaryReply:nil];
|
||||
}
|
||||
|
||||
- (void)testSetMessageHandlerWithTaskQueue {
|
||||
id messenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
|
||||
FlutterBinaryMessengerRelay* relay =
|
||||
[[FlutterBinaryMessengerRelay alloc] initWithParent:messenger];
|
||||
NSString* channel = @"foobar";
|
||||
NSObject<FlutterTaskQueue>* taskQueue = OCMProtocolMock(@protocol(FlutterTaskQueue));
|
||||
FlutterBinaryMessageHandler handler = ^(NSData* _Nullable, FlutterBinaryReply _Nonnull) {
|
||||
};
|
||||
[relay setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:taskQueue];
|
||||
OCMVerify([messenger setMessageHandlerOnChannel:channel
|
||||
binaryMessageHandler:handler
|
||||
taskQueue:taskQueue]);
|
||||
}
|
||||
|
||||
- (void)testMakeBackgroundTaskQueue {
|
||||
id messenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
|
||||
FlutterBinaryMessengerRelay* relay =
|
||||
[[FlutterBinaryMessengerRelay alloc] initWithParent:messenger];
|
||||
[relay makeBackgroundTaskQueue];
|
||||
OCMVerify([messenger makeBackgroundTaskQueue]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -952,12 +952,24 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
_shell->GetPlatformView()->DispatchPlatformMessage(std::move(platformMessage));
|
||||
}
|
||||
|
||||
- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
|
||||
return flutter::PlatformMessageHandlerIos::MakeBackgroundTaskQueue();
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:
|
||||
(FlutterBinaryMessageHandler)handler {
|
||||
return [self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)
|
||||
setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:(FlutterBinaryMessageHandler)handler
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
|
||||
NSParameterAssert(channel);
|
||||
if (_shell && _shell->IsSetup()) {
|
||||
self.iosPlatformView->GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, handler);
|
||||
self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
|
||||
handler, taskQueue);
|
||||
return _connections->AquireConnection(channel.UTF8String);
|
||||
} else {
|
||||
NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
|
||||
@@ -970,7 +982,8 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
if (_shell && _shell->IsSetup()) {
|
||||
std::string channel = _connections->CleanupConnection(connection);
|
||||
if (!channel.empty()) {
|
||||
self.iosPlatformView->GetPlatformMessageRouter().SetMessageHandler(channel.c_str(), nil);
|
||||
self.iosPlatformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.c_str(), nil,
|
||||
nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1604,12 +1604,24 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
|
||||
[_engine.get().binaryMessenger sendOnChannel:channel message:message binaryReply:callback];
|
||||
}
|
||||
|
||||
- (NSObject<FlutterTaskQueue>*)makeBackgroundTaskQueue {
|
||||
return [_engine.get().binaryMessenger makeBackgroundTaskQueue];
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:
|
||||
(FlutterBinaryMessageHandler)handler {
|
||||
return [self setMessageHandlerOnChannel:channel binaryMessageHandler:handler taskQueue:nil];
|
||||
}
|
||||
|
||||
- (FlutterBinaryMessengerConnection)
|
||||
setMessageHandlerOnChannel:(NSString*)channel
|
||||
binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler
|
||||
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
|
||||
NSAssert(channel, @"The channel must not be null");
|
||||
return [_engine.get().binaryMessenger setMessageHandlerOnChannel:channel
|
||||
binaryMessageHandler:handler];
|
||||
binaryMessageHandler:handler
|
||||
taskQueue:taskQueue];
|
||||
}
|
||||
|
||||
- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// 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 SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_ROUTER_H_
|
||||
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_ROUTER_H_
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/memory/weak_ptr.h"
|
||||
#include "flutter/fml/platform/darwin/scoped_block.h"
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class PlatformMessageRouter {
|
||||
public:
|
||||
PlatformMessageRouter();
|
||||
~PlatformMessageRouter();
|
||||
|
||||
void HandlePlatformMessage(
|
||||
std::unique_ptr<flutter::PlatformMessage> message) const;
|
||||
|
||||
void SetMessageHandler(const std::string& channel,
|
||||
FlutterBinaryMessageHandler handler);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, fml::ScopedBlock<FlutterBinaryMessageHandler>>
|
||||
message_handlers_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PlatformMessageRouter);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_ACCESSIBILITY_BRIDGE_H_
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#import "flutter/shell/platform/darwin/common/buffer_conversions.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
PlatformMessageRouter::PlatformMessageRouter() = default;
|
||||
|
||||
PlatformMessageRouter::~PlatformMessageRouter() = default;
|
||||
|
||||
void PlatformMessageRouter::HandlePlatformMessage(
|
||||
std::unique_ptr<flutter::PlatformMessage> message) const {
|
||||
fml::RefPtr<flutter::PlatformMessageResponse> completer = message->response();
|
||||
auto it = message_handlers_.find(message->channel());
|
||||
if (it != message_handlers_.end()) {
|
||||
FlutterBinaryMessageHandler handler = it->second;
|
||||
NSData* data = nil;
|
||||
if (message->hasData()) {
|
||||
data = ConvertMappingToNSData(message->releaseData());
|
||||
}
|
||||
handler(data, ^(NSData* reply) {
|
||||
if (completer) {
|
||||
if (reply) {
|
||||
completer->Complete(ConvertNSDataToMappingPtr(reply));
|
||||
} else {
|
||||
completer->CompleteEmpty();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (completer) {
|
||||
completer->CompleteEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformMessageRouter::SetMessageHandler(const std::string& channel,
|
||||
FlutterBinaryMessageHandler handler) {
|
||||
message_handlers_.erase(channel);
|
||||
if (handler) {
|
||||
message_handlers_[channel] =
|
||||
fml::ScopedBlock<FlutterBinaryMessageHandler>{handler, fml::OwnershipPolicy::Retain};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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_DARWIN_IOS_PLATFORM_MESSAGE_HANDLER_IOS_H_
|
||||
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_PLATFORM_MESSAGE_HANDLER_IOS_H_
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/common/task_runners.h"
|
||||
#include "flutter/fml/platform/darwin/scoped_block.h"
|
||||
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
|
||||
#include "flutter/shell/common/platform_message_handler.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
|
||||
|
||||
@protocol FlutterTaskQueue;
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class PlatformMessageHandlerIos : public PlatformMessageHandler {
|
||||
public:
|
||||
static NSObject<FlutterTaskQueue>* MakeBackgroundTaskQueue();
|
||||
|
||||
PlatformMessageHandlerIos(TaskRunners task_runners);
|
||||
|
||||
void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
|
||||
|
||||
void InvokePlatformMessageResponseCallback(int response_id,
|
||||
std::unique_ptr<fml::Mapping> mapping) override;
|
||||
|
||||
void InvokePlatformMessageEmptyResponseCallback(int response_id) override;
|
||||
|
||||
void SetMessageHandler(const std::string& channel,
|
||||
FlutterBinaryMessageHandler handler,
|
||||
NSObject<FlutterTaskQueue>* task_queue);
|
||||
|
||||
struct HandlerInfo {
|
||||
fml::scoped_nsprotocol<NSObject<FlutterTaskQueue>*> task_queue;
|
||||
fml::ScopedBlock<FlutterBinaryMessageHandler> handler;
|
||||
};
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, HandlerInfo> message_handlers_;
|
||||
TaskRunners task_runners_;
|
||||
std::mutex message_handlers_mutex_;
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PlatformMessageHandlerIos);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
// 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.
|
||||
|
||||
#import "flutter/shell/platform/darwin/ios/platform_message_handler_ios.h"
|
||||
|
||||
#import "flutter/shell/platform/darwin/common/buffer_conversions.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
|
||||
|
||||
@protocol FlutterTaskQueue
|
||||
- (void)dispatch:(dispatch_block_t)block;
|
||||
@end
|
||||
|
||||
@interface FLTSerialTaskQueue : NSObject <FlutterTaskQueue>
|
||||
@property(nonatomic, strong) dispatch_queue_t queue;
|
||||
@end
|
||||
|
||||
@implementation FLTSerialTaskQueue
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_queue = dispatch_queue_create("FLTSerialTaskQueue", DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
dispatch_release(_queue);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)dispatch:(dispatch_block_t)block {
|
||||
dispatch_async(self.queue, block);
|
||||
}
|
||||
@end
|
||||
|
||||
namespace flutter {
|
||||
|
||||
NSObject<FlutterTaskQueue>* PlatformMessageHandlerIos::MakeBackgroundTaskQueue() {
|
||||
return [[[FLTSerialTaskQueue alloc] init] autorelease];
|
||||
}
|
||||
|
||||
PlatformMessageHandlerIos::PlatformMessageHandlerIos(TaskRunners task_runners)
|
||||
: task_runners_(task_runners) {}
|
||||
|
||||
void PlatformMessageHandlerIos::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
|
||||
FML_CHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
|
||||
fml::RefPtr<flutter::PlatformMessageResponse> completer = message->response();
|
||||
HandlerInfo handler_info;
|
||||
{
|
||||
std::lock_guard lock(message_handlers_mutex_);
|
||||
auto it = message_handlers_.find(message->channel());
|
||||
if (it != message_handlers_.end()) {
|
||||
handler_info = it->second;
|
||||
}
|
||||
}
|
||||
if (handler_info.handler) {
|
||||
FlutterBinaryMessageHandler handler = handler_info.handler;
|
||||
NSData* data = nil;
|
||||
if (message->hasData()) {
|
||||
data = ConvertMappingToNSData(message->releaseData());
|
||||
}
|
||||
|
||||
dispatch_block_t run_handler = ^{
|
||||
handler(data, ^(NSData* reply) {
|
||||
// Called from any thread.
|
||||
if (completer) {
|
||||
if (reply) {
|
||||
completer->Complete(ConvertNSDataToMappingPtr(reply));
|
||||
} else {
|
||||
completer->CompleteEmpty();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (handler_info.task_queue.get()) {
|
||||
[handler_info.task_queue.get() dispatch:run_handler];
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), run_handler);
|
||||
}
|
||||
} else {
|
||||
if (completer) {
|
||||
completer->CompleteEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformMessageHandlerIos::InvokePlatformMessageResponseCallback(
|
||||
int response_id,
|
||||
std::unique_ptr<fml::Mapping> mapping) {
|
||||
// Called from any thread.
|
||||
// TODO(gaaclarke): This vestigal from the Android implementation, find a way
|
||||
// to migrate this to PlatformMessageHandlerAndroid.
|
||||
}
|
||||
|
||||
void PlatformMessageHandlerIos::InvokePlatformMessageEmptyResponseCallback(int response_id) {
|
||||
// Called from any thread.
|
||||
// TODO(gaaclarke): This vestigal from the Android implementation, find a way
|
||||
// to migrate this to PlatformMessageHandlerAndroid.
|
||||
}
|
||||
|
||||
void PlatformMessageHandlerIos::SetMessageHandler(const std::string& channel,
|
||||
FlutterBinaryMessageHandler handler,
|
||||
NSObject<FlutterTaskQueue>* task_queue) {
|
||||
FML_CHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
|
||||
/// TODO(gaaclarke): This should be migrated to a lockfree datastructure.
|
||||
std::lock_guard lock(message_handlers_mutex_);
|
||||
message_handlers_.erase(channel);
|
||||
if (handler) {
|
||||
message_handlers_[channel] = {
|
||||
.task_queue = fml::scoped_nsprotocol([task_queue retain]),
|
||||
.handler =
|
||||
fml::ScopedBlock<FlutterBinaryMessageHandler>{handler, fml::OwnershipPolicy::Retain},
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace flutter
|
||||
@@ -0,0 +1,132 @@
|
||||
// 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.
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "flutter/shell/platform/darwin/ios/platform_message_handler_ios.h"
|
||||
|
||||
#import "flutter/common/task_runners.h"
|
||||
#import "flutter/fml/message_loop.h"
|
||||
#import "flutter/fml/thread.h"
|
||||
#import "flutter/shell/common/thread_host.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
|
||||
|
||||
FLUTTER_ASSERT_NOT_ARC
|
||||
|
||||
namespace {
|
||||
using namespace flutter;
|
||||
fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
||||
auto thread = std::make_unique<fml::Thread>(name);
|
||||
auto runner = thread->GetTaskRunner();
|
||||
return runner;
|
||||
}
|
||||
|
||||
fml::RefPtr<fml::TaskRunner> GetCurrentTaskRunner() {
|
||||
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
||||
return fml::MessageLoop::GetCurrent().GetTaskRunner();
|
||||
}
|
||||
|
||||
class MockPlatformMessageResponse : public PlatformMessageResponse {
|
||||
public:
|
||||
static fml::RefPtr<MockPlatformMessageResponse> Create() {
|
||||
return fml::AdoptRef(new MockPlatformMessageResponse());
|
||||
}
|
||||
void Complete(std::unique_ptr<fml::Mapping> data) override { is_complete_ = true; }
|
||||
void CompleteEmpty() override { is_complete_ = true; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@interface PlatformMessageHandlerIosTest : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation PlatformMessageHandlerIosTest
|
||||
- (void)testCreate {
|
||||
flutter::TaskRunners task_runners("test", GetCurrentTaskRunner(), CreateNewThread("raster"),
|
||||
CreateNewThread("ui"), CreateNewThread("io"));
|
||||
auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
|
||||
XCTAssertTrue(handler);
|
||||
}
|
||||
|
||||
- (void)testSetAndCallHandler {
|
||||
ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
|
||||
ThreadHost::Type::RASTER | ThreadHost::Type::IO | ThreadHost::Type::UI);
|
||||
TaskRunners task_runners(
|
||||
"test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
|
||||
thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
|
||||
|
||||
auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
|
||||
std::string channel = "foo";
|
||||
XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
|
||||
handler->SetMessageHandler(
|
||||
channel,
|
||||
^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
|
||||
reply(nil);
|
||||
[didCallReply fulfill];
|
||||
},
|
||||
nil);
|
||||
auto response = MockPlatformMessageResponse::Create();
|
||||
task_runners.GetUITaskRunner()->PostTask([channel, response, &handler] {
|
||||
auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
|
||||
handler->HandlePlatformMessage(std::move(platform_message));
|
||||
});
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
XCTAssertTrue(response->is_complete());
|
||||
}
|
||||
|
||||
- (void)testSetClearAndCallHandler {
|
||||
ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
|
||||
ThreadHost::Type::RASTER | ThreadHost::Type::IO | ThreadHost::Type::UI);
|
||||
TaskRunners task_runners(
|
||||
"test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
|
||||
thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
|
||||
|
||||
auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
|
||||
std::string channel = "foo";
|
||||
XCTestExpectation* didCallMessage = [self expectationWithDescription:@"didCallMessage"];
|
||||
handler->SetMessageHandler(
|
||||
channel,
|
||||
^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
|
||||
XCTFail(@"This shouldn't be called");
|
||||
reply(nil);
|
||||
},
|
||||
nil);
|
||||
handler->SetMessageHandler(channel, nil, nil);
|
||||
auto response = MockPlatformMessageResponse::Create();
|
||||
task_runners.GetUITaskRunner()->PostTask([channel, response, &handler, &didCallMessage] {
|
||||
auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
|
||||
handler->HandlePlatformMessage(std::move(platform_message));
|
||||
[didCallMessage fulfill];
|
||||
});
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
XCTAssertTrue(response->is_complete());
|
||||
}
|
||||
|
||||
- (void)testSetAndCallHandlerTaskQueue {
|
||||
ThreadHost thread_host("io.flutter.test." + std::string(self.name.UTF8String),
|
||||
ThreadHost::Type::RASTER | ThreadHost::Type::IO | ThreadHost::Type::UI);
|
||||
TaskRunners task_runners(
|
||||
"test", GetCurrentTaskRunner(), thread_host.raster_thread->GetTaskRunner(),
|
||||
thread_host.ui_thread->GetTaskRunner(), thread_host.io_thread->GetTaskRunner());
|
||||
|
||||
auto handler = std::make_unique<PlatformMessageHandlerIos>(task_runners);
|
||||
std::string channel = "foo";
|
||||
XCTestExpectation* didCallReply = [self expectationWithDescription:@"didCallReply"];
|
||||
NSObject<FlutterTaskQueue>* taskQueue = PlatformMessageHandlerIos::MakeBackgroundTaskQueue();
|
||||
handler->SetMessageHandler(
|
||||
channel,
|
||||
^(NSData* _Nullable data, FlutterBinaryReply _Nonnull reply) {
|
||||
XCTAssertFalse([NSThread isMainThread]);
|
||||
reply(nil);
|
||||
[didCallReply fulfill];
|
||||
},
|
||||
taskQueue);
|
||||
auto response = MockPlatformMessageResponse::Create();
|
||||
task_runners.GetUITaskRunner()->PostTask([channel, response, &handler] {
|
||||
auto platform_message = std::make_unique<flutter::PlatformMessage>(channel, response);
|
||||
handler->HandlePlatformMessage(std::move(platform_message));
|
||||
});
|
||||
[self waitForExpectationsWithTimeout:1.0 handler:nil];
|
||||
XCTAssertTrue(response->is_complete());
|
||||
}
|
||||
@end
|
||||
@@ -16,10 +16,10 @@
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h"
|
||||
#import "flutter/shell/platform/darwin/ios/ios_context.h"
|
||||
#import "flutter/shell/platform/darwin/ios/ios_external_view_embedder.h"
|
||||
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
|
||||
#import "flutter/shell/platform/darwin/ios/platform_message_handler_ios.h"
|
||||
#import "flutter/shell/platform/darwin/ios/rendering_api_selection.h"
|
||||
|
||||
@class FlutterViewController;
|
||||
@@ -53,12 +53,6 @@ class PlatformViewIOS final : public PlatformView {
|
||||
|
||||
~PlatformViewIOS() override;
|
||||
|
||||
/**
|
||||
* The `PlatformMessageRouter` is the iOS bridge connecting the shell's
|
||||
* platform agnostic `PlatformMessage` to iOS's channel message handler.
|
||||
*/
|
||||
PlatformMessageRouter& GetPlatformMessageRouter();
|
||||
|
||||
/**
|
||||
* Returns the `FlutterViewController` currently attached to the `FlutterEngine` owning
|
||||
* this PlatformViewIOS.
|
||||
@@ -96,6 +90,14 @@ class PlatformViewIOS final : public PlatformView {
|
||||
/** Accessor for the `IOSContext` associated with the platform view. */
|
||||
const std::shared_ptr<IOSContext>& GetIosContext() { return ios_context_; }
|
||||
|
||||
std::shared_ptr<PlatformMessageHandlerIos> GetPlatformMessageHandlerIos() const {
|
||||
return platform_message_handler_;
|
||||
}
|
||||
|
||||
std::shared_ptr<PlatformMessageHandler> GetPlatformMessageHandler() const override {
|
||||
return platform_message_handler_;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Smart pointer for use with objective-c observers.
|
||||
/// This guarantees we remove the observer.
|
||||
@@ -136,12 +138,12 @@ class PlatformViewIOS final : public PlatformView {
|
||||
std::unique_ptr<IOSSurface> ios_surface_;
|
||||
std::shared_ptr<IOSContext> ios_context_;
|
||||
const std::shared_ptr<FlutterPlatformViewsController>& platform_views_controller_;
|
||||
PlatformMessageRouter platform_message_router_;
|
||||
AccessibilityBridgePtr accessibility_bridge_;
|
||||
fml::scoped_nsprotocol<FlutterTextInputPlugin*> text_input_plugin_;
|
||||
fml::closure firstFrameCallback_;
|
||||
ScopedObserver dealloc_view_controller_observer_;
|
||||
std::vector<std::string> platform_resolved_locale_;
|
||||
std::shared_ptr<PlatformMessageHandlerIos> platform_message_handler_;
|
||||
|
||||
// |PlatformView|
|
||||
void HandlePlatformMessage(std::unique_ptr<flutter::PlatformMessage> message) override;
|
||||
|
||||
@@ -53,7 +53,8 @@ PlatformViewIOS::PlatformViewIOS(
|
||||
: PlatformView(delegate, std::move(task_runners)),
|
||||
ios_context_(context),
|
||||
platform_views_controller_(platform_views_controller),
|
||||
accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }) {}
|
||||
accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
|
||||
platform_message_handler_(new PlatformMessageHandlerIos(task_runners)) {}
|
||||
|
||||
PlatformViewIOS::PlatformViewIOS(
|
||||
PlatformView::Delegate& delegate,
|
||||
@@ -67,13 +68,9 @@ PlatformViewIOS::PlatformViewIOS(
|
||||
|
||||
PlatformViewIOS::~PlatformViewIOS() = default;
|
||||
|
||||
PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() {
|
||||
return platform_message_router_;
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
void PlatformViewIOS::HandlePlatformMessage(std::unique_ptr<flutter::PlatformMessage> message) {
|
||||
platform_message_router_.HandlePlatformMessage(std::move(message));
|
||||
platform_message_handler_->HandlePlatformMessage(std::move(message));
|
||||
}
|
||||
|
||||
fml::WeakPtr<FlutterViewController> PlatformViewIOS::GetOwnerViewController() const {
|
||||
|
||||
Reference in New Issue
Block a user