writeFlutterApi method

  1. @override
void writeFlutterApi(
  1. SwiftOptions generatorOptions,
  2. Root root,
  3. Indent indent,
  4. Api api, {
  5. required String dartPackageName,
})
override

Writes the code for a flutter Api, api. Example: class Foo { private let binaryMessenger: FlutterBinaryMessenger init(binaryMessenger: FlutterBinaryMessenger) {...} func add(x: Int32, y: Int32, completion: @escaping (Int32?) -> Void) {...} }

Implementation

@override
void writeFlutterApi(
  SwiftOptions generatorOptions,
  Root root,
  Indent indent,
  Api api, {
  required String dartPackageName,
}) {
  assert(api.location == ApiLocation.flutter);

  /// Returns an argument name that can be used in a context where it is possible to collide.
  String getEnumSafeArgumentExpression(
      Root root, int count, NamedType argument) {
    String enumTag = '';
    if (argument.type.isEnum) {
      enumTag = argument.type.isNullable ? '?.rawValue' : '.rawValue';
    }

    return '${_getArgumentName(count, argument)}Arg$enumTag';
  }

  final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty;
  if (isCustomCodec) {
    _writeCodec(indent, api, root);
  }

  const List<String> generatedComments = <String>[
    ' Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.'
  ];
  addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
      generatorComments: generatedComments);

  indent.addScoped('protocol ${api.name}Protocol {', '}', () {
    for (final Method func in api.methods) {
      addDocumentationComments(
          indent, func.documentationComments, _docCommentSpec);
      indent.writeln(_getMethodSignature(func));
    }
  });

  indent.write('class ${api.name}: ${api.name}Protocol ');
  indent.addScoped('{', '}', () {
    indent.writeln('private let binaryMessenger: FlutterBinaryMessenger');
    indent.write('init(binaryMessenger: FlutterBinaryMessenger)');
    indent.addScoped('{', '}', () {
      indent.writeln('self.binaryMessenger = binaryMessenger');
    });
    final String codecName = _getCodecName(api);
    String codecArgumentString = '';
    if (getCodecClasses(api, root).isNotEmpty) {
      codecArgumentString = ', codec: codec';
      indent.write('var codec: FlutterStandardMessageCodec ');
      indent.addScoped('{', '}', () {
        indent.writeln('return $codecName.shared');
      });
    }
    for (final Method func in api.methods) {
      addDocumentationComments(
          indent, func.documentationComments, _docCommentSpec);
      indent.writeScoped('${_getMethodSignature(func)} {', '}', () {
        final Iterable<String> enumSafeArgNames = func.parameters
            .asMap()
            .entries
            .map((MapEntry<int, NamedType> e) =>
                getEnumSafeArgumentExpression(root, e.key, e.value));
        final String sendArgument = func.parameters.isEmpty
            ? 'nil'
            : '[${enumSafeArgNames.join(', ')}] as [Any?]';
        const String channel = 'channel';
        indent.writeln(
            'let channelName: String = "${makeChannelName(api, func, dartPackageName)}"');
        indent.writeln(
            'let $channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger$codecArgumentString)');
        indent.write('$channel.sendMessage($sendArgument) ');

        indent.addScoped('{ response in', '}', () {
          indent.writeScoped(
              'guard let listResponse = response as? [Any?] else {', '}', () {
            indent.writeln(
                'completion(.failure(createConnectionError(withChannelName:channelName)))');
            indent.writeln('return');
          });
          indent.writeScoped('if (listResponse.count > 1) {', '} ', () {
            indent.writeln('let code: String = listResponse[0] as! String');
            indent.writeln(
                'let message: String? = nilOrValue(listResponse[1])');
            indent.writeln(
                'let details: String? = nilOrValue(listResponse[2])');
            indent.writeln(
                'completion(.failure(FlutterError(code: code, message: message, details: details)));');
          }, addTrailingNewline: false);
          if (!func.returnType.isNullable && !func.returnType.isVoid) {
            indent.addScoped('else if (listResponse[0] == nil) {', '} ', () {
              indent.writeln(
                  'completion(.failure(FlutterError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: "")))');
            }, addTrailingNewline: false);
          }
          indent.addScoped('else {', '}', () {
            if (func.returnType.isVoid) {
              indent.writeln('completion(.success(Void()))');
            } else {
              final String fieldType = _swiftTypeForDartType(func.returnType);

              _writeGenericCasting(
                  indent: indent,
                  value: 'listResponse[0]',
                  variableName: 'result',
                  fieldType: fieldType,
                  type: func.returnType);

              indent.writeln('completion(.success(result))');
            }
          });
        });
      });
    }
  });
}