From e7a44a64a7fcd9b7f95c9befbb17e7c6bceb6181 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 7 Jun 2023 12:16:56 -0700 Subject: [PATCH] [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 --- .../Source/FlutterPlatformViewController.h | 10 +++-- .../Source/FlutterPlatformViewController.mm | 24 ++++++++--- .../FlutterPlatformViewControllerTest.mm | 40 ++++++++++++++++++- .../Source/TestFlutterPlatformView.h | 4 ++ .../Source/TestFlutterPlatformView.mm | 5 ++- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h index d0969e1f1a..31f9c63cff 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h @@ -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`. diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm index ba2399ab9f..917ee5def5 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm @@ -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* factory = _platformViewFactories[viewType]; + if ([factory respondsToSelector:@selector(createArgsCodec)]) { + NSObject* 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." diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm index 03c435ec0b..f8880ba69d 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm @@ -43,11 +43,22 @@ TEST(FlutterPlatformViewController, TestRegisterPlatformViewFactoryAndCreate) { [platformViewController registerViewFactory:factory withId:@"MockPlatformView"]; + NSDictionary* creationArgs = @{ + @"album" : @"スコットとリバース", + @"releaseYear" : @2013, + @"artists" : @[ @"Scott Murphy", @"Rivers Cuomo" ], + @"playlist" : @[ @"おかしいやつ", @"ほどけていたんだ" ], + }; + NSObject* 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) { diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.h b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.h index 719000ae66..f6ba2cdfb2 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.h +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.h @@ -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 diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.mm index 9c486e2565..b1bd763b25 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/TestFlutterPlatformView.mm @@ -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*)createArgsCodec {