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