| Flutter macOS Embedder |

FlutterPlatformViewController.mm
Go to the documentation of this file.
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 #include "flutter/fml/logging.h"
6
7 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
8
9 @implementation FlutterPlatformViewController {
10 // NSDictionary maps platform view type identifiers to FlutterPlatformViewFactories.
11 NSMutableDictionary<NSString*, NSObject<FlutterPlatformViewFactory>*>* _platformViewFactories;
12
13 // Map from platform view id to the underlying NSView.
14 std::map<int, NSView*> _platformViews;
15
16 // View ids that are going to be disposed on the next present call.
17 std::unordered_set<int64_t> _platformViewsToDispose;
18 }
19
20 - (instancetype)init {
21 self = [super init];
22 if (self) {
23 _platformViewFactories = [[NSMutableDictionary alloc] init];
24 }
25 return self;
26 }
27
28 - (void)onCreateWithViewIdentifier:(int64_t)viewId
29 viewType:(nonnull NSString*)viewType
30 arguments:(nullable id)args
31 result:(nonnull FlutterResult)result {
32 if (_platformViews.count(viewId) != 0) {
33 result([FlutterError errorWithCode:@"recreating_view"
34 message:@"trying to create an already created view"
35 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
36 return;
37 }
38
39 NSObject<FlutterPlatformViewFactory>* factory = _platformViewFactories[viewType];
40 if (!factory) {
41 result([FlutterError
42 errorWithCode:@"unregistered_view_type"
43 message:[NSString stringWithFormat:@"A UIKitView widget is trying to create a "
44 @"PlatformView with an unregistered type: < %@ >",
45 viewType]
46 details:@"If you are the author of the PlatformView, make sure `registerViewFactory` "
47 @"is invoked.\n"
48 @"See: "
49 @"https://docs.flutter.dev/development/platform-integration/"
50 @"platform-views#on-the-platform-side-1 for more details.\n"
51 @"If you are not the author of the PlatformView, make sure to call "
52 @"`GeneratedPluginRegistrant.register`."]);
53 return;
54 }
55
56 NSView* platform_view = [factory createWithViewIdentifier:viewId arguments:args];
57 // Flutter compositing requires CALayer-backed platform views.
58 // Force the platform view to be backed by a CALayer.
59 [platform_view setWantsLayer:YES];
60 _platformViews[viewId] = platform_view;
61 result(nil);
62 }
63
64 - (void)onDisposeWithViewID:(int64_t)viewId result:(nonnull FlutterResult)result {
65 if (_platformViews.count(viewId) == 0) {
66 result([FlutterError errorWithCode:@"unknown_view"
67 message:@"trying to dispose an unknown"
68 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
69 return;
70 }
71
72 // The following disposePlatformViews call will dispose the views.
73 _platformViewsToDispose.insert(viewId);
74 result(nil);
75 }
76
77 - (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory>*)factory
78 withId:(nonnull NSString*)factoryId {
79 _platformViewFactories[factoryId] = factory;
80 }
81
82 - (nullable NSView*)platformViewWithID:(int64_t)viewId {
83 if (_platformViews.count(viewId)) {
84 return _platformViews[viewId];
85 } else {
86 return nil;
87 }
88 }
89
90 - (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result {
91 if ([[call method] isEqualToString:@"create"]) {
92 NSMutableDictionary<NSString*, id>* args = [call arguments];
93 if ([args objectForKey:@"id"]) {
94 int64_t viewId = [args[@"id"] longLongValue];
95 NSString* viewType = [NSString stringWithUTF8String:([args[@"viewType"] UTF8String])];
96
97 id creationArgs = nil;
98 NSObject<FlutterPlatformViewFactory>* factory = _platformViewFactories[viewType];
99 if ([factory respondsToSelector:@selector(createArgsCodec)]) {
100 NSObject<FlutterMessageCodec>* codec = [factory createArgsCodec];
101 if (codec != nil && args[@"params"] != nil) {
102 FlutterStandardTypedData* creationArgsData = args[@"params"];
103 creationArgs = [codec decode:creationArgsData.data];
104 }
105 }
106 [self onCreateWithViewIdentifier:viewId
107 viewType:viewType
108 arguments:creationArgs
109 result:result];
110 } else {
111 result([FlutterError errorWithCode:@"unknown_view"
112 message:@"'id' argument must be passed to create a platform view."
113 details:[NSString stringWithFormat:@"'id' not specified."]]);
114 }
115 } else if ([[call method] isEqualToString:@"dispose"]) {
116 NSNumber* arg = [call arguments];
117 int64_t viewId = [arg longLongValue];
118 [self onDisposeWithViewID:viewId result:result];
119 } else if ([[call method] isEqualToString:@"acceptGesture"]) {
120 [self handleAcceptGesture:call result:result];
121 } else if ([[call method] isEqualToString:@"rejectGesture"]) {
122 [self handleRejectGesture:call result:result];
123 } else {
124 result(FlutterMethodNotImplemented);
125 }
126 }
127
128 - (void)handleAcceptGesture:(FlutterMethodCall*)call result:(FlutterResult)result {
129 NSDictionary<NSString*, id>* args = [call arguments];
130 NSAssert(args && args[@"id"], @"id argument is required");
131 int64_t viewId = [args[@"id"] longLongValue];
132 if (_platformViews.count(viewId) == 0) {
133 result([FlutterError errorWithCode:@"unknown_view"
134 message:@"trying to set gesture state for an unknown view"
135 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
136 return;
137 }
138
139 // TODO(cbracken): Implement. https://github.com/flutter/flutter/issues/124492
140 result(nil);
141 }
142
143 - (void)handleRejectGesture:(FlutterMethodCall*)call result:(FlutterResult)result {
144 NSDictionary<NSString*, id>* args = [call arguments];
145 NSAssert(args && args[@"id"], @"id argument is required");
146 int64_t viewId = [args[@"id"] longLongValue];
147 if (_platformViews.count(viewId) == 0) {
148 result([FlutterError errorWithCode:@"unknown_view"
149 message:@"trying to set gesture state for an unknown view"
150 details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
151 return;
152 }
153
154 // TODO(cbracken): Implement. https://github.com/flutter/flutter/issues/124492
155 result(nil);
156 }
157
158 - (void)disposePlatformViews {
159 if (_platformViewsToDispose.empty()) {
160 return;
161 }
162
163 FML_DCHECK([[NSThread currentThread] isMainThread])
164 << "Must be on the main thread to handle disposing platform views";
165 for (int64_t viewId : _platformViewsToDispose) {
166 NSView* view = _platformViews[viewId];
167 [view removeFromSuperview];
168 _platformViews.erase(viewId);
169 }
170 _platformViewsToDispose.clear();
171 }
172
173 - (void)reset {
174 for (const auto& pair : _platformViews) {
175 _platformViewsToDispose.insert(pair.first);
176 }
177 [self disposePlatformViews];
178 }
179
180 @end
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterPlatformViewController.h
_platformViews
std::map< int, NSView * > _platformViews
Definition: FlutterPlatformViewController.mm:9
_platformViewsToDispose
std::unordered_set< int64_t > _platformViewsToDispose
Definition: FlutterPlatformViewController.mm:17
FlutterError
Definition: FlutterCodecs.h:247
FlutterMethodCall
Definition: FlutterCodecs.h:221
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238
FlutterPlatformViewController
Definition: FlutterPlatformViewController.h:18
FlutterStandardTypedData
Definition: FlutterCodecs.h:301
FlutterPlatformViewFactory-p
Definition: FlutterPlatformViews.h:13