[macOS] Add platformview creation parameter support (flutter/engine#42607)
Previously, when creating native platform views on macOS, we ignored any parameters passed via the framework side "params" argument in the "create" method call, and instead always passed a nil value to the FlutterPlatformViewFactory. This made it impossible for users of macOS platform views to pass constructor arguments to the NSView subclass implementing the platform view. We now decode the arguments data using the codec specified by the `FlutterPlatformViewFactory` and pass them through to the `[FlutterPlatformViewFactory createWithIdentifier:arguments:]` method where the platform view author can make use of them. Fixes: https://github.com/flutter/flutter/issues/124723 This is a part of the broader macOS platform view support effort: https://github.com/flutter/flutter/issues/41722 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
@@ -17,13 +17,15 @@
|
||||
@interface FlutterPlatformViewController ()
|
||||
|
||||
/**
|
||||
* Creates a platform view of viewType with viewId.
|
||||
* Creates a platform view of viewType with viewId and arguments passed from
|
||||
* the framework's creationParams constructor parameter.
|
||||
* FlutterResult is updated to contain nil for success or to contain
|
||||
* a FlutterError if there is an error.
|
||||
*/
|
||||
- (void)onCreateWithViewID:(int64_t)viewId
|
||||
viewType:(nonnull NSString*)viewType
|
||||
result:(nonnull FlutterResult)result;
|
||||
- (void)onCreateWithViewIdentifier:(int64_t)viewId
|
||||
viewType:(nonnull NSString*)viewType
|
||||
arguments:(nullable id)args
|
||||
result:(nonnull FlutterResult)result;
|
||||
|
||||
/**
|
||||
* Disposes the platform view with `viewId`.
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onCreateWithViewID:(int64_t)viewId
|
||||
viewType:(nonnull NSString*)viewType
|
||||
result:(nonnull FlutterResult)result {
|
||||
- (void)onCreateWithViewIdentifier:(int64_t)viewId
|
||||
viewType:(nonnull NSString*)viewType
|
||||
arguments:(nullable id)args
|
||||
result:(nonnull FlutterResult)result {
|
||||
if (_platformViews.count(viewId) != 0) {
|
||||
result([FlutterError errorWithCode:@"recreating_view"
|
||||
message:@"trying to create an already created view"
|
||||
@@ -52,7 +53,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
NSView* platform_view = [factory createWithViewIdentifier:viewId arguments:nil];
|
||||
NSView* platform_view = [factory createWithViewIdentifier:viewId arguments:args];
|
||||
// Flutter compositing requires CALayer-backed platform views.
|
||||
// Force the platform view to be backed by a CALayer.
|
||||
[platform_view setWantsLayer:YES];
|
||||
@@ -92,7 +93,20 @@
|
||||
if ([args objectForKey:@"id"]) {
|
||||
int64_t viewId = [args[@"id"] longLongValue];
|
||||
NSString* viewType = [NSString stringWithUTF8String:([args[@"viewType"] UTF8String])];
|
||||
[self onCreateWithViewID:viewId viewType:viewType result:result];
|
||||
|
||||
id creationArgs = nil;
|
||||
NSObject<FlutterPlatformViewFactory>* factory = _platformViewFactories[viewType];
|
||||
if ([factory respondsToSelector:@selector(createArgsCodec)]) {
|
||||
NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
|
||||
if (codec != nil && args[@"params"] != nil) {
|
||||
FlutterStandardTypedData* creationArgsData = args[@"params"];
|
||||
creationArgs = [codec decode:creationArgsData.data];
|
||||
}
|
||||
}
|
||||
[self onCreateWithViewIdentifier:viewId
|
||||
viewType:viewType
|
||||
arguments:creationArgs
|
||||
result:result];
|
||||
} else {
|
||||
result([FlutterError errorWithCode:@"unknown_view"
|
||||
message:@"'id' argument must be passed to create a platform view."
|
||||
|
||||
@@ -43,11 +43,22 @@ TEST(FlutterPlatformViewController, TestRegisterPlatformViewFactoryAndCreate) {
|
||||
|
||||
[platformViewController registerViewFactory:factory withId:@"MockPlatformView"];
|
||||
|
||||
NSDictionary* creationArgs = @{
|
||||
@"album" : @"スコットとリバース",
|
||||
@"releaseYear" : @2013,
|
||||
@"artists" : @[ @"Scott Murphy", @"Rivers Cuomo" ],
|
||||
@"playlist" : @[ @"おかしいやつ", @"ほどけていたんだ" ],
|
||||
};
|
||||
NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
|
||||
FlutterStandardTypedData* creationArgsData =
|
||||
[FlutterStandardTypedData typedDataWithBytes:[codec encode:creationArgs]];
|
||||
|
||||
FlutterMethodCall* methodCall =
|
||||
[FlutterMethodCall methodCallWithMethodName:@"create"
|
||||
arguments:@{
|
||||
@"id" : @2,
|
||||
@"viewType" : @"MockPlatformView"
|
||||
@"viewType" : @"MockPlatformView",
|
||||
@"params" : creationArgsData,
|
||||
}];
|
||||
|
||||
__block bool success = false;
|
||||
@@ -58,8 +69,33 @@ TEST(FlutterPlatformViewController, TestRegisterPlatformViewFactoryAndCreate) {
|
||||
}
|
||||
};
|
||||
[platformViewController handleMethodCall:methodCall result:result];
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
|
||||
// Verify PlatformView parameters are decoded correctly.
|
||||
TestFlutterPlatformView* view =
|
||||
(TestFlutterPlatformView*)[platformViewController platformViewWithID:2];
|
||||
ASSERT_TRUE(view != nil);
|
||||
ASSERT_TRUE(view.args != nil);
|
||||
|
||||
// Verify string type.
|
||||
NSString* album = [view.args objectForKey:@"album"];
|
||||
EXPECT_TRUE([album isEqualToString:@"スコットとリバース"]);
|
||||
|
||||
// Verify int type.
|
||||
NSNumber* releaseYear = [view.args objectForKey:@"releaseYear"];
|
||||
EXPECT_EQ(releaseYear.intValue, 2013);
|
||||
|
||||
// Verify list/array types.
|
||||
NSArray* artists = [view.args objectForKey:@"artists"];
|
||||
ASSERT_TRUE(artists != nil);
|
||||
ASSERT_EQ(artists.count, 2ul);
|
||||
EXPECT_TRUE([artists[0] isEqualToString:@"Scott Murphy"]);
|
||||
EXPECT_TRUE([artists[1] isEqualToString:@"Rivers Cuomo"]);
|
||||
|
||||
NSArray* playlist = [view.args objectForKey:@"playlist"];
|
||||
ASSERT_EQ(playlist.count, 2ul);
|
||||
EXPECT_TRUE([playlist[0] isEqualToString:@"おかしいやつ"]);
|
||||
EXPECT_TRUE([playlist[1] isEqualToString:@"ほどけていたんだ"]);
|
||||
}
|
||||
|
||||
TEST(FlutterPlatformViewController, TestCreateAndDispose) {
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
|
||||
|
||||
@interface TestFlutterPlatformView : NSView
|
||||
|
||||
/// Arguments passed via the params value in the create method call.
|
||||
@property(nonatomic, copy) id args;
|
||||
|
||||
@end
|
||||
|
||||
@interface TestFlutterPlatformViewFactory : NSObject <FlutterPlatformViewFactory>
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
@implementation TestFlutterPlatformView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
- (instancetype)initWithFrame:(CGRect)frame arguments:(nullable NSDictionary*)args {
|
||||
self = [super initWithFrame:frame];
|
||||
_args = args;
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -18,7 +19,7 @@
|
||||
|
||||
@implementation TestFlutterPlatformViewFactory
|
||||
- (NSView*)createWithViewIdentifier:(int64_t)viewId arguments:(nullable id)args {
|
||||
return [[TestFlutterPlatformView alloc] initWithFrame:CGRectZero];
|
||||
return [[TestFlutterPlatformView alloc] initWithFrame:CGRectZero arguments:args];
|
||||
}
|
||||
|
||||
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
|
||||
|
||||
Reference in New Issue
Block a user