Surrogate binary messenger (flutter/engine#9347)

Created FlutterSurrogateBinaryMessenger to make sure that channels are
holding onto engines and not viewcontrollers.  This doesn't change the
public API but makes clients do what we want them to be doing, using
Engine for FlutterBinaryMessenger.
This commit is contained in:
gaaclarke 2019-06-18 17:58:45 -07:00 committed by GitHub
parent 8eb78e2baa
commit 002159e772
7 changed files with 142 additions and 7 deletions

View File

@ -664,6 +664,7 @@ FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterChan
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterCodecs.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_channels_unittest.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_codecs_unittest.mm
FILE: ../../../flutter/shell/platform/darwin/common/framework/Source/flutter_standard_codec_unittest.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec
@ -699,6 +700,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatfor
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate_internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterSurrogateBinaryMessenger.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm

View File

@ -53,6 +53,7 @@ executable("flutter_channels_unittests") {
testonly = true
sources = [
"common/framework/Source/flutter_channels_unittest.mm",
"common/framework/Source/flutter_codecs_unittest.mm",
"common/framework/Source/flutter_standard_codec_unittest.mm",
]

View File

@ -3,9 +3,19 @@
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSurrogateBinaryMessenger.h"
#pragma mark - Basic message channel
static NSObject<FlutterBinaryMessenger>* getSurrogate(NSObject<FlutterBinaryMessenger>* messenger) {
if ([messenger conformsToProtocol:@protocol(FlutterSurrogateBinaryMessenger)]) {
NSObject<FlutterSurrogateBinaryMessenger>* surrogate =
(NSObject<FlutterSurrogateBinaryMessenger>*)messenger;
return [surrogate surrogateBinaryMessenger];
}
return messenger;
}
@implementation FlutterBasicMessageChannel {
NSObject<FlutterBinaryMessenger>* _messenger;
NSString* _name;
@ -32,7 +42,7 @@
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_name = [name retain];
_messenger = [messenger retain];
_messenger = [getSurrogate(messenger) retain];
_codec = [codec retain];
return self;
}
@ -172,7 +182,7 @@ NSObject const* FlutterMethodNotImplemented = [NSObject new];
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_name = [name retain];
_messenger = [messenger retain];
_messenger = [getSurrogate(messenger) retain];
_codec = [codec retain];
return self;
}
@ -251,7 +261,7 @@ NSObject const* FlutterEndOfEventStream = [NSObject new];
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_name = [name retain];
_messenger = [messenger retain];
_messenger = [getSurrogate(messenger) retain];
_codec = [codec retain];
return self;
}

View File

