writeHostApi method

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

Write the kotlin code that represents a host Api, api. Example: interface Foo { Int add(x: Int, y: Int); companion object { fun setUp(binaryMessenger: BinaryMessenger, api: Api) {...} } }

Implementation

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

  final String apiName = api.name;

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

  const List<String> generatedMessages = <String>[
    ' Generated interface from Pigeon that represents a handler of messages from Flutter.'
  ];
  addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
      generatorComments: generatedMessages);

  indent.write('interface $apiName ');
  indent.addScoped('{', '}', () {
    for (final Method method in api.methods) {
      final List<String> argSignature = <String>[];
      if (method.arguments.isNotEmpty) {
        final Iterable<String> argTypes = method.arguments
            .map((NamedType e) => _nullsafeKotlinTypeForDartType(e.type));
        final Iterable<String> argNames =
            method.arguments.map((NamedType e) => e.name);
        argSignature.addAll(
            map2(argTypes, argNames, (String argType, String argName) {
          return '$argName: $argType';
        }));
      }

      final String returnType = method.returnType.isVoid
          ? ''
          : _nullsafeKotlinTypeForDartType(method.returnType);

      final String resultType =
          method.returnType.isVoid ? 'Unit' : returnType;
      addDocumentationComments(
          indent, method.documentationComments, _docCommentSpec);

      if (method.isAsynchronous) {
        argSignature.add('callback: (Result<$resultType>) -> Unit');
        indent.writeln('fun ${method.name}(${argSignature.join(', ')})');
      } else if (method.returnType.isVoid) {
        indent.writeln('fun ${method.name}(${argSignature.join(', ')})');
      } else {
        indent.writeln(
            'fun ${method.name}(${argSignature.join(', ')}): $returnType');
      }
    }

    indent.newln();
    indent.write('companion object ');
    indent.addScoped('{', '}', () {
      indent.writeln('/** The codec used by $apiName. */');
      indent.write('val codec: MessageCodec<Any?> by lazy ');
      indent.addScoped('{', '}', () {
        if (isCustomCodec) {
          indent.writeln(_getCodecName(api));
        } else {
          indent.writeln('StandardMessageCodec()');
        }
      });
      indent.writeln(
          '/** Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`. */');
      indent.writeln('@Suppress("UNCHECKED_CAST")');
      indent.write(
          'fun setUp(binaryMessenger: BinaryMessenger, api: $apiName?) ');
      indent.addScoped('{', '}', () {
        for (final Method method in api.methods) {
          indent.write('run ');
          indent.addScoped('{', '}', () {
            String? taskQueue;
            if (method.taskQueueType != TaskQueueType.serial) {
              taskQueue = 'taskQueue';
              indent.writeln(
                  'val $taskQueue = binaryMessenger.makeBackgroundTaskQueue()');
            }

            final String channelName =
                makeChannelName(api, method, dartPackageName);

            indent.write(
                'val channel = BasicMessageChannel<Any?>(binaryMessenger, "$channelName", codec');

            if (taskQueue != null) {
              indent.addln(', $taskQueue)');
            } else {
              indent.addln(')');
            }

            indent.write('if (api != null) ');
            indent.addScoped('{', '}', () {
              final String messageVarName =
                  method.arguments.isNotEmpty ? 'message' : '_';

              indent.write('channel.setMessageHandler ');
              indent.addScoped('{ $messageVarName, reply ->', '}', () {
                final List<String> methodArguments = <String>[];
                if (method.arguments.isNotEmpty) {
                  indent.writeln('val args = message as List<Any?>');
                  enumerate(method.arguments, (int index, NamedType arg) {
                    final String argName = _getSafeArgumentName(index, arg);
                    final String argIndex = 'args[$index]';
                    indent.writeln(
                        'val $argName = ${_castForceUnwrap(argIndex, arg.type, root)}');
                    methodArguments.add(argName);
                  });
                }
                final String call =
                    'api.${method.name}(${methodArguments.join(', ')})';

                if (method.isAsynchronous) {
                  indent.write('$call ');
                  final String resultType = method.returnType.isVoid
                      ? 'Unit'
                      : _nullsafeKotlinTypeForDartType(method.returnType);
                  indent.addScoped('{ result: Result<$resultType> ->', '}',
                      () {
                    indent.writeln('val error = result.exceptionOrNull()');
                    indent.writeScoped('if (error != null) {', '}', () {
                      indent.writeln('reply.reply(wrapError(error))');
                    }, addTrailingNewline: false);
                    indent.addScoped(' else {', '}', () {
                      if (method.returnType.isVoid) {
                        indent.writeln('reply.reply(wrapResult(null))');
                      } else {
                        indent.writeln('val data = result.getOrNull()');
                        indent.writeln('reply.reply(wrapResult(data))');
                      }
                    });
                  });
                } else {
                  indent.writeln('var wrapped: List<Any?>');
                  indent.write('try ');
                  indent.addScoped('{', '}', () {
                    if (method.returnType.isVoid) {
                      indent.writeln(call);
                      indent.writeln('wrapped = listOf<Any?>(null)');
                    } else {
                      indent.writeln('wrapped = listOf<Any?>($call)');
                    }
                  }, addTrailingNewline: false);
                  indent.add(' catch (exception: Throwable) ');
                  indent.addScoped('{', '}', () {
                    indent.writeln('wrapped = wrapError(exception)');
                  });
                  indent.writeln('reply.reply(wrapped)');
                }
              });
            }, addTrailingNewline: false);
            indent.addScoped(' else {', '}', () {
              indent.writeln('channel.setMessageHandler(null)');
            });
          });
        }
      });
    });
  });
}