writeHostApi method

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

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

class Foo { Foo(BinaryMessenger? binaryMessenger) {} static const MessageCodec<Object?> codec = FooCodec(); Future

Messages will be sent and received in a list.

If the message received was successful, the result will be contained at the 0'th index.

If the message was a failure, the list will contain 3 items: a code, a message, and details in that order.

Implementation

@override
void writeHostApi(
  DartOptions generatorOptions,
  Root root,
  Indent indent,
  Api api, {
  required String dartPackageName,
}) {
  assert(api.location == ApiLocation.host);
  String codecName = _standardMessageCodec;
  if (getCodecClasses(api, root).isNotEmpty) {
    codecName = _getCodecName(api);
    _writeCodec(indent, codecName, api, root);
  }
  indent.newln();
  bool first = true;
  addDocumentationComments(
      indent, api.documentationComments, _docCommentSpec);
  indent.write('class ${api.name} ');
  indent.addScoped('{', '}', () {
    indent.format('''
/// Constructor for [${api.name}].  The [binaryMessenger] named argument is
/// available for dependency injection.  If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
${api.name}({BinaryMessenger? binaryMessenger})
\t\t: ${_varNamePrefix}binaryMessenger = binaryMessenger;
final BinaryMessenger? ${_varNamePrefix}binaryMessenger;
''');

    indent.writeln(
        'static const MessageCodec<Object?> $_pigeonChannelCodec = $codecName();');
    indent.newln();
    for (final Method func in api.methods) {
      if (!first) {
        indent.newln();
      } else {
        first = false;
      }
      addDocumentationComments(
          indent, func.documentationComments, _docCommentSpec);
      String argSignature = '';
      String sendArgument = 'null';
      if (func.parameters.isNotEmpty) {
        final Iterable<String> argExpressions =
            indexMap(func.parameters, (int index, NamedType type) {
          final String name = _getParameterName(index, type);
          if (type.type.isEnum) {
            return '$name${type.type.isNullable ? '?' : ''}.index';
          } else {
            return name;
          }
        });
        sendArgument = '<Object?>[${argExpressions.join(', ')}]';
        argSignature = _getMethodParameterSignature(func);
      }
      indent.write(
        'Future<${_addGenericTypesNullable(func.returnType)}> ${func.name}($argSignature) async ',
      );
      indent.addScoped('{', '}', () {
        indent.writeln(
            "const String ${_varNamePrefix}channelName = '${makeChannelName(api, func, dartPackageName)}';");
        indent.writeScoped(
            'final BasicMessageChannel<Object?> ${_varNamePrefix}channel = BasicMessageChannel<Object?>(',
            ');', () {
          indent.writeln('${_varNamePrefix}channelName,');
          indent.writeln('$_pigeonChannelCodec,');
          indent
              .writeln('binaryMessenger: ${_varNamePrefix}binaryMessenger,');
        });
        final String returnType = _makeGenericTypeArguments(func.returnType);
        final String genericCastCall = _makeGenericCastCall(func.returnType);
        const String accessor = '${_varNamePrefix}replyList[0]';
        // Avoid warnings from pointlessly casting to `Object?`.
        final String nullablyTypedAccessor =
            returnType == 'Object' ? accessor : '($accessor as $returnType?)';
        final String nullHandler = func.returnType.isNullable
            ? (genericCastCall.isEmpty ? '' : '?')
            : '!';
        String returnStatement = 'return';
        if (func.returnType.isEnum) {
          if (func.returnType.isNullable) {
            returnStatement =
                '$returnStatement ($accessor as int?) == null ? null : $returnType.values[$accessor! as int]';
          } else {
            returnStatement =
                '$returnStatement $returnType.values[$accessor! as int]';
          }
        } else if (!func.returnType.isVoid) {
          returnStatement =
              '$returnStatement $nullablyTypedAccessor$nullHandler$genericCastCall';
        }
        returnStatement = '$returnStatement;';

        indent.format('''
final List<Object?>? ${_varNamePrefix}replyList =
\t\tawait ${_varNamePrefix}channel.send($sendArgument) as List<Object?>?;
if (${_varNamePrefix}replyList == null) {
\tthrow _createConnectionError(${_varNamePrefix}channelName);
} else if (${_varNamePrefix}replyList.length > 1) {
\tthrow PlatformException(
\t\tcode: ${_varNamePrefix}replyList[0]! as String,
\t\tmessage: ${_varNamePrefix}replyList[1] as String?,
\t\tdetails: ${_varNamePrefix}replyList[2],
\t);''');
        // On iOS we can return nil from functions to accommodate error
        // handling.  Returning a nil value and not returning an error is an
        // exception.
        if (!func.returnType.isNullable && !func.returnType.isVoid) {
          indent.format('''
} else if (${_varNamePrefix}replyList[0] == null) {
\tthrow PlatformException(
\t\tcode: 'null-error',
\t\tmessage: 'Host platform returned null value for non-null return value.',
\t);''');
        }
        indent.format('''
} else {
\t$returnStatement
}''');
      });
    }
  });
}