@ -0,0 +1,107 @@
// 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/darwin/common/framework/Headers/FlutterChannels.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSurrogateBinaryMessenger.h"
#include "gtest/gtest.h"
@interface MockBinaryMessenger : NSObject <FlutterBinaryMessenger>
@property(nonatomic, assign) int sendOnChannel_message_count;
@end
@implementation MockBinaryMessenger
- (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message {
_sendOnChannel_message_count++;
}
- (void)sendOnChannel:(NSString*)channel
message:(NSData* _Nullable)message
binaryReply:(FlutterBinaryReply _Nullable)callback {
}
- (void)setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler {
}
@end
@interface MockSurrogateBinaryMessenger
: NSObject <FlutterBinaryMessenger, FlutterSurrogateBinaryMessenger>
@property(nonatomic, strong) MockBinaryMessenger* surrogate;
@property(nonatomic, assign) int sendOnChannel_message_count;
@end
@implementation MockSurrogateBinaryMessenger
- (instancetype)init {
self = [super init];
if (self) {
_surrogate = [[[MockBinaryMessenger alloc] init] retain];
}
return self;
}
- (void)dealloc {
[_surrogate release];
[super dealloc];
}
- (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message {
_sendOnChannel_message_count++;
}
- (void)sendOnChannel:(NSString*)channel
message:(NSData* _Nullable)message
binaryReply:(FlutterBinaryReply _Nullable)callback {
}
- (void)setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler {
}
- (NSObject<FlutterBinaryMessenger>*)surrogateBinaryMessenger {
return _surrogate;
}
@end
TEST(FlutterChannels, BasicMessageChannelUsesSurrogate) {
MockSurrogateBinaryMessenger* binaryMessenger =
[[[MockSurrogateBinaryMessenger alloc] init] autorelease];
NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
FlutterBasicMessageChannel* channel =
[[[FlutterBasicMessageChannel alloc] initWithName:@"channel-name"
binaryMessenger:binaryMessenger
codec:codec] autorelease];
ASSERT_TRUE(channel != nil);
[channel sendMessage:nil];
ASSERT_EQ(1, binaryMessenger.surrogate.sendOnChannel_message_count);
ASSERT_EQ(0, binaryMessenger.sendOnChannel_message_count);
}
TEST(FlutterChannels, MethodChannelUsesSurrogate) {
MockSurrogateBinaryMessenger* binaryMessenger =
[[[MockSurrogateBinaryMessenger alloc] init] autorelease];
NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
FlutterMethodChannel* channel = [[[FlutterMethodChannel alloc] initWithName:@"channel-name"
binaryMessenger:binaryMessenger
codec:codec] autorelease];
ASSERT_TRUE(channel != nil);
[channel invokeMethod:@"foo" arguments:nil];
ASSERT_EQ(1, binaryMessenger.surrogate.sendOnChannel_message_count);
ASSERT_EQ(0, binaryMessenger.sendOnChannel_message_count);
}
TEST(FlutterChannels, EventChannelRetainsSurrogate) {
MockSurrogateBinaryMessenger* binaryMessenger =
[[[MockSurrogateBinaryMessenger alloc] init] autorelease];
NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
NSUInteger binaryMessengerRetainCount = [binaryMessenger retainCount];
NSUInteger surrogateRetainCount = [binaryMessenger.surrogate retainCount];
FlutterEventChannel* channel = [[[FlutterEventChannel alloc] initWithName:@"channel-name"
binaryMessenger:binaryMessenger
codec:codec] autorelease];
ASSERT_TRUE(channel != nil);
ASSERT_EQ(binaryMessengerRetainCount, binaryMessenger.retainCount);
ASSERT_EQ(surrogateRetainCount + 1, binaryMessenger.surrogate.retainCount);
}

View File

@ -0,0 +1,9 @@
// 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.
@protocol FlutterBinaryMessenger;
@protocol FlutterSurrogateBinaryMessenger
- (NSObject<FlutterBinaryMessenger>*)surrogateBinaryMessenger;
@end

View File

@ -992,20 +992,20 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0;
#pragma mark - FlutterBinaryMessenger
- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
[_engine.get() sendOnChannel:channel message:message];
[self.surrogateBinaryMessenger sendOnChannel:channel message:message];
}
- (void)sendOnChannel:(NSString*)channel
message:(NSData*)message
binaryReply:(FlutterBinaryReply)callback {
NSAssert(channel, @"The channel must not be null");
[_engine.get() sendOnChannel:channel message:message binaryReply:callback];
[self.surrogateBinaryMessenger sendOnChannel:channel message:message binaryReply:callback];
}
- (void)setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler)handler {
NSAssert(channel, @"The channel must not be null");
[_engine.get() setMessageHandlerOnChannel:channel binaryMessageHandler:handler];
[self.surrogateBinaryMessenger setMessageHandlerOnChannel:channel binaryMessageHandler:handler];
}
#pragma mark - FlutterTextureRegistry
@ -1048,4 +1048,9 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0;
return [_engine.get() valuePublishedByPlugin:pluginKey];
}
#pragma mark - FlutterSurrogateBinaryMessenger
- (NSObject<FlutterBinaryMessenger>*)surrogateBinaryMessenger {
return _engine.get();
}
@end

View File

@ -11,8 +11,9 @@
#include "flutter/shell/common/shell.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSurrogateBinaryMessenger.h"
@interface FlutterViewController ()
@interface FlutterViewController () <FlutterSurrogateBinaryMessenger>
- (fml::WeakPtr<FlutterViewController>)getWeakPtr;
- (flutter::FlutterPlatformViewsController*)platformViewsController;