writeFlutterApi method
void
writeFlutterApi(
- JavaOptions generatorOptions,
- Root root,
- Indent indent,
- AstFlutterApi api, {
- required String dartPackageName,
override
Writes the code for a flutter Api, api
.
Example:
public static final class Foo {
public Foo(BinaryMessenger argBinaryMessenger) {...}
public interface Result
Implementation
@override
void writeFlutterApi(
JavaOptions generatorOptions,
Root root,
Indent indent,
AstFlutterApi api, {
required String dartPackageName,
}) {
/// Returns an argument name that can be used in a context where it is possible to collide
/// and append `.index` to enums.
String getEnumSafeArgumentExpression(int count, NamedType argument) {
if (argument.type.isEnum) {
return argument.type.isNullable
? '${_getArgumentName(count, argument)}Arg == null ? null : ${_getArgumentName(count, argument)}Arg.index'
: '${_getArgumentName(count, argument)}Arg.index';
}
return '${_getArgumentName(count, argument)}Arg';
}
if (getCodecClasses(api, root).isNotEmpty) {
_writeCodec(indent, api, root);
}
const List<String> generatedMessages = <String>[
' Generated class from Pigeon that represents Flutter messages that can be called from Java.'
];
addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
generatorComments: generatedMessages);
indent.write('public static class ${api.name} ');
indent.addScoped('{', '}', () {
indent.writeln('private final @NonNull BinaryMessenger binaryMessenger;');
indent.writeln('private final String messageChannelSuffix;');
indent.newln();
indent.write(
'public ${api.name}(@NonNull BinaryMessenger argBinaryMessenger) ');
indent.addScoped('{', '}', () {
indent.writeln('this(argBinaryMessenger, "");');
});
indent.write(
'public ${api.name}(@NonNull BinaryMessenger argBinaryMessenger, @NonNull String messageChannelSuffix) ');
indent.addScoped('{', '}', () {
indent.writeln('this.binaryMessenger = argBinaryMessenger;');
indent.writeln(
'this.messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;');
});
indent.newln();
indent.writeln('/** Public interface for sending reply. */ ');
final String codecName = _getCodecName(api);
indent.writeln('/** The codec used by ${api.name}. */');
indent.write('static @NonNull MessageCodec<Object> getCodec() ');
indent.addScoped('{', '}', () {
indent.write('return ');
if (getCodecClasses(api, root).isNotEmpty) {
indent.addln('$codecName.INSTANCE;');
} else {
indent.addln('new $_standardMessageCodec();');
}
});
for (final Method func in api.methods) {
final String resultType = _getResultType(func.returnType);
final String returnType = func.returnType.isVoid
? 'Void'
: _javaTypeForDartType(func.returnType);
String sendArgument;
addDocumentationComments(
indent, func.documentationComments, _docCommentSpec);
if (func.parameters.isEmpty) {
indent
.write('public void ${func.name}(@NonNull $resultType result) ');
sendArgument = 'null';
} else {
final Iterable<String> argTypes = func.parameters
.map((NamedType e) => _nullsafeJavaTypeForDartType(e.type));
final Iterable<String> argNames =
indexMap(func.parameters, _getSafeArgumentName);
final Iterable<String> enumSafeArgNames =
indexMap(func.parameters, getEnumSafeArgumentExpression);
if (func.parameters.length == 1) {
sendArgument =
'new ArrayList<Object>(Collections.singletonList(${enumSafeArgNames.first}))';
} else {
sendArgument =
'new ArrayList<Object>(Arrays.asList(${enumSafeArgNames.join(', ')}))';
}
final String argsSignature =
map2(argTypes, argNames, (String x, String y) => '$x $y')
.join(', ');
indent.write(
'public void ${func.name}($argsSignature, @NonNull $resultType result) ');
}
indent.addScoped('{', '}', () {
const String channel = 'channel';
indent.writeln(
'final String channelName = "${makeChannelName(api, func, dartPackageName)}" + messageChannelSuffix;');
indent.writeln('BasicMessageChannel<Object> $channel =');
indent.nest(2, () {
indent.writeln('new BasicMessageChannel<>(');
indent.nest(2, () {
indent.writeln('binaryMessenger, channelName, getCodec());');
});
});
indent.writeln('$channel.send(');
indent.nest(2, () {
indent.writeln('$sendArgument,');
indent.write('channelReply -> ');
indent.addScoped('{', '});', () {
indent.writeScoped('if (channelReply instanceof List) {', '} ',
() {
indent.writeln(
'List<Object> listReply = (List<Object>) channelReply;');
indent.writeScoped('if (listReply.size() > 1) {', '} ', () {
indent.writeln(
'result.error(new FlutterError((String) listReply.get(0), (String) listReply.get(1), (String) listReply.get(2)));');
}, addTrailingNewline: false);
if (!func.returnType.isNullable && !func.returnType.isVoid) {
indent.addScoped('else if (listReply.get(0) == null) {', '} ',
() {
indent.writeln(
'result.error(new FlutterError("null-error", "Flutter api returned null value for non-null return value.", ""));');
}, addTrailingNewline: false);
}
indent.addScoped('else {', '}', () {
if (func.returnType.isVoid) {
indent.writeln('result.success();');
} else {
const String output = 'output';
final String outputExpression;
indent.writeln('@SuppressWarnings("ConstantConditions")');
if (func.returnType.baseName == 'int') {
outputExpression =
'listReply.get(0) == null ? null : ((Number) listReply.get(0)).longValue();';
} else if (func.returnType.isEnum) {
if (func.returnType.isNullable) {
outputExpression =
'listReply.get(0) == null ? null : $returnType.values()[(int) listReply.get(0)];';
} else {
outputExpression =
'$returnType.values()[(int) listReply.get(0)];';
}
} else {
outputExpression =
'${_cast('listReply.get(0)', javaType: returnType)};';
}
indent.writeln('$returnType $output = $outputExpression');
indent.writeln('result.success($output);');
}
});
}, addTrailingNewline: false);
indent.addScoped(' else {', '} ', () {
indent.writeln(
'result.error(createConnectionError(channelName));');
});
});
});
});
}
});
}