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 
8 
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 {
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 @end
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
_platformViewsToDispose
std::unordered_set< int64_t > _platformViewsToDispose
Definition: FlutterPlatformViewController.mm:17
FlutterPlatformViewController
Definition: FlutterPlatformViewController.h:17
FlutterPlatformViewController.h
FlutterError
Definition: FlutterCodecs.h:246
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterPlatformViewFactory-p
Definition: FlutterPlatformViews.h:13
FlutterStandardTypedData
Definition: FlutterCodecs.h:300
_platformViews
std::map< int, NSView * > _platformViews
Definition: FlutterPlatformViewController.mm:9
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238