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