in packages/pigeon/lib/objc_generator.dart [580:706]
void _writeHostApiSource(Indent indent, ObjcOptions options, Api api) {
assert(api.location == ApiLocation.host);
final String apiName = _className(options.prefix, api.name);
void writeChannelAllocation(Method func, String varName) {
indent.writeln('FlutterBasicMessageChannel *$varName =');
indent.inc();
indent.writeln('[FlutterBasicMessageChannel');
indent.inc();
indent.writeln('messageChannelWithName:@"${makeChannelName(api, func)}"');
indent.writeln('binaryMessenger:binaryMessenger');
indent
.writeln('codec:${_getCodecGetterName(options.prefix, api.name)}()];');
indent.dec();
indent.dec();
}
void writeChannelApiBinding(Method func, String channel) {
void unpackArgs(String variable, Iterable<String> argNames) {
indent.writeln('NSArray *args = $variable;');
map3(wholeNumbers.take(func.arguments.length), argNames, func.arguments,
(int count, String argName, NamedType arg) {
final _ObjcPtr argType = _objcTypeForDartType(options.prefix, arg.type);
return '${argType.ptr}$argName = args[$count];';
}).forEach(indent.writeln);
}
void writeAsyncBindings(Iterable<String> selectorComponents,
String callSignature, _ObjcPtr returnType) {
if (func.returnType.isVoid) {
const String callback = 'callback(wrapResult(nil, error));';
if (func.arguments.isEmpty) {
indent.writeScoped(
'[api ${selectorComponents.first}:^(FlutterError *_Nullable error) {',
'}];', () {
indent.writeln(callback);
});
} else {
indent.writeScoped(
'[api $callSignature ${selectorComponents.last}:^(FlutterError *_Nullable error) {',
'}];', () {
indent.writeln(callback);
});
}
} else {
const String callback = 'callback(wrapResult(output, error));';
if (func.arguments.isEmpty) {
indent.writeScoped(
'[api ${selectorComponents.first}:^(${returnType.ptr}_Nullable output, FlutterError *_Nullable error) {',
'}];', () {
indent.writeln(callback);
});
} else {
indent.writeScoped(
'[api $callSignature ${selectorComponents.last}:^(${returnType.ptr}_Nullable output, FlutterError *_Nullable error) {',
'}];', () {
indent.writeln(callback);
});
}
}
}
void writeSyncBindings(String call, _ObjcPtr returnType) {
indent.writeln('FlutterError *error;');
if (func.returnType.isVoid) {
indent.writeln('$call;');
indent.writeln('callback(wrapResult(nil, error));');
} else {
indent.writeln('${returnType.ptr}output = $call;');
indent.writeln('callback(wrapResult(output, error));');
}
}
// TODO(gaaclarke): Incorporate this into _getSelectorComponents.
final String lastSelectorComponent =
func.isAsynchronous ? 'completion' : 'error';
final String selector = _getSelector(func, lastSelectorComponent);
indent.writeln(
'NSCAssert([api respondsToSelector:@selector($selector)], @"$apiName api (%@) doesn\'t respond to @selector($selector)", api);');
indent.write(
'[$channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ');
indent.scoped('{', '}];', () {
final _ObjcPtr returnType =
_objcTypeForDartType(options.prefix, func.returnType);
final Iterable<String> selectorComponents =
_getSelectorComponents(func, lastSelectorComponent);
final Iterable<String> argNames =
indexMap(func.arguments, _getSafeArgName);
final String callSignature =
map2(selectorComponents.take(argNames.length), argNames,
(String selectorComponent, String argName) {
return '$selectorComponent:$argName';
}).join(' ');
if (func.arguments.isNotEmpty) {
unpackArgs('message', argNames);
}
if (func.isAsynchronous) {
writeAsyncBindings(selectorComponents, callSignature, returnType);
} else {
final String syncCall = func.arguments.isEmpty
? '[api ${selectorComponents.first}:&error]'
: '[api $callSignature error:&error]';
writeSyncBindings(syncCall, returnType);
}
});
}
const String channelName = 'channel';
indent.write(
'void ${apiName}Setup(id<FlutterBinaryMessenger> binaryMessenger, NSObject<$apiName> *api) ');
indent.scoped('{', '}', () {
for (final Method func in api.methods) {
indent.write('');
indent.scoped('{', '}', () {
writeChannelAllocation(func, channelName);
indent.write('if (api) ');
indent.scoped('{', '}', () {
writeChannelApiBinding(func, channelName);
});
indent.write('else ');
indent.scoped('{', '}', () {
indent.writeln('[$channelName setMessageHandler:nil];');
});
});
}
});
}