Flutter Engine
The Flutter Engine
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
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/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 */
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([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;
73 NSObject<FlutterTaskQueue>* _taskQueue;
74}
75+ (instancetype)messageChannelWithName:(NSString*)name
76 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
77 NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
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) {
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;
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
236NSObject const* FlutterMethodNotImplemented = [[NSObject alloc] init];
237
238////////////////////////////////////////////////////////////////////////////////
239@implementation FlutterMethodChannel {
240 NSObject<FlutterBinaryMessenger>* _messenger;
241 NSString* _name;
242 NSObject<FlutterMethodCodec>* _codec;
244 NSObject<FlutterTaskQueue>* _taskQueue;
245}
246
247+ (instancetype)methodChannelWithName:(NSString*)name
248 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
249 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
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 {
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 {
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;
312 FlutterMethodCall* call = [codec decodeMethodCall:message];
313 handler(call, ^(id result) {
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
334NSObject 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;
343}
344+ (instancetype)eventChannelWithName:(NSString*)name
345 binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
346 NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
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
375static 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;
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) {
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 }
436 SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec, _taskQueue);
437}
438@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
static void encode(uint8_t output[16], const uint32_t input[4])
Definition: SkMD5.cpp:240
static uint32_t hash(const SkShaderBase::GradientInfo &v)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
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)
Win32Message message
def call(args)
Definition: dom.py:159
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
int BOOL
Definition: windows_types.h:37