writeFlutterApi method

  1. @override
void writeFlutterApi(
  1. DartOptions generatorOptions,
  2. Root root,
  3. Indent indent,
  4. Api api, {
  5. String channelNameFunc(
    1. Method
    )?,
  6. bool isMockHandler = false,
  7. required String dartPackageName,
})
override

Writes the code for host Api, api. Example: class FooCodec extends StandardMessageCodec {...}

abstract class Foo { static const MessageCodec<Object?> codec = FooCodec(); int add(int x, int y); static void setup(Foo api, {BinaryMessenger? binaryMessenger}) {...} }

Implementation

@override
void writeFlutterApi(
  DartOptions generatorOptions,
  Root root,
  Indent indent,
  Api api, {
  String Function(Method)? channelNameFunc,
  bool isMockHandler = false,
  required String dartPackageName,
}) {
  assert(api.location == ApiLocation.flutter);
  final List<String> customEnumNames =
      root.enums.map((Enum x) => x.name).toList();
  String codecName = _standardMessageCodec;
  if (getCodecClasses(api, root).isNotEmpty) {
    codecName = _getCodecName(api);
    _writeCodec(indent, codecName, api, root);
  }
  indent.newln();
  addDocumentationComments(
      indent, api.documentationComments, _docCommentSpec);

  indent.write('abstract class ${api.name} ');
  indent.addScoped('{', '}', () {
    if (isMockHandler) {
      indent.writeln(
          'static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance;');
    }
    indent
        .writeln('static const MessageCodec<Object?> codec = $codecName();');
    indent.newln();
    for (final Method func in api.methods) {
      addDocumentationComments(
          indent, func.documentationComments, _docCommentSpec);

      final bool isAsync = func.isAsynchronous;
      final String returnType = isAsync
          ? 'Future<${_addGenericTypesNullable(func.returnType)}>'
          : _addGenericTypesNullable(func.returnType);
      final String argSignature = _getMethodArgumentsSignature(
        func,
        _getArgumentName,
      );
      indent.writeln('$returnType ${func.name}($argSignature);');
      indent.newln();
    }
    indent.write(
        'static void setup(${api.name}? api, {BinaryMessenger? binaryMessenger}) ');
    indent.addScoped('{', '}', () {
      for (final Method func in api.methods) {
        indent.write('');
        indent.addScoped('{', '}', () {
          indent.writeln(
            'final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(',
          );
          final String channelName = channelNameFunc == null
              ? makeChannelName(api, func, dartPackageName)
              : channelNameFunc(func);
          indent.nest(2, () {
            indent.writeln("'$channelName', codec,");
            indent.writeln(
              'binaryMessenger: binaryMessenger);',
            );
          });
          final String messageHandlerSetterWithOpeningParentheses = isMockHandler
              ? '_testBinaryMessengerBinding!.defaultBinaryMessenger.setMockDecodedMessageHandler<Object?>(channel, '
              : 'channel.setMessageHandler(';
          indent.write('if (api == null) ');
          indent.addScoped('{', '}', () {
            indent.writeln(
                '${messageHandlerSetterWithOpeningParentheses}null);');
          }, addTrailingNewline: false);
          indent.add(' else ');
          indent.addScoped('{', '}', () {
            indent.write(
              '$messageHandlerSetterWithOpeningParentheses(Object? message) async ',
            );
            indent.addScoped('{', '});', () {
              final String returnType =
                  _addGenericTypesNullable(func.returnType);
              final bool isAsync = func.isAsynchronous;
              final String emptyReturnStatement = isMockHandler
                  ? 'return <Object?>[];'
                  : func.returnType.isVoid
                      ? 'return;'
                      : 'return null;';
              String call;
              if (func.arguments.isEmpty) {
                indent.writeln('// ignore message');
                call = 'api.${func.name}()';
              } else {
                indent.writeln('assert(message != null,');
                indent.writeln("'Argument for $channelName was null.');");
                const String argsArray = 'args';
                indent.writeln(
                    'final List<Object?> $argsArray = (message as List<Object?>?)!;');
                String argNameFunc(int index, NamedType type) =>
                    _getSafeArgumentName(index, type);
                enumerate(func.arguments, (int count, NamedType arg) {
                  final String argType = _addGenericTypes(arg.type);
                  final String argName = argNameFunc(count, arg);
                  final String genericArgType =
                      _makeGenericTypeArguments(arg.type);
                  final String castCall = _makeGenericCastCall(arg.type);

                  final String leftHandSide = 'final $argType? $argName';
                  if (customEnumNames.contains(arg.type.baseName)) {
                    indent.writeln(
                        '$leftHandSide = $argsArray[$count] == null ? null : $argType.values[$argsArray[$count] as int];');
                  } else {
                    indent.writeln(
                        '$leftHandSide = ($argsArray[$count] as $genericArgType?)${castCall.isEmpty ? '' : '?$castCall'};');
                  }
                  if (!arg.type.isNullable) {
                    indent.writeln('assert($argName != null,');
                    indent.writeln(
                        "    'Argument for $channelName was null, expected non-null $argType.');");
                  }
                });
                final Iterable<String> argNames =
                    indexMap(func.arguments, (int index, NamedType field) {
                  final String name = _getSafeArgumentName(index, field);
                  return '$name${field.type.isNullable ? '' : '!'}';
                });
                call = 'api.${func.name}(${argNames.join(', ')})';
              }
              if (func.returnType.isVoid) {
                if (isAsync) {
                  indent.writeln('await $call;');
                } else {
                  indent.writeln('$call;');
                }
                indent.writeln(emptyReturnStatement);
              } else {
                if (isAsync) {
                  indent.writeln('final $returnType output = await $call;');
                } else {
                  indent.writeln('final $returnType output = $call;');
                }
                const String returnExpression = 'output';
                final String returnStatement = isMockHandler
                    ? 'return <Object?>[$returnExpression];'
                    : 'return $returnExpression;';
                indent.writeln(returnStatement);
              }
            });
          });
        });
      }
    });
  });
}