Skip to content

Commit 74338e9

Browse files
committed
[macos] Wireup platform views on macOS
* The plan is to only support platform views when using Metal rendering backend. * This PR is based on the work done in: flutter#22905 * There are some threading issues to be addressed still to make this feature usable: flutter/flutter#96668
1 parent 1fab2fb commit 74338e9

15 files changed

+504
-24
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppD
12201220
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h
12211221
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h
12221222
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterMacOS.h
1223+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPlatformViews.h
12231224
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginMacOS.h
12241225
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h
12251226
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h
@@ -1281,6 +1282,11 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenG
12811282
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.h
12821283
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.mm
12831284
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMacTest.mm
1285+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm
1286+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm
1287+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h
1288+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewMock.h
1289+
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewMock.mm
12841290
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h
12851291
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderingBackend.h
12861292
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderingBackend.mm

shell/platform/darwin/macos/BUILD.gn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ _flutter_framework_headers = [
4040
"framework/Headers/FlutterDartProject.h",
4141
"framework/Headers/FlutterEngine.h",
4242
"framework/Headers/FlutterMacOS.h",
43+
"framework/Headers/FlutterPlatformViews.h",
4344
"framework/Headers/FlutterPluginMacOS.h",
4445
"framework/Headers/FlutterPluginRegistrarMacOS.h",
4546
"framework/Headers/FlutterViewController.h",
@@ -95,6 +96,8 @@ source_set("flutter_framework_source") {
9596
"framework/Source/FlutterOpenGLRenderer.mm",
9697
"framework/Source/FlutterPlatformNodeDelegateMac.h",
9798
"framework/Source/FlutterPlatformNodeDelegateMac.mm",
99+
"framework/Source/FlutterPlatformViewController.h",
100+
"framework/Source/FlutterPlatformViewController.mm",
98101
"framework/Source/FlutterRenderer.h",
99102
"framework/Source/FlutterRenderingBackend.h",
100103
"framework/Source/FlutterRenderingBackend.mm",
@@ -186,11 +189,14 @@ executable("flutter_desktop_darwin_unittests") {
186189
"framework/Source/FlutterMetalSurfaceManagerTest.mm",
187190
"framework/Source/FlutterOpenGLRendererTest.mm",
188191
"framework/Source/FlutterPlatformNodeDelegateMacTest.mm",
192+
"framework/Source/FlutterPlatformViewControllerTest.mm",
189193
"framework/Source/FlutterTextInputPluginTest.mm",
190194
"framework/Source/FlutterTextInputSemanticsObjectTest.mm",
191195
"framework/Source/FlutterViewControllerTest.mm",
192196
"framework/Source/FlutterViewControllerTestUtils.h",
193197
"framework/Source/FlutterViewControllerTestUtils.mm",
198+
"framework/Source/TestFlutterPlatformView.h",
199+
"framework/Source/TestFlutterPlatformView.mm",
194200
]
195201

196202
cflags_objcc = flutter_cflags_objcc_arc
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FLUTTERPLATFORMVIEWS_H_
6+
#define FLUTTER_FLUTTERPLATFORMVIEWS_H_
7+
8+
#import <AppKit/AppKit.h>
9+
10+
#import "FlutterCodecs.h"
11+
#import "FlutterMacros.h"
12+
13+
@protocol FlutterPlatformViewFactory <NSObject>
14+
15+
/**
16+
* Create a Platform View which is an `NSView`.
17+
*
18+
* Implemented by MacOS plugin code to return an `NSView` to be inserted into the Flutter view
19+
* hierarchy.
20+
*
21+
* The implementation of this method should create a new `NSView` and return it.
22+
*
23+
* @param frame The rectangle for the newly created view measured in points.
24+
* @param viewId A unique identifier for this view.
25+
* @param args Parameters for creating the view sent from the Dart side of the
26+
* Flutter app. If `createArgsCodec` is not implemented, or if no creation arguments were sent from
27+
* the Dart code, this will be null. Otherwise this will be the value sent from the Dart code as
28+
* decoded by `createArgsCodec`.
29+
*/
30+
- (nonnull NSView*)createWithFrame:(CGRect)frame
31+
viewIdentifier:(int64_t)viewId
32+
arguments:(nullable id)args;
33+
34+
/**
35+
* Returns the `FlutterMessageCodec` for decoding the args parameter of `createWithFrame`.
36+
*
37+
* Only needs to be implemented if `createWithFrame` needs an arguments parameter.
38+
*/
39+
@optional
40+
- (nullable NSObject<FlutterMessageCodec>*)createArgsCodec;
41+
@end
42+
43+
#endif // FLUTTER_FLUTTERPLATFORMVIEWS_H_

shell/platform/darwin/macos/framework/Headers/FlutterPluginRegistrarMacOS.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#import "FlutterBinaryMessenger.h"
88
#import "FlutterChannels.h"
99
#import "FlutterMacros.h"
10+
#import "FlutterPlatformViews.h"
1011
#import "FlutterPluginMacOS.h"
1112
#import "FlutterTexture.h"
1213

@@ -48,6 +49,18 @@ FLUTTER_DARWIN_EXPORT
4849
- (void)addMethodCallDelegate:(nonnull id<FlutterPlugin>)delegate
4950
channel:(nonnull FlutterMethodChannel*)channel;
5051

52+
/**
53+
* Registers a `FlutterPlatformViewFactory` for creation of platform views.
54+
*
55+
* Plugins expose `NSView` for embedding in Flutter apps by registering a view factory.
56+
*
57+
* @param factory The view factory that will be registered.
58+
* @param factoryId A unique identifier for the factory, the Dart code of the Flutter app can use
59+
* this identifier to request creation of a `NSView` by the registered factory.
60+
*/
61+
- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory>*)factory
62+
withId:(nonnull NSString*)factoryId;
63+
5164
@end
5265

5366
/**

shell/platform/darwin/macos/framework/Headers/FlutterViewController.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#import "FlutterEngine.h"
88
#import "FlutterMacros.h"
9+
#import "FlutterPlatformViews.h"
910
#import "FlutterPluginRegistrarMacOS.h"
1011

1112
/**

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h"
1616
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h"
1717
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
18+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
1819
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderingBackend.h"
1920
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
20-
#include "flutter/shell/platform/embedder/embedder.h"
21+
#import "flutter/shell/platform/embedder/embedder.h"
2122

2223
/**
2324
* Constructs and returns a FlutterLocale struct corresponding to |locale|, which must outlive
@@ -95,6 +96,11 @@ - (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)t
9596
*/
9697
- (void)loadAOTData:(NSString*)assetsDir;
9798

99+
/**
100+
* Creates a platform view channel and sets up the method handler.
101+
*/
102+
- (void)setupPlatformViewChannel;
103+
98104
@end
99105

100106
#pragma mark -
@@ -145,6 +151,11 @@ - (void)addMethodCallDelegate:(nonnull id<FlutterPlugin>)delegate
145151
}];
146152
}
147153

