Flutter Engine
The Flutter Engine
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) {
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];
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 }
171}
172
173@end
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
std::unique_ptr< flutter::PlatformViewIOS > platform_view
std::map< int, NSView * > _platformViews
std::unordered_set< int64_t > _platformViewsToDispose
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
HWND(* FlutterPlatformViewFactory)(const FlutterPlatformViewCreationParameters *)
#define FML_DCHECK(condition)
Definition: logging.h:103
Win32Message message
static bool init()
def call(args)
Definition: dom.py:159