Skip to content

Commit

Permalink
[macOS] Add platformview creation parameter support (flutter#42607)
Browse files Browse the repository at this point in the history
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: flutter/flutter#124723

This is a part of the broader macOS platform view support effort: flutter/flutter#41722

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
cbracken authored Jun 7, 2023
1 parent f5007e9 commit 71c9d51
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ - (instancetype)init {
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"
Expand All @@ -52,7 +53,7 @@ - (void)onCreateWithViewID:(int64_t)viewId
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];
Expand Down Expand Up @@ -92,7 +93,20 @@ - (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull Flutte
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."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,22 @@

[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;
Expand All @@ -58,8 +69,33 @@
}
};
[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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@

@implementation TestFlutterPlatformView

- (instancetype)initWithFrame:(CGRect)frame {
- (instancetype)initWithFrame:(CGRect)frame arguments:(nullable NSDictionary*)args {
self = [super initWithFrame:frame];
_args = args;
return self;
}

@end

@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 {
Expand Down

0 comments on commit 71c9d51

Please sign in to comment.