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