// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import "AppDelegate.h" #import "GeneratedPluginRegistrant.h" @interface Pair : NSObject @property(atomic, readonly, strong, nullable) NSObject* left; @property(atomic, readonly, strong, nullable) NSObject* right; - (instancetype)initWithLeft:(NSObject*)first right:(NSObject*)right; @end @implementation Pair - (instancetype)initWithLeft:(NSObject*)left right:(NSObject*)right { self = [super init]; _left = left; _right = right; return self; } @end const UInt8 DATE = 128; const UInt8 PAIR = 129; @interface ExtendedWriter : FlutterStandardWriter - (void)writeValue:(id)value; @end @implementation ExtendedWriter - (void)writeValue:(id)value { if ([value isKindOfClass:[NSDate class]]) { [self writeByte:DATE]; NSDate* date = value; NSTimeInterval time = date.timeIntervalSince1970; SInt64 ms = (SInt64) (time * 1000.0); [self writeBytes:&ms length:8]; } else if ([value isKindOfClass:[Pair class]]) { Pair* pair = value; [self writeByte:PAIR]; [self writeValue:pair.left]; [self writeValue:pair.right]; } else { [super writeValue:value]; } } @end @interface ExtendedReader : FlutterStandardReader - (id)readValueOfType:(UInt8)type; @end @implementation ExtendedReader - (id)readValueOfType:(UInt8)type { switch (type) { case DATE: { SInt64 value; [self readBytes:&value length:8]; NSTimeInterval time = [NSNumber numberWithLong:value].doubleValue / 1000.0; return [NSDate dateWithTimeIntervalSince1970:time]; } case PAIR: { return [[Pair alloc] initWithLeft:[self readValue] right:[self readValue]]; } default: return [super readValueOfType:type]; } } @end @interface ExtendedReaderWriter : FlutterStandardReaderWriter - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data; - (FlutterStandardReader*)readerWithData:(NSData*)data; @end @implementation ExtendedReaderWriter - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data { return [[ExtendedWriter alloc] initWithData:data]; } - (FlutterStandardReader*)readerWithData:(NSData*)data { return [[ExtendedReader alloc] initWithData:data]; } @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. FlutterViewController *flutterController = (FlutterViewController *)self.window.rootViewController; ExtendedReaderWriter* extendedReaderWriter = [ExtendedReaderWriter new]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"binary-msg" binaryMessenger:flutterController codec:[FlutterBinaryCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"string-msg" binaryMessenger:flutterController codec:[FlutterStringCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"json-msg" binaryMessenger:flutterController codec:[FlutterJSONMessageCodec sharedInstance]]]; [self setupMessagingHandshakeOnChannel: [FlutterBasicMessageChannel messageChannelWithName:@"std-msg" binaryMessenger:flutterController codec:[FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"json-method" binaryMessenger:flutterController codec:[FlutterJSONMethodCodec sharedInstance]]]; [self setupMethodCallSuccessHandshakeOnChannel: [FlutterMethodChannel methodChannelWithName:@"std-method" binaryMessenger:flutterController codec:[FlutterStandardMethodCodec codecWithReaderWriter:extendedReaderWriter]]]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (void)setupMessagingHandshakeOnChannel:(FlutterBasicMessageChannel*)channel { [channel setMessageHandler:^(id message, FlutterReply reply) { [channel sendMessage:message reply:^(id messageReply) { [channel sendMessage:messageReply]; reply(message); }]; }]; } - (void)setupMethodCallSuccessHandshakeOnChannel:(FlutterMethodChannel*)channel { [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { if ([call.method isEqual:@"success"]) { [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { [channel invokeMethod:call.method arguments:value]; result(call.arguments); }]; } else if ([call.method isEqual:@"error"]) { [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { FlutterError* error = (FlutterError*) value; [channel invokeMethod:call.method arguments:error.details]; result(error); }]; } else { [channel invokeMethod:call.method arguments:call.arguments result:^(id value) { NSAssert(value == FlutterMethodNotImplemented, @"Result must be not implemented"); [channel invokeMethod:call.method arguments:nil]; result(FlutterMethodNotImplemented); }]; } }]; } @end