writeHostApi method
void
writeHostApi(
- DartOptions generatorOptions,
- Root root,
- Indent indent,
- Api api, {
- 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);
}
final List<String> customEnumNames =
root.enums.map((Enum x) => x.name).toList();
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: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
''');
indent
.writeln('static const MessageCodec<Object?> codec = $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.arguments.isNotEmpty) {
String argNameFunc(int index, NamedType type) =>
_getSafeArgumentName(index, type);
final Iterable<String> argExpressions =
indexMap(func.arguments, (int index, NamedType type) {
final String name = argNameFunc(index, type);
if (root.enums
.map((Enum e) => e.name)
.contains(type.type.baseName)) {
return '$name${type.type.isNullable ? '?' : ''}.index';
} else {
return name;
}
});
sendArgument = '<Object?>[${argExpressions.join(', ')}]';
argSignature = _getMethodArgumentsSignature(func, argNameFunc);
}
indent.write(
'Future<${_addGenericTypesNullable(func.returnType)}> ${func.name}($argSignature) async ',
);
indent.addScoped('{', '}', () {
final String channelName =
makeChannelName(api, func, dartPackageName);
indent.writeln(
'final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(');
indent.nest(2, () {
indent.writeln("'$channelName', codec,");
indent.writeln('binaryMessenger: _binaryMessenger);');
});
final String returnType = _makeGenericTypeArguments(func.returnType);
final String genericCastCall = _makeGenericCastCall(func.returnType);
const String accessor = '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 (customEnumNames.contains(returnType)) {
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?>? replyList =
\t\tawait channel.send($sendArgument) as List<Object?>?;
if (replyList == null) {
\tthrow PlatformException(
\t\tcode: 'channel-error',
\t\tmessage: 'Unable to establish connection on channel.',
\t);
} else if (replyList.length > 1) {
\tthrow PlatformException(
\t\tcode: replyList[0]! as String,
\t\tmessage: replyList[1] as String?,
\t\tdetails: 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 (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
}''');
});
}
});
}