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