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 FlutterChannelBuffersChannel = @"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:FlutterChannelBuffersChannel message:message];
17 }
18 
19 @implementation FlutterBasicMessageChannel {
20  NSObject<FlutterBinaryMessenger>* _messenger;
21  NSString* _name;
22  NSObject<FlutterMessageCodec>* _codec;
24 }
25 + (instancetype)messageChannelWithName:(NSString*)name
26  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
27  NSObject<FlutterMessageCodec>* codec = [FlutterStandardMessageCodec sharedInstance];
29  binaryMessenger:messenger
30  codec:codec];
31 }
32 + (instancetype)messageChannelWithName:(NSString*)name
33  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
34  codec:(NSObject<FlutterMessageCodec>*)codec {
35  return [[[FlutterBasicMessageChannel alloc] initWithName:name
36  binaryMessenger:messenger
37  codec:codec] autorelease];
38 }
39 
40 - (instancetype)initWithName:(NSString*)name
41  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
42  codec:(NSObject<FlutterMessageCodec>*)codec {
43  self = [super init];
44  NSAssert(self, @"Super init cannot be nil");
45  _name = [name retain];
46  _messenger = [messenger retain];
47  _codec = [codec retain];
48  return self;
49 }
50 
51 - (void)dealloc {
52  [_name release];
53  [_messenger release];
54  [_codec release];
55  [super dealloc];
56 }
57 
58 - (void)sendMessage:(id)message {
59  [_messenger sendOnChannel:_name message:[_codec encode:message]];
60 }
61 
62 - (void)sendMessage:(id)message reply:(FlutterReply)callback {
63  FlutterBinaryReply reply = ^(NSData* data) {
64  if (callback)
65  callback([_codec decode:data]);
66  };
67  [_messenger sendOnChannel:_name message:[_codec encode:message] binaryReply:reply];
68 }
69 
70 - (void)setMessageHandler:(FlutterMessageHandler)handler {
71  if (!handler) {
72  if (_connection > 0) {
73  [_messenger cleanupConnection:_connection];
74  _connection = 0;
75  } else {
76  [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
77  }
78  return;
79  }
80  // Grab reference to avoid retain on self.
81  NSObject<FlutterMessageCodec>* codec = _codec;
82  FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
83  handler([codec decode:message], ^(id reply) {
84  callback([codec encode:reply]);
85  });
86  };
87  _connection = [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
88 }
89 
90 - (void)resizeChannelBuffer:(NSInteger)newSize {
91  ResizeChannelBuffer(_messenger, _name, newSize);
92 }
93 
94 @end
95 
96 #pragma mark - Method channel
97 
98 @implementation FlutterError
99 + (instancetype)errorWithCode:(NSString*)code message:(NSString*)message details:(id)details {
100  return [[[FlutterError alloc] initWithCode:code message:message details:details] autorelease];
101 }
102 
103 - (instancetype)initWithCode:(NSString*)code message:(NSString*)message details:(id)details {
104  NSAssert(code, @"Code cannot be nil");
105  self = [super init];
106  NSAssert(self, @"Super init cannot be nil");
107  _code = [code retain];
108  _message = [message retain];
109  _details = [details retain];
110  return self;
111 }
112 
113 - (void)dealloc {
114  [_code release];
115  [_message release];
116  [_details release];
117  [super dealloc];
118 }
119 
120 - (BOOL)isEqual:(id)object {
121  if (self == object)
122  return YES;
123  if (![object isKindOfClass:[FlutterError class]])
124  return NO;
125  FlutterError* other = (FlutterError*)object;
126  return [self.code isEqual:other.code] &&
127  ((!self.message && !other.message) || [self.message isEqual:other.message]) &&
128  ((!self.details && !other.details) || [self.details isEqual:other.details]);
129 }
130 
131 - (NSUInteger)hash {
132  return [self.code hash] ^ [self.message hash] ^ [self.details hash];
133 }
134 @end
135 
136 @implementation FlutterMethodCall
137 + (instancetype)methodCallWithMethodName:(NSString*)method arguments:(id)arguments {
138  return [[[FlutterMethodCall alloc] initWithMethodName:method arguments:arguments] autorelease];
139 }
140 
141 - (instancetype)initWithMethodName:(NSString*)method arguments:(id)arguments {
142  NSAssert(method, @"Method name cannot be nil");
143  self = [super init];
144  NSAssert(self, @"Super init cannot be nil");
145  _method = [method retain];
146  _arguments = [arguments retain];
147  return self;
148 }
149 
150 - (void)dealloc {
151  [_method release];
152  [_arguments release];
153  [super dealloc];
154 }
155 
156 - (BOOL)isEqual:(id)object {
157  if (self == object)
158  return YES;
159  if (![object isKindOfClass:[FlutterMethodCall class]])
160  return NO;
161  FlutterMethodCall* other = (FlutterMethodCall*)object;
162  return [self.method isEqual:[other method]] &&
163  ((!self.arguments && !other.arguments) || [self.arguments isEqual:other.arguments]);
164 }
165 
166 - (NSUInteger)hash {
167  return [self.method hash] ^ [self.arguments hash];
168 }
169 @end
170 
171 NSObject const* FlutterMethodNotImplemented = [NSObject new];
172 
173 @implementation FlutterMethodChannel {
174  NSObject<FlutterBinaryMessenger>* _messenger;
175  NSString* _name;
176  NSObject<FlutterMethodCodec>* _codec;
178 }
179 
180 + (instancetype)methodChannelWithName:(NSString*)name
181  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
182  NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
183  return [FlutterMethodChannel methodChannelWithName:name binaryMessenger:messenger codec:codec];
184 }
185 
186 + (instancetype)methodChannelWithName:(NSString*)name
187  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
188  codec:(NSObject<FlutterMethodCodec>*)codec {
189  return [[[FlutterMethodChannel alloc] initWithName:name binaryMessenger:messenger
190  codec:codec] autorelease];
191 }
192 
193 - (instancetype)initWithName:(NSString*)name
194  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
195  codec:(NSObject<FlutterMethodCodec>*)codec {
196  self = [super init];
197  NSAssert(self, @"Super init cannot be nil");
198  _name = [name retain];
199  _messenger = [messenger retain];
200  _codec = [codec retain];
201  return self;
202 }
203 
204 - (void)dealloc {
205  [_name release];
206  [_messenger release];
207  [_codec release];
208  [super dealloc];
209 }
210 
211 - (void)invokeMethod:(NSString*)method arguments:(id)arguments {
213  arguments:arguments];
214  NSData* message = [_codec encodeMethodCall:methodCall];
215  [_messenger sendOnChannel:_name message:message];
216 }
217 
218 - (void)invokeMethod:(NSString*)method arguments:(id)arguments result:(FlutterResult)callback {
220  arguments:arguments];
221  NSData* message = [_codec encodeMethodCall:methodCall];
222  FlutterBinaryReply reply = ^(NSData* data) {
223  if (callback) {
224  callback((data == nil) ? FlutterMethodNotImplemented : [_codec decodeEnvelope:data]);
225  }
226  };
227  [_messenger sendOnChannel:_name message:message binaryReply:reply];
228 }
229 
230 - (void)setMethodCallHandler:(FlutterMethodCallHandler)handler {
231  if (!handler) {
232  if (_connection > 0) {
233  [_messenger cleanupConnection:_connection];
234  _connection = 0;
235  } else {
236  [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
237  }
238  return;
239  }
240  // Make sure the block captures the codec, not self.
241  NSObject<FlutterMethodCodec>* codec = _codec;
242  FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
243  FlutterMethodCall* call = [codec decodeMethodCall:message];
244  handler(call, ^(id result) {
245  if (result == FlutterMethodNotImplemented)
246  callback(nil);
247  else if ([result isKindOfClass:[FlutterError class]])
248  callback([codec encodeErrorEnvelope:(FlutterError*)result]);
249  else
250  callback([codec encodeSuccessEnvelope:result]);
251  });
252  };
253  _connection = [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler];
254 }
255 
256 - (void)resizeChannelBuffer:(NSInteger)newSize {
257  ResizeChannelBuffer(_messenger, _name, newSize);
258 }
259 
260 @end
261 
262 #pragma mark - Event channel
263 
264 NSObject const* FlutterEndOfEventStream = [NSObject new];
265 
266 @implementation FlutterEventChannel {
267  NSObject<FlutterBinaryMessenger>* _messenger;
268  NSString* _name;
269  NSObject<FlutterMethodCodec>* _codec;
270 }
271 + (instancetype)eventChannelWithName:(NSString*)name
272  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
273  NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
274  return [FlutterEventChannel eventChannelWithName:name binaryMessenger:messenger codec:codec];
275 }
276 
277 + (instancetype)eventChannelWithName:(NSString*)name
278  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
279  codec:(NSObject<FlutterMethodCodec>*)codec {
280  return [[[FlutterEventChannel alloc] initWithName:name binaryMessenger:messenger
281  codec:codec] autorelease];
282 }
283 
284 - (instancetype)initWithName:(NSString*)name
285  binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
286  codec:(NSObject<FlutterMethodCodec>*)codec {
287  self = [super init];
288  NSAssert(self, @"Super init cannot be nil");
289  _name = [name retain];
290  _messenger = [messenger retain];
291  _codec = [codec retain];
292  return self;
293 }
294 
295 - (void)dealloc {
296  [_name release];
297  [_codec release];
298  [_messenger release];
299  [super dealloc];
300 }
301 
302 static void SetStreamHandlerMessageHandlerOnChannel(NSObject<FlutterStreamHandler>* handler,
303  NSString* name,
304  NSObject<FlutterBinaryMessenger>* messenger,
305  NSObject<FlutterMethodCodec>* codec) {
306  __block FlutterEventSink currentSink = nil;
307  FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
308  FlutterMethodCall* call = [codec decodeMethodCall:message];
309  if ([call.method isEqual:@"listen"]) {
310  if (currentSink) {
311  FlutterError* error = [handler onCancelWithArguments:nil];
312  if (error)
313  NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message,
314  error.details);
315  }
316  currentSink = ^(id event) {
318  [messenger sendOnChannel:name message:nil];
319  else if ([event isKindOfClass:[FlutterError class]])
320  [messenger sendOnChannel:name message:[codec encodeErrorEnvelope:(FlutterError*)event]];
321  else
322  [messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]];
323  };
324  FlutterError* error = [handler onListenWithArguments:call.arguments eventSink:currentSink];
325  if (error)
326  callback([codec encodeErrorEnvelope:error]);
327  else
328  callback([codec encodeSuccessEnvelope:nil]);
329  } else if ([call.method isEqual:@"cancel"]) {
330  if (!currentSink) {
331  callback(
332  [codec encodeErrorEnvelope:[FlutterError errorWithCode:@"error"
333  message:@"No active stream to cancel"
334  details:nil]]);
335  return;
336  }
337  currentSink = nil;
338  FlutterError* error = [handler onCancelWithArguments:call.arguments];
339  if (error)
340  callback([codec encodeErrorEnvelope:error]);
341  else
342  callback([codec encodeSuccessEnvelope:nil]);
343  } else {
344  callback(nil);
345  }
346  };
347  [messenger setMessageHandlerOnChannel:name binaryMessageHandler:messageHandler];
348 }
349 
350 - (void)setStreamHandler:(NSObject<FlutterStreamHandler>*)handler {
351  if (!handler) {
352  [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
353  return;
354  }
355  SetStreamHandlerMessageHandlerOnChannel(handler, _name, _messenger, _codec);
356 }
357 @end
NSString * code
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)
FlMethodResponse GError ** error
void(^ FlutterMethodCallHandler)(FlutterMethodCall *call, FlutterResult result)
static void ResizeChannelBuffer(NSObject< FlutterBinaryMessenger > *binaryMessenger, NSString *channel, NSInteger newSize)
NSString * _name
FlutterBinaryMessengerConnection _connection
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
instancetype sharedInstance()
NSString * message
void(^ FlutterEventSink)(id _Nullable event)
NSObject const * FlutterEndOfEventStream
void(^ FlutterMessageHandler)(id _Nullable message, FlutterReply callback)
void(^ FlutterResult)(id _Nullable result)
static NSString *const FlutterChannelBuffersChannel
GdkEventButton * event
Definition: fl_view.cc:62
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterReply)(id _Nullable reply)
instancetype methodCallWithMethodName:arguments:(NSString *method, [arguments] id _Nullable arguments)
const char * name
Definition: fuchsia.cc:50
NSObject< FlutterMessageCodec > * _codec
int32_t id
int64_t FlutterBinaryMessengerConnection