Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
6
8
9#pragma mark - Basic message channel
10
11static NSString* const kFlutterChannelBuffersChannel = @"dev.flutter/channel-buffers";
12static NSString* const kResizeMethod = @"resize";
13static NSString* const kOverflowMethod = @"overflow";
14
15static 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 */
39static 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
51 NSObject<FlutterBinaryMessenger>* messenger,
52 NSString* name,
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;
75 NSObject<FlutterTaskQueue>* _taskQueue;
76}
77+ (instancetype)messageChannelWithName:(NSString*)name
78 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
79 NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
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;
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
238NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
239
240////////////////////////////////////////////////////////////////////////////////
241@implementation FlutterMethodChannel {
242 NSObject<FlutterBinaryMessenger>* _messenger;
243 NSString* _name;
244 NSObject<FlutterMethodCodec>* _codec;
246 NSObject<FlutterTaskQueue>* _taskQueue;
247}
248
249+ (instancetype)methodChannelWithName:(NSString*)name
250 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
251 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
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 {
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 {
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;
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
336NSObject 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;
345}
346+ (instancetype)eventChannelWithName:(NSString*)name
347 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
348 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
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
377static 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;
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 }
438 SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec, _taskQueue);
439}
440@end
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
void(^ FlutterMethodCallHandler)(FlutterMethodCall *call, FlutterResult result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
void(^ FlutterMessageHandler)(id _Nullable message, FlutterReply callback)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterEndOfEventStream
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterReply)(id _Nullable reply)
void(^ FlutterEventSink)(id _Nullable event)
static NSString *const kOverflowMethod
FlutterBinaryMessengerConnection _connection
NSString * _name
static void SetWarnsOnOverflow(NSObject< FlutterBinaryMessenger > *binaryMessenger, NSString *channel, BOOL warns)
static FlutterBinaryMessengerConnection SetMessageHandler(NSObject< FlutterBinaryMessenger > *messenger, NSString *name, FlutterBinaryMessageHandler handler, NSObject< FlutterTaskQueue > *taskQueue)
NSObject< FlutterMessageCodec > * _codec
NSObject< FlutterTaskQueue > * _taskQueue
static void ResizeChannelBuffer(NSObject< FlutterBinaryMessenger > *binaryMessenger, NSString *channel, NSInteger newSize)
static NSString *const kResizeMethod
static FLUTTER_ASSERT_ARC NSString *const kFlutterChannelBuffersChannel
const char * message
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar * channel
const gchar FlBinaryMessengerMessageHandler handler
const uint8_t uint32_t uint32_t GError ** error
FlutterDesktopBinaryReply callback
const char * name
Definition fuchsia.cc:50
instancetype messageChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMessageCodec > *codec)
NSString * message
NSString * code
instancetype eventChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
instancetype sharedInstance()
const uintptr_t id
int BOOL