| Flutter macOS Embedder |

FlutterChannels.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 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
6
7 FLUTTER_ASSERT_ARC
8
9 #pragma mark - Basic message channel
10
11 static NSString* const kFlutterChannelBuffersChannel = @"dev.flutter/channel-buffers";
12 static NSString* const kResizeMethod = @"resize";
13 static NSString* const kOverflowMethod = @"overflow";
14
15 static void ResizeChannelBuffer(NSObject<FlutterBinaryMessenger>* binaryMessenger,
16 NSString* channel,
17 NSInteger newSize) {
18 NSCAssert(newSize >= 0, @"Channel buffer size must be non-negative");
19 // Cast newSize to int because the deserialization logic handles only 32 bits values,
20 // see
21 // https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L495.
22 NSArray* args = @[ channel, @(static_cast<int>(newSize)) ];
23 FlutterMethodCall* resizeMethodCall = [FlutterMethodCall methodCallWithMethodName:kResizeMethod
24 arguments:args];
25 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
26 NSData* message = [codec encodeMethodCall:resizeMethodCall];
27 [binaryMessenger sendOnChannel:kFlutterChannelBuffersChannel message:message];
28 }
29
30 /**
31 * Defines whether a channel should show warning messages when discarding messages
32 * due to overflow.
33 *
34 * @param binaryMessenger The binary messenger.
35 * @param channel The channel name.
36 * @param warns When false, the channel is expected to overflow and warning messages
37 * will not be shown.
38 */
39 static void SetWarnsOnOverflow(NSObject<FlutterBinaryMessenger>* binaryMessenger,
40 NSString* channel,
41 BOOL warns) {
42 FlutterMethodCall* overflowMethodCall =
43 [FlutterMethodCall methodCallWithMethodName:kOverflowMethod
44 arguments:@[ channel, @(!warns) ]];
45 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
46 NSData* message = [codec encodeMethodCall:overflowMethodCall];
47 [binaryMessenger sendOnChannel:kFlutterChannelBuffersChannel message:message];
48 }
49
50 static FlutterBinaryMessengerConnection SetMessageHandler(
51 NSObject<FlutterBinaryMessenger>* messenger,
52 NSString* name,
53 FlutterBinaryMessageHandler handler,
54 NSObject<FlutterTaskQueue>* taskQueue) {
55 if (taskQueue) {
56 NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:
57 binaryMessageHandler:taskQueue:)],
58 @"");
59 return [messenger setMessageHandlerOnChannel:name
60 binaryMessageHandler:handler
61 taskQueue:taskQueue];
62 } else {
63 return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];
64 }
65 }
66
67 ////////////////////////////////////////////////////////////////////////////////
68 @implementation FlutterBasicMessageChannel {
69 NSObject<FlutterBinaryMessenger>* _messenger;
70 NSString* _name;
71 NSObject<FlutterMessageCodec>* _codec;
72 FlutterBinaryMessengerConnection _connection;
73 NSObject<FlutterTaskQueue>* _taskQueue;
74 }
75 + (instancetype)messageChannelWithName:(NSString*)name
76 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
77 NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
78 return [FlutterBasicMessageChannel messageChannelWithName:name
79 binaryMessenger:messenger
80 codec:codec];
81 }
82 + (instancetype)messageChannelWithName:(NSString*)name
83 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
84 codec:(NSObject<FlutterMessageCodec>*)codec {
85 return [[FlutterBasicMessageChannel alloc] initWithName:name
86 binaryMessenger:messenger
87 codec:codec];
88 }
89
90 - (instancetype)initWithName:(NSString*)name
91 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
92 codec:(NSObject<FlutterMessageCodec>*)codec {
93 self = [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
94 return self;
95 }
96
97 - (instancetype)initWithName:(NSString*)name
98 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
99 codec:(NSObject<FlutterMessageCodec>*)codec
100 taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
101 self = [super init];
102 NSAssert(self, @"Super init cannot be nil");
103 _name = [name copy];
104 _messenger = messenger;
105 _codec = codec;
106 _taskQueue = taskQueue;
107 return self;
108 }
109
110 - (void)sendMessage:(id)message {
111 [_messenger sendOnChannel:_name message:[_codec encode:message]];
112 }
113
114 - (void)sendMessage:(id)message reply:(FlutterReply)callback {
115 FlutterBinaryReply reply = ^(NSData* data) {
116 if (callback) {
117 callback([_codec decode:data]);
118 }
119 };
120 [_messenger sendOnChannel:_name message:[_codec encode:message] binaryReply:reply];
121 }
122
123 - (void)setMessageHandler:(FlutterMessageHandler)handler {
124 if (!handler) {
125 if (_connection > 0) {
126 [_messenger cleanUpConnection:_connection];
127 _connection = 0;
128 } else {
129 [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
130 }
131 return;
132 }
133
134 // Grab reference to avoid retain on self.
135 // `self` might be released before the block, so the block needs to retain the codec to
136 // make sure it is not released with `self`
137 NSObject<FlutterMessageCodec>* codec = _codec;
138 FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
139 handler([codec decode:message], ^(id reply) {
140 callback([codec encode:reply]);
141 });
142 };
143 _connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
144 }
145
146 + (void)resizeChannelWithName:(NSString*)name
147 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
148 size:(NSInteger)newSize {
149 ResizeChannelBuffer(messenger, name, newSize);
150 }
151
152 - (void)resizeChannelBuffer:(NSInteger)newSize {
153 ResizeChannelBuffer(_messenger, _name, newSize);
154 }
155
156 + (void)setWarnsOnOverflow:(BOOL)warns
157 forChannelWithName:(NSString*)name
158 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
159 SetWarnsOnOverflow(messenger, name, warns);
160 }
161
162 - (void)setWarnsOnOverflow:(BOOL)warns {
163 SetWarnsOnOverflow(_messenger, _name, warns);
164 }
165
166 @end
167
168 #pragma mark - Method channel
169
170 ////////////////////////////////////////////////////////////////////////////////
171 @implementation FlutterError
172 + (instancetype)errorWithCode:(NSString*)code message:(NSString*)message details:(id)details {
173 return [[FlutterError alloc] initWithCode:code message:message details:details];
174 }
175
176 - (instancetype)initWithCode:(NSString*)code message:(NSString*)message details:(id)details {
177 NSAssert(code, @"Code cannot be nil");
178 self = [super init];
179 NSAssert(self, @"Super init cannot be nil");
180 _code = [code copy];
181 _message = [message copy];
182 _details = details;
183 return self;
184 }
185
186 - (BOOL)isEqual:(id)object {
187 if (self == object) {
188 return YES;
189 }
190 if (![object isKindOfClass:[FlutterError class]]) {
191 return NO;
192 }
193 FlutterError* other = (FlutterError*)object;
194 return [self.code isEqual:other.code] &&
195 ((!self.message && !other.message) || [self.message isEqual:other.message]) &&
196 ((!self.details && !other.details) || [self.details isEqual:other.details]);
197 }
198
199 - (NSUInteger)hash {
200 return [self.code hash] ^ [self.message hash] ^ [self.details hash];
201 }
202 @end
203
204 ////////////////////////////////////////////////////////////////////////////////
205 @implementation FlutterMethodCall
206 + (instancetype)methodCallWithMethodName:(NSString*)method arguments:(id)arguments {
207 return [[FlutterMethodCall alloc] initWithMethodName:method arguments:arguments];
208 }
209
210 - (instancetype)initWithMethodName:(NSString*)method arguments:(id)arguments {
211 NSAssert(method, @"Method name cannot be nil");
212 self = [super init];
213 NSAssert(self, @"Super init cannot be nil");
214 _method = [method copy];
215 _arguments = arguments;
216 return self;
217 }
218
219 - (BOOL)isEqual:(id)object {
220 if (self == object) {
221 return YES;
222 }
223 if (![object isKindOfClass:[FlutterMethodCall class]]) {
224 return NO;
225 }
226 FlutterMethodCall* other = (FlutterMethodCall*)object;
227 return [self.method isEqual:[other method]] &&
228 ((!self.arguments && !other.arguments) || [self.arguments isEqual:other.arguments]);
229 }
230
231 - (NSUInteger)hash {
232 return [self.method hash] ^ [self.arguments hash];
233 }
234 @end
235
236 NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
237
238 ////////////////////////////////////////////////////////////////////////////////
239 @implementation FlutterMethodChannel {
240 NSObject<FlutterBinaryMessenger>* _messenger;
241 NSString* _name;
242 NSObject<FlutterMethodCodec>* _codec;
243 FlutterBinaryMessengerConnection _connection;
244 NSObject<FlutterTaskQueue>* _taskQueue;
245 }
246
247 + (instancetype)methodChannelWithName:(NSString*)name
248 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
249 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
250 return [FlutterMethodChannel methodChannelWithName:name binaryMessenger:messenger codec:codec];
251 }
252
253 + (instancetype)methodChannelWithName:(NSString*)name
254 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
255 codec:(NSObject<FlutterMethodCodec>*)codec {
256 return [[FlutterMethodChannel alloc] initWithName:name binaryMessenger:messenger codec:codec];
257 }
258
259 - (instancetype)initWithName:(NSString*)name
260 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
261 codec:(NSObject<FlutterMethodCodec>*)codec {
262 self = [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
263 return self;
264 }
265 - (instancetype)initWithName:(NSString*)name
266 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
267 codec:(NSObject<FlutterMethodCodec>*)codec
268 taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
269 self = [super init];
270 NSAssert(self, @"Super init cannot be nil");
271 _name = [name copy];
272 _messenger = messenger;
273 _codec = codec;
274 _taskQueue = taskQueue;
275 return self;
276 }
277
278 - (void)invokeMethod:(NSString*)method arguments:(id)arguments {
279 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:method
280 arguments:arguments];
281 NSData* message = [_codec encodeMethodCall:methodCall];
282 [_messenger sendOnChannel:_name message:message];
283 }
284
285 - (void)invokeMethod:(NSString*)method arguments:(id)arguments result:(FlutterResult)callback {
286 FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:method
287 arguments:arguments];
288 NSData* message = [_codec encodeMethodCall:methodCall];
289 FlutterBinaryReply reply = ^(NSData* data) {
290 if (callback) {
291 callback((data == nil) ? FlutterMethodNotImplemented : [_codec decodeEnvelope:data]);
292 }
293 };
294 [_messenger sendOnChannel:_name message:message binaryReply:reply];
295 }
296
297 - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler {
298 if (!handler) {
299 if (_connection > 0) {
300 [_messenger cleanUpConnection:_connection];
301 _connection = 0;
302 } else {
303 [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
304 }
305 return;
306 }
307 // Make sure the block captures the codec, not self.
308 // `self` might be released before the block, so the block needs to retain the codec to
309 // make sure it is not released with `self`
310 NSObject<FlutterMethodCodec>* codec = _codec;
311 FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
312 FlutterMethodCall* call = [codec decodeMethodCall:message];
313 handler(call, ^(id result) {
314 if (result == FlutterMethodNotImplemented) {
315 callback(nil);
316 } else if ([result isKindOfClass:[FlutterError class]]) {
317 callback([codec encodeErrorEnvelope:(FlutterError*)result]);
318 } else {
319 callback([codec encodeSuccessEnvelope:result]);
320 }
321 });
322 };
323 _connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
324 }
325
326 - (void)resizeChannelBuffer:(NSInteger)newSize {
327 ResizeChannelBuffer(_messenger, _name, newSize);
328 }
329
330 @end
331
332 #pragma mark - Event channel
333
334 NSObject const* FlutterEndOfEventStream = [[NSObject alloc] init];
335
336 ////////////////////////////////////////////////////////////////////////////////
337 @implementation FlutterEventChannel {
338 NSObject<FlutterBinaryMessenger>* _messenger;
339 NSString* _name;
340 NSObject<FlutterMethodCodec>* _codec;
341 NSObject<FlutterTaskQueue>* _taskQueue;
342 FlutterBinaryMessengerConnection _connection;
343 }
344 + (instancetype)eventChannelWithName:(NSString*)name
345 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
346 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
347 return [FlutterEventChannel eventChannelWithName:name binaryMessenger:messenger codec:codec];
348 }
349
350 + (instancetype)eventChannelWithName:(NSString*)name
351 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
352 codec:(NSObject<FlutterMethodCodec>*)codec {
353 return [[FlutterEventChannel alloc] initWithName:name binaryMessenger:messenger codec:codec];
354 }
355
356 - (instancetype)initWithName:(NSString*)name
357 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
358 codec:(NSObject<FlutterMethodCodec>*)codec {
359 return [self initWithName:name binaryMessenger:messenger codec:codec taskQueue:nil];
360 }
361
362 - (instancetype)initWithName:(NSString*)name
363 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
364 codec:(NSObject<FlutterMethodCodec>*)codec
365 taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
366 self = [super init];
367 NSAssert(self, @"Super init cannot be nil");
368 _name = [name copy];
369 _messenger = messenger;
370 _codec = codec;
371 _taskQueue = taskQueue;
372 return self;
373 }
374
375 static FlutterBinaryMessengerConnection SetStreamHandlerMessageHandlerOnChannel(
376 NSObject<FlutterStreamHandler>* handler,
377 NSString* name,
378 NSObject<FlutterBinaryMessenger>* messenger,
379 NSObject<FlutterMethodCodec>* codec,
380 NSObject<FlutterTaskQueue>* taskQueue) {
381 __block FlutterEventSink currentSink = nil;
382 FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
383 FlutterMethodCall* call = [codec decodeMethodCall:message];
384 if ([call.method isEqual:@"listen"]) {
385 if (currentSink) {
386 FlutterError* error = [handler onCancelWithArguments:nil];
387 if (error) {
388 NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message,
389 error.details);
390 }
391 }
392 currentSink = ^(id event) {
393 if (event == FlutterEndOfEventStream) {
394 [messenger sendOnChannel:name message:nil];
395 } else if ([event isKindOfClass:[FlutterError class]]) {
396 [messenger sendOnChannel:name message:[codec encodeErrorEnvelope:(FlutterError*)event]];
397 } else {
398 [messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]];
399 }
400 };
401 FlutterError* error = [handler onListenWithArguments:call.arguments eventSink:currentSink];
402 if (error) {
403 callback([codec encodeErrorEnvelope:error]);
404 } else {
405 callback([codec encodeSuccessEnvelope:nil]);
406 }
407 } else if ([call.method isEqual:@"cancel"]) {
408 if (!currentSink) {
409 callback(
410 [codec encodeErrorEnvelope:[FlutterError errorWithCode:@"error"
411 message:@"No active stream to cancel"
412 details:nil]]);
413 return;
414 }
415 currentSink = nil;
416 FlutterError* error = [handler onCancelWithArguments:call.arguments];
417 if (error) {
418 callback([codec encodeErrorEnvelope:error]);
419 } else {
420 callback([codec encodeSuccessEnvelope:nil]);
421 }
422 } else {
423 callback(nil);
424 }
425 };
426 return SetMessageHandler(messenger, name, messageHandler, taskQueue);
427 }
428
429 - (void)setStreamHandler:(NSObject<FlutterStreamHandler>*)handler {
430 if (!handler) {
431 [_messenger cleanUpConnection:_connection];
432 _connection = 0;
433 return;
434 }
435 _connection =
436 SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec, _taskQueue);
437 }
438 @end
+[FlutterBasicMessageChannel messageChannelWithName:binaryMessenger:codec:]
instancetype messageChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMessageCodec > *codec)
Definition: FlutterChannels.mm:82
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterBasicMessageChannel
Definition: FlutterChannels.h:39
FlutterMethodChannel
Definition: FlutterChannels.h:222
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
kOverflowMethod
static NSString *const kOverflowMethod
Definition: FlutterChannels.mm:13
_codec
NSObject< FlutterMessageCodec > * _codec
Definition: FlutterChannels.mm:71
FlutterError
Definition: FlutterCodecs.h:246
FlutterChannels.h
FlutterMethodCall::method
NSString * method
Definition: FlutterCodecs.h:233
FlutterMethodCallHandler
void(^ FlutterMethodCallHandler)(FlutterMethodCall *call, FlutterResult result)
Definition: FlutterChannels.h:208
FlutterEventChannel
Definition: FlutterChannels.h:402
+[FlutterEventChannel eventChannelWithName:binaryMessenger:codec:]
instancetype eventChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
FlutterError::details
id details
Definition: FlutterCodecs.h:270
kResizeMethod
static NSString *const kResizeMethod
Definition: FlutterChannels.mm:12
FlutterEndOfEventStream
FLUTTER_DARWIN_EXPORT NSObject const * FlutterEndOfEventStream
FlutterBinaryMessageHandler
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
Definition: FlutterBinaryMessenger.h:30
FlutterStandardMessageCodec
Definition: FlutterCodecs.h:209
SetMessageHandler
static FlutterBinaryMessengerConnection SetMessageHandler(NSObject< FlutterBinaryMessenger > *messenger, NSString *name, FlutterBinaryMessageHandler handler, NSObject< FlutterTaskQueue > *taskQueue)
Definition: FlutterChannels.mm:50
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterError::message
NSString * message
Definition: FlutterCodecs.h:265
FlutterTaskQueue-p
Definition: FlutterBinaryMessengerRelayTest.mm:16
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:196
+[FlutterMethodChannel methodChannelWithName:binaryMessenger:codec:]
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
FlutterError::code
NSString * code
Definition: FlutterCodecs.h:260
-[FlutterBasicMessageChannel initWithName:binaryMessenger:codec:taskQueue:]
instancetype initWithName:binaryMessenger:codec:taskQueue:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMessageCodec > *codec,[taskQueue] NSObject< FlutterTaskQueue > *_Nullable taskQueue)
ResizeChannelBuffer
static void ResizeChannelBuffer(NSObject< FlutterBinaryMessenger > *binaryMessenger, NSString *channel, NSInteger newSize)
Definition: FlutterChannels.mm:15
FlutterReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterReply)(id _Nullable reply)
FlutterEventSink
void(^ FlutterEventSink)(id _Nullable event)
Definition: FlutterChannels.h:352
SetWarnsOnOverflow
static void SetWarnsOnOverflow(NSObject< FlutterBinaryMessenger > *binaryMessenger, NSString *channel, BOOL warns)
Definition: FlutterChannels.mm:39
_name
NSString * _name
Definition: FlutterChannels.mm:68
FlutterMessageCodec-p
Definition: FlutterCodecs.h:18
FlutterStreamHandler-p
Definition: FlutterChannels.h:358
FlutterMessageHandler
void(^ FlutterMessageHandler)(id _Nullable message, FlutterReply callback)
Definition: FlutterChannels.h:32
_taskQueue
NSObject< FlutterTaskQueue > * _taskQueue
Definition: FlutterChannels.mm:73
kFlutterChannelBuffersChannel
static FLUTTER_ASSERT_ARC NSString *const kFlutterChannelBuffersChannel
Definition: FlutterChannels.mm:11
FlutterBinaryMessenger-p
Definition: FlutterBinaryMessenger.h:48
_connection
FlutterBinaryMessengerConnection _connection
Definition: FlutterChannels.mm:72
FlutterStandardMethodCodec
Definition: FlutterCodecs.h:467
FlutterBinaryMessengerConnection
int64_t FlutterBinaryMessengerConnection
Definition: FlutterBinaryMessenger.h:32
FlutterBinaryReply
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()