154+
- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory>*)factory
155+
withId:(nonnull NSString*)factoryId {
156+
[[_flutterEngine platformViewController] registerViewFactory:factory withId:factoryId];
157+
}
158+
148159
@end
149160

150161
// Callbacks provided to the engine. See the called methods for documentation.
@@ -186,6 +197,14 @@ @implementation FlutterEngine {
186197

187198
// FlutterCompositor is copied and used in embedder.cc.
188199
FlutterCompositor _compositor;
200+
201+
// Method channel for platform view functions. These functions include creating, disposing and
202+
// mutating a platform view.
203+
FlutterMethodChannel* _platformViewsChannel;
204+
205+
// Used to support creation and deletion of platform views and registering platform view
206+
// factories. Lifecycle is tied to the engine.
207+
FlutterPlatformViewController* _platformViewController;
189208
}
190209

191210
- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
@@ -219,6 +238,9 @@ - (instancetype)initWithName:(NSString*)labelPrefix
219238
name:NSCurrentLocaleDidChangeNotification
220239
object:nil];
221240

241+
_platformViewController = [[FlutterPlatformViewController alloc] init];
242+
[self setupPlatformViewChannel];
243+
222244
return self;
223245
}
224246

@@ -383,8 +405,8 @@ - (FlutterCompositor*)createFlutterCompositor {
383405

384406
if ([FlutterRenderingBackend renderUsingMetal]) {
385407
FlutterMetalRenderer* metalRenderer = reinterpret_cast<FlutterMetalRenderer*>(_renderer);
386-
_macOSCompositor =
387-
std::make_unique<flutter::FlutterMetalCompositor>(_viewController, metalRenderer.device);
408+
_macOSCompositor = std::make_unique<flutter::FlutterMetalCompositor>(
409+
_viewController, _platformViewController, metalRenderer.device);
388410
_macOSCompositor->SetPresentCallback([weakSelf](bool has_flutter_content) {
389411
if (has_flutter_content) {
390412
FlutterMetalRenderer* metalRenderer =
@@ -541,6 +563,10 @@ - (void)dispatchSemanticsAction:(FlutterSemanticsAction)action
541563
_embedderAPI.DispatchSemanticsAction(_engine, target, action, data.GetMapping(), data.GetSize());
542564
}
543565

566+
- (FlutterPlatformViewController*)platformViewController {
567+
return _platformViewController;
568+
}
569+
544570
#pragma mark - Private methods
545571

546572
- (void)sendUserLocales {
@@ -630,6 +656,18 @@ - (void)shutDownEngine {
630656
_engine = nullptr;
631657
}
632658

659+
- (void)setupPlatformViewChannel {
660+
_platformViewsChannel =
661+
[FlutterMethodChannel methodChannelWithName:@"flutter/platform_views"
662+
binaryMessenger:self.binaryMessenger
663+
codec:[FlutterStandardMethodCodec sharedInstance]];
664+
665+
__weak FlutterEngine* weakSelf = self;
666+
[_platformViewsChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
667+
[[weakSelf platformViewController] handleMethodCall:call result:result];
668+
}];
669+
}
670+
633671
#pragma mark - FlutterBinaryMessenger
634672

635673
- (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
@@ -781,20 +819,22 @@ - (void)updateSemanticsCustomActions:(const FlutterSemanticsCustomAction*)action
781819

782820
#pragma mark - Task runner integration
783821

784-
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
785-
const auto engine_time = _embedderAPI.GetCurrentTime();
822+
- (void)runTaskOnEmbedder:(FlutterTask)task {
823+
if (_engine) {
824+
auto result = _embedderAPI.RunTask(_engine, &task);
825+
if (result != kSuccess) {
826+
NSLog(@"Could not post a task to the Flutter engine.");
827+
}
828+
}
829+
}
786830

787-
__weak FlutterEngine* weak_self = self;
831+
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
832+
__weak FlutterEngine* weakSelf = self;
788833
auto worker = ^{
789-
FlutterEngine* strong_self = weak_self;
790-
if (strong_self && strong_self->_engine) {
791-
auto result = _embedderAPI.RunTask(strong_self->_engine, &task);
792-
if (result != kSuccess) {
793-
NSLog(@"Could not post a task to the Flutter engine.");
794-
}
795-
}
834+
[weakSelf runTaskOnEmbedder:task];
796835
};
797836

837+
const auto engine_time = _embedderAPI.GetCurrentTime();
798838
if (targetTime <= engine_time) {
799839
dispatch_async(dispatch_get_main_queue(), worker);
800840

shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "flutter/shell/platform/common/accessibility_bridge.h"
1212
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
13+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
1314
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h"
1415

1516
@interface FlutterEngine ()
@@ -70,6 +71,8 @@
7071
*/
7172
- (BOOL)unregisterTextureWithID:(int64_t)textureID;
7273

74+
- (nonnull FlutterPlatformViewController*)platformViewController;
75+
7376
// Accessibility API.
7477

7578
/**

shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
#include "flutter/fml/macros.h"
99
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
10+
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
1011

1112
namespace flutter {
1213

1314
class FlutterMetalCompositor : public FlutterCompositor {
1415
public:
15-
explicit FlutterMetalCompositor(FlutterViewController* view_controller,
16-
id<MTLDevice> mtl_device);
16+
explicit FlutterMetalCompositor(
17+
FlutterViewController* view_controller,
18+
FlutterPlatformViewController* platform_views_controller,
19+
id<MTLDevice> mtl_device);
1720

1821
virtual ~FlutterMetalCompositor() = default;
1922

@@ -42,7 +45,12 @@ class FlutterMetalCompositor : public FlutterCompositor {
4245
bool Present(const FlutterLayer** layers, size_t layers_count) override;
4346

4447
private:
48+
// Presents the platform view layer represented by `layer`. `layer_index` is
49+
// used to position the layer in the z-axis.
50+
void PresentPlatformView(const FlutterLayer* layer, size_t layer_index);
51+
4552
const id<MTLDevice> mtl_device_;
53+
const FlutterPlatformViewController* platform_views_controller_;
4654

4755
FML_DISALLOW_COPY_AND_ASSIGN(FlutterMetalCompositor);
4856
};

shell/platform/darwin/macos/framework/Source/FlutterMetalCompositor.mm

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010

1111
namespace flutter {
1212

13-
FlutterMetalCompositor::FlutterMetalCompositor(FlutterViewController* view_controller,
14-
id<MTLDevice> mtl_device)
15-
: FlutterCompositor(view_controller), mtl_device_(mtl_device) {}
13+
FlutterMetalCompositor::FlutterMetalCompositor(
14+
FlutterViewController* view_controller,
15+
FlutterPlatformViewController* platform_views_controller,
16+
id<MTLDevice> mtl_device)
17+
: FlutterCompositor(view_controller),
18+
mtl_device_(mtl_device),
19+
platform_views_controller_(platform_views_controller) {}
1620

1721
bool FlutterMetalCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
1822
FlutterBackingStore* backing_store_out) {
@@ -77,7 +81,6 @@
7781
SetFrameStatus(FrameStatus::kPresenting);
7882

7983
bool has_flutter_content = false;
80-
8184
for (size_t i = 0; i < layers_count; ++i) {
8285
const auto* layer = layers[i];
8386
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
@@ -94,13 +97,32 @@
9497
break;
9598
}
9699
case kFlutterLayerContentTypePlatformView:
97-
// Add functionality in follow up PR.
98-
FML_LOG(WARNING) << "Presenting PlatformViews not yet supported";
100+
PresentPlatformView(layer, i);
99101
break;
100102
};
101103
}
102104

103105
return EndFrame(has_flutter_content);
104106
}
105107

108+
void FlutterMetalCompositor::PresentPlatformView(const FlutterLayer* layer, size_t layer_position) {
109+
// TODO (https://github.com/flutter/flutter/issues/96668)
110+
FML_DCHECK([[NSThread currentThread] isMainThread])
111+
<< "Must be on the main thread to handle presenting platform views";
112+
113+
int64_t platform_view_id = layer->platform_view->identifier;
114+
NSView* platform_view = [platform_views_controller_ platformViewWithID:platform_view_id];
115+
116+
FML_DCHECK(platform_view) << "Platform view not found for id: " << platform_view_id;
117+
118+
CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];
119+
platform_view.frame = CGRectMake(layer->offset.x / scale, layer->offset.y / scale,
120+
layer->size.width / scale, layer->size.height / scale);
121+
if (platform_view.superview == nil) {
122+
[view_controller_.flutterView addSubview:platform_view];
123+
} else {
124+
platform_view.layer.zPosition = layer_position;
125+
}
126+
}
127+
106128
} // namespace flutter

0 commit comments

Comments
 (0)