[pigeon] add flutter api protocol (#5181)

Protocols to make testing with mocks easier.

Fixes https://github.com/flutter/flutter/issues/136811
This commit is contained in:
Tarrin Neal
2023-10-19 08:11:05 -07:00
committed by GitHub
parent 09c6b11520
commit 24654d3d8c
18 changed files with 482 additions and 99 deletions

View File

@ -1,3 +1,7 @@
## 12.0.1
* [swift] Adds protocol for Flutter APIs.
## 12.0.0 ## 12.0.0
* Adds error handling on Flutter API methods. * Adds error handling on Flutter API methods.

View File

@ -173,8 +173,11 @@ class ExampleHostApiSetup {
} }
} }
} }
/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
class MessageFlutterApi { protocol MessageFlutterApiProtocol {
func flutterMethod(aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class MessageFlutterApi: MessageFlutterApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){ init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger self.binaryMessenger = binaryMessenger

View File

@ -13,7 +13,7 @@ import 'ast.dart';
/// The current version of pigeon. /// The current version of pigeon.
/// ///
/// This must match the version in pubspec.yaml. /// This must match the version in pubspec.yaml.
const String pigeonVersion = '12.0.0'; const String pigeonVersion = '12.0.1';
/// Read all the content from [stdin] to a String. /// Read all the content from [stdin] to a String.
String readStdin() { String readStdin() {

View File

@ -291,13 +291,22 @@ import FlutterMacOS
if (isCustomCodec) { if (isCustomCodec) {
_writeCodec(indent, api, root); _writeCodec(indent, api, root);
} }
const List<String> generatedComments = <String>[ const List<String> generatedComments = <String>[
' Generated class from Pigeon that represents Flutter messages that can be called from Swift.' ' Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.'
]; ];
addDocumentationComments(indent, api.documentationComments, _docCommentSpec, addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
generatorComments: generatedComments); generatorComments: generatedComments);
indent.write('class ${api.name} '); indent.addScoped('protocol ${api.name}Protocol {', '}', () {
for (final Method func in api.methods) {
addDocumentationComments(
indent, func.documentationComments, _docCommentSpec);
indent.writeln(_getMethodSignature(func));
}
});
indent.write('class ${api.name}: ${api.name}Protocol ');
indent.addScoped('{', '}', () { indent.addScoped('{', '}', () {
indent.writeln('private let binaryMessenger: FlutterBinaryMessenger'); indent.writeln('private let binaryMessenger: FlutterBinaryMessenger');
indent.write('init(binaryMessenger: FlutterBinaryMessenger)'); indent.write('init(binaryMessenger: FlutterBinaryMessenger)');
@ -314,47 +323,19 @@ import FlutterMacOS
}); });
} }
for (final Method func in api.methods) { for (final Method func in api.methods) {
final _SwiftFunctionComponents components =
_SwiftFunctionComponents.fromMethod(func);
final String channelName = makeChannelName(api, func, dartPackageName); final String channelName = makeChannelName(api, func, dartPackageName);
final String returnType = func.returnType.isVoid
? 'Void'
: _nullsafeSwiftTypeForDartType(func.returnType);
String sendArgument;
addDocumentationComments( addDocumentationComments(
indent, func.documentationComments, _docCommentSpec); indent, func.documentationComments, _docCommentSpec);
indent.writeScoped('${_getMethodSignature(func)} {', '}', () {
if (func.arguments.isEmpty) {
indent.write(
'func ${func.name}(completion: @escaping (Result<$returnType, FlutterError>) -> Void) ');
sendArgument = 'nil';
} else {
final Iterable<String> argTypes = func.arguments
.map((NamedType e) => _nullsafeSwiftTypeForDartType(e.type));
final Iterable<String> argLabels = indexMap(components.arguments,
(int index, _SwiftFunctionArgument argument) {
return argument.label ??
_getArgumentName(index, argument.namedType);
});
final Iterable<String> argNames =
indexMap(func.arguments, _getSafeArgumentName);
final Iterable<String> enumSafeArgNames = func.arguments final Iterable<String> enumSafeArgNames = func.arguments
.asMap() .asMap()
.entries .entries
.map((MapEntry<int, NamedType> e) => .map((MapEntry<int, NamedType> e) =>
getEnumSafeArgumentExpression(root, e.key, e.value)); getEnumSafeArgumentExpression(root, e.key, e.value));
sendArgument = '[${enumSafeArgNames.join(', ')}] as [Any?]'; final String sendArgument = func.arguments.isEmpty
final String argsSignature = map3( ? 'nil'
argTypes, : '[${enumSafeArgNames.join(', ')}] as [Any?]';
argLabels,
argNames,
(String type, String label, String name) =>
'$label $name: $type').join(', ');
indent.write(
'func ${components.name}($argsSignature, completion: @escaping (Result<$returnType, FlutterError>) -> Void) ');
}
indent.addScoped('{', '}', () {
const String channel = 'channel'; const String channel = 'channel';
indent.writeln( indent.writeln(
'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)'); 'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)');
@ -893,6 +874,31 @@ String _nullsafeSwiftTypeForDartType(TypeDeclaration type) {
return '${_swiftTypeForDartType(type)}$nullSafe'; return '${_swiftTypeForDartType(type)}$nullSafe';
} }
String _getMethodSignature(Method func) {
final _SwiftFunctionComponents components =
_SwiftFunctionComponents.fromMethod(func);
final String returnType = func.returnType.isVoid
? 'Void'
: _nullsafeSwiftTypeForDartType(func.returnType);
if (func.arguments.isEmpty) {
return 'func ${func.name}(completion: @escaping (Result<$returnType, FlutterError>) -> Void) ';
} else {
final Iterable<String> argTypes = func.arguments
.map((NamedType e) => _nullsafeSwiftTypeForDartType(e.type));
final Iterable<String> argLabels = indexMap(components.arguments,
(int index, _SwiftFunctionArgument argument) {
return argument.label ?? _getArgumentName(index, argument.namedType);
});
final Iterable<String> argNames =
indexMap(func.arguments, _getSafeArgumentName);
final String argsSignature = map3(argTypes, argLabels, argNames,
(String type, String label, String name) => '$label $name: $type')
.join(', ');
return 'func ${components.name}($argsSignature, completion: @escaping (Result<$returnType, FlutterError>) -> Void) ';
}
}
/// A class that represents a Swift function argument. /// A class that represents a Swift function argument.
/// ///
/// The [name] is the name of the argument. /// The [name] is the name of the argument.

View File

@ -661,6 +661,10 @@ abstract class FlutterSmallApi {
@ObjCSelector('echoWrappedList:') @ObjCSelector('echoWrappedList:')
@SwiftFunction('echo(_:)') @SwiftFunction('echo(_:)')
TestMessage echoWrappedList(TestMessage msg); TestMessage echoWrappedList(TestMessage msg);
@ObjCSelector('echoString:')
@SwiftFunction('echo(_:)')
String echoString(String aString);
} }
/// A data class containing a List, used in unit tests. /// A data class containing a List, used in unit tests.

View File

@ -4390,5 +4390,41 @@ public class CoreTests {
} }
}); });
} }
public void echoString(@NonNull String aStringArg, @NonNull Result<String> result) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString",
getCodec());
channel.send(
new ArrayList<Object>(Collections.singletonList(aStringArg)),
channelReply -> {
if (channelReply instanceof List) {
List<Object> listReply = (List<Object>) channelReply;
if (listReply.size() > 1) {
result.error(
new FlutterError(
(String) listReply.get(0),
(String) listReply.get(1),
(String) listReply.get(2)));
} else if (listReply.get(0) == null) {
result.error(
new FlutterError(
"null-error",
"Flutter api returned null value for non-null return value.",
""));
} else {
@SuppressWarnings("ConstantConditions")
String output = (String) listReply.get(0);
result.success(output);
}
} else {
result.error(
new FlutterError(
"channel-error", "Unable to establish connection on channel.", ""));
}
});
}
} }
} }

View File

@ -494,6 +494,8 @@ NSObject<FlutterMessageCodec> *FlutterSmallApiGetCodec(void);
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger; - (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
- (void)echoWrappedList:(TestMessage *)msg - (void)echoWrappedList:(TestMessage *)msg
completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion; completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion;
- (void)echoString:(NSString *)aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -2971,4 +2971,30 @@ NSObject<FlutterMessageCodec> *FlutterSmallApiGetCodec(void) {
} }
}]; }];
} }
- (void)echoString:(NSString *)arg_aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion {
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
messageChannelWithName:
@"dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString"
binaryMessenger:self.binaryMessenger
codec:FlutterSmallApiGetCodec()];
[channel sendMessage:@[ arg_aString ?: [NSNull null] ]
reply:^(NSArray<id> *reply) {
if (reply != nil) {
if (reply.count > 1) {
completion(nil, [FlutterError errorWithCode:reply[0]
message:reply[1]
details:reply[2]]);
} else {
NSString *output = reply[0] == [NSNull null] ? nil : reply[0];
completion(output, nil);
}
} else {
completion(nil, [FlutterError
errorWithCode:@"channel-error"
message:@"Unable to establish connection on channel."
details:@""]);
}
}];
}
@end @end

View File

@ -494,6 +494,8 @@ NSObject<FlutterMessageCodec> *FlutterSmallApiGetCodec(void);
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger; - (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
- (void)echoWrappedList:(TestMessage *)msg - (void)echoWrappedList:(TestMessage *)msg
completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion; completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion;
- (void)echoString:(NSString *)aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -2971,4 +2971,30 @@ NSObject<FlutterMessageCodec> *FlutterSmallApiGetCodec(void) {
} }
}]; }];
} }
- (void)echoString:(NSString *)arg_aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion {
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
messageChannelWithName:
@"dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString"
binaryMessenger:self.binaryMessenger
codec:FlutterSmallApiGetCodec()];
[channel sendMessage:@[ arg_aString ?: [NSNull null] ]
reply:^(NSArray<id> *reply) {
if (reply != nil) {
if (reply.count > 1) {
completion(nil, [FlutterError errorWithCode:reply[0]
message:reply[1]
details:reply[2]]);
} else {
NSString *output = reply[0] == [NSNull null] ? nil : reply[0];
completion(output, nil);
}
} else {
completion(nil, [FlutterError
errorWithCode:@"channel-error"
message:@"Unable to establish connection on channel."
details:@""]);
}
}];
}
@end @end

View File

@ -3120,6 +3120,8 @@ abstract class FlutterSmallApi {
TestMessage echoWrappedList(TestMessage msg); TestMessage echoWrappedList(TestMessage msg);
String echoString(String aString);
static void setup(FlutterSmallApi? api, {BinaryMessenger? binaryMessenger}) { static void setup(FlutterSmallApi? api, {BinaryMessenger? binaryMessenger}) {
{ {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@ -3148,5 +3150,32 @@ abstract class FlutterSmallApi {
}); });
} }
} }
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString',
codec,
binaryMessenger: binaryMessenger);
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString was null.');
final List<Object?> args = (message as List<Object?>?)!;
final String? arg_aString = (args[0] as String?);
assert(arg_aString != null,
'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString was null, expected non-null String.');
try {
final String output = api.echoString(arg_aString!);
return wrapResponse(result: output);
} on PlatformException catch (e) {
return wrapResponse(error: e);
} catch (e) {
return wrapResponse(
error: PlatformException(code: 'error', message: e.toString()));
}
});
}
}
} }
} }

View File

@ -2479,4 +2479,21 @@ class FlutterSmallApi(private val binaryMessenger: BinaryMessenger) {
} }
} }
} }
fun echoString(aStringArg: String, callback: (Result<String>) -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString", codec)
channel.send(listOf(aStringArg)) {
if (it is List<*>) {
if (it.size > 1) {
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
} else if (it[0] == null) {
callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")));
} else {
val output = it[0] as String
callback(Result.success(output));
}
} else {
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
}
}
}
} }

View File

@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import Flutter
import Foundation
import XCTest import XCTest
@testable import test_plugin @testable import test_plugin
class RunnerTests: XCTestCase { class RunnerTests: XCTestCase {
@ -27,4 +30,32 @@ class RunnerTests: XCTestCase {
let copy = MessageSearchReply.fromList(dict) let copy = MessageSearchReply.fromList(dict)
XCTAssertEqual(reply.error, copy?.error) XCTAssertEqual(reply.error, copy?.error)
} }
/// This validates that pigeon clients can easily write tests that mock out Flutter API
/// calls using a pigeon-generated protocol.
func testEchoStringFromProtocol() throws {
let api: FlutterApiFromProtocol = FlutterApiFromProtocol()
let aString = "aString"
api.echo(aString) { response in
switch response {
case .success(let res):
XCTAssertEqual(aString, res)
case .failure(let error):
XCTFail(error.code)
}
}
}
}
class FlutterApiFromProtocol: FlutterSmallApiProtocol {
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void) {
completion(.success(aStringArg))
}
func echo(
_ msgArg: test_plugin.TestMessage,
completion: @escaping (Result<test_plugin.TestMessage, FlutterError>) -> Void
) {
completion(.success(msgArg))
}
} }

View File

@ -1739,8 +1739,62 @@ class FlutterIntegrationCoreApiCodec: FlutterStandardMessageCodec {
/// The core interface that the Dart platform_test code implements for host /// The core interface that the Dart platform_test code implements for host
/// integration tests to call into. /// integration tests to call into.
/// ///
/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
class FlutterIntegrationCoreApi { protocol FlutterIntegrationCoreApiProtocol {
/// A no-op function taking no arguments and returning no value, to sanity
/// test basic calling.
func noop(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Responds with an error from an async function returning a value.
func throwError(completion: @escaping (Result<Any?, FlutterError>) -> Void)
/// Responds with an error from an async void function.
func throwErrorFromVoid(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Returns the passed object, to test serialization and deserialization.
func echo(_ everythingArg: AllTypes, completion: @escaping (Result<AllTypes, FlutterError>) -> Void)
/// Returns the passed object, to test serialization and deserialization.
func echoNullable(_ everythingArg: AllNullableTypes?, completion: @escaping (Result<AllNullableTypes?, FlutterError>) -> Void)
/// Returns passed in arguments of multiple types.
///
/// Tests multiple-arity FlutterApi handling.
func sendMultipleNullableTypes(aBool aNullableBoolArg: Bool?, anInt aNullableIntArg: Int64?, aString aNullableStringArg: String?, completion: @escaping (Result<AllNullableTypes, FlutterError>) -> Void)
/// Returns the passed boolean, to test serialization and deserialization.
func echo(_ aBoolArg: Bool, completion: @escaping (Result<Bool, FlutterError>) -> Void)
/// Returns the passed int, to test serialization and deserialization.
func echo(_ anIntArg: Int64, completion: @escaping (Result<Int64, FlutterError>) -> Void)
/// Returns the passed double, to test serialization and deserialization.
func echo(_ aDoubleArg: Double, completion: @escaping (Result<Double, FlutterError>) -> Void)
/// Returns the passed string, to test serialization and deserialization.
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
/// Returns the passed byte list, to test serialization and deserialization.
func echo(_ aListArg: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, FlutterError>) -> Void)
/// Returns the passed list, to test serialization and deserialization.
func echo(_ aListArg: [Any?], completion: @escaping (Result<[Any?], FlutterError>) -> Void)
/// Returns the passed map, to test serialization and deserialization.
func echo(_ aMapArg: [String?: Any?], completion: @escaping (Result<[String?: Any?], FlutterError>) -> Void)
/// Returns the passed enum to test serialization and deserialization.
func echo(_ anEnumArg: AnEnum, completion: @escaping (Result<AnEnum, FlutterError>) -> Void)
/// Returns the passed boolean, to test serialization and deserialization.
func echoNullable(_ aBoolArg: Bool?, completion: @escaping (Result<Bool?, FlutterError>) -> Void)
/// Returns the passed int, to test serialization and deserialization.
func echoNullable(_ anIntArg: Int64?, completion: @escaping (Result<Int64?, FlutterError>) -> Void)
/// Returns the passed double, to test serialization and deserialization.
func echoNullable(_ aDoubleArg: Double?, completion: @escaping (Result<Double?, FlutterError>) -> Void)
/// Returns the passed string, to test serialization and deserialization.
func echoNullable(_ aStringArg: String?, completion: @escaping (Result<String?, FlutterError>) -> Void)
/// Returns the passed byte list, to test serialization and deserialization.
func echoNullable(_ aListArg: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, FlutterError>) -> Void)
/// Returns the passed list, to test serialization and deserialization.
func echoNullable(_ aListArg: [Any?]?, completion: @escaping (Result<[Any?]?, FlutterError>) -> Void)
/// Returns the passed map, to test serialization and deserialization.
func echoNullable(_ aMapArg: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, FlutterError>) -> Void)
/// Returns the passed enum to test serialization and deserialization.
func echoNullable(_ anEnumArg: AnEnum?, completion: @escaping (Result<AnEnum?, FlutterError>) -> Void)
/// A no-op function taking no arguments and returning no value, to sanity
/// test basic asynchronous calling.
func noopAsync(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Returns the passed in generic Object asynchronously.
func echoAsync(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class FlutterIntegrationCoreApi: FlutterIntegrationCoreApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){ init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger self.binaryMessenger = binaryMessenger
@ -2307,8 +2361,12 @@ class FlutterSmallApiCodec: FlutterStandardMessageCodec {
/// A simple API called in some unit tests. /// A simple API called in some unit tests.
/// ///
/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
class FlutterSmallApi { protocol FlutterSmallApiProtocol {
func echo(_ msgArg: TestMessage, completion: @escaping (Result<TestMessage, FlutterError>) -> Void)
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class FlutterSmallApi: FlutterSmallApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){ init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger self.binaryMessenger = binaryMessenger
@ -2336,4 +2394,24 @@ class FlutterSmallApi {
} }
} }
} }
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void) {
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString", binaryMessenger: binaryMessenger, codec: codec)
channel.sendMessage([aStringArg] as [Any?]) { response in
guard let listResponse = response as? [Any?] else {
completion(.failure(FlutterError(code: "channel-error", message: "Unable to establish connection on channel.", details: "")))
return
}
if (listResponse.count > 1) {
let code: String = listResponse[0] as! String
let message: String? = nilOrValue(listResponse[1])
let details: String? = nilOrValue(listResponse[2])
completion(.failure(FlutterError(code: code, message: message, details: details)));
} else if (listResponse[0] == nil) {
completion(.failure(FlutterError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: "")))
} else {
let result = listResponse[0] as! String
completion(.success(result))
}
}
}
} }

View File

@ -1739,8 +1739,62 @@ class FlutterIntegrationCoreApiCodec: FlutterStandardMessageCodec {
/// The core interface that the Dart platform_test code implements for host /// The core interface that the Dart platform_test code implements for host
/// integration tests to call into. /// integration tests to call into.
/// ///
/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
class FlutterIntegrationCoreApi { protocol FlutterIntegrationCoreApiProtocol {
/// A no-op function taking no arguments and returning no value, to sanity
/// test basic calling.
func noop(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Responds with an error from an async function returning a value.
func throwError(completion: @escaping (Result<Any?, FlutterError>) -> Void)
/// Responds with an error from an async void function.
func throwErrorFromVoid(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Returns the passed object, to test serialization and deserialization.
func echo(_ everythingArg: AllTypes, completion: @escaping (Result<AllTypes, FlutterError>) -> Void)
/// Returns the passed object, to test serialization and deserialization.
func echoNullable(_ everythingArg: AllNullableTypes?, completion: @escaping (Result<AllNullableTypes?, FlutterError>) -> Void)
/// Returns passed in arguments of multiple types.
///
/// Tests multiple-arity FlutterApi handling.
func sendMultipleNullableTypes(aBool aNullableBoolArg: Bool?, anInt aNullableIntArg: Int64?, aString aNullableStringArg: String?, completion: @escaping (Result<AllNullableTypes, FlutterError>) -> Void)
/// Returns the passed boolean, to test serialization and deserialization.
func echo(_ aBoolArg: Bool, completion: @escaping (Result<Bool, FlutterError>) -> Void)
/// Returns the passed int, to test serialization and deserialization.
func echo(_ anIntArg: Int64, completion: @escaping (Result<Int64, FlutterError>) -> Void)
/// Returns the passed double, to test serialization and deserialization.
func echo(_ aDoubleArg: Double, completion: @escaping (Result<Double, FlutterError>) -> Void)
/// Returns the passed string, to test serialization and deserialization.
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
/// Returns the passed byte list, to test serialization and deserialization.
func echo(_ aListArg: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, FlutterError>) -> Void)
/// Returns the passed list, to test serialization and deserialization.
func echo(_ aListArg: [Any?], completion: @escaping (Result<[Any?], FlutterError>) -> Void)
/// Returns the passed map, to test serialization and deserialization.
func echo(_ aMapArg: [String?: Any?], completion: @escaping (Result<[String?: Any?], FlutterError>) -> Void)
/// Returns the passed enum to test serialization and deserialization.
func echo(_ anEnumArg: AnEnum, completion: @escaping (Result<AnEnum, FlutterError>) -> Void)
/// Returns the passed boolean, to test serialization and deserialization.
func echoNullable(_ aBoolArg: Bool?, completion: @escaping (Result<Bool?, FlutterError>) -> Void)
/// Returns the passed int, to test serialization and deserialization.
func echoNullable(_ anIntArg: Int64?, completion: @escaping (Result<Int64?, FlutterError>) -> Void)
/// Returns the passed double, to test serialization and deserialization.
func echoNullable(_ aDoubleArg: Double?, completion: @escaping (Result<Double?, FlutterError>) -> Void)
/// Returns the passed string, to test serialization and deserialization.
func echoNullable(_ aStringArg: String?, completion: @escaping (Result<String?, FlutterError>) -> Void)
/// Returns the passed byte list, to test serialization and deserialization.
func echoNullable(_ aListArg: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, FlutterError>) -> Void)
/// Returns the passed list, to test serialization and deserialization.
func echoNullable(_ aListArg: [Any?]?, completion: @escaping (Result<[Any?]?, FlutterError>) -> Void)
/// Returns the passed map, to test serialization and deserialization.
func echoNullable(_ aMapArg: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, FlutterError>) -> Void)
/// Returns the passed enum to test serialization and deserialization.
func echoNullable(_ anEnumArg: AnEnum?, completion: @escaping (Result<AnEnum?, FlutterError>) -> Void)
/// A no-op function taking no arguments and returning no value, to sanity
/// test basic asynchronous calling.
func noopAsync(completion: @escaping (Result<Void, FlutterError>) -> Void)
/// Returns the passed in generic Object asynchronously.
func echoAsync(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class FlutterIntegrationCoreApi: FlutterIntegrationCoreApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){ init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger self.binaryMessenger = binaryMessenger
@ -2307,8 +2361,12 @@ class FlutterSmallApiCodec: FlutterStandardMessageCodec {
/// A simple API called in some unit tests. /// A simple API called in some unit tests.
/// ///
/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. /// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
class FlutterSmallApi { protocol FlutterSmallApiProtocol {
func echo(_ msgArg: TestMessage, completion: @escaping (Result<TestMessage, FlutterError>) -> Void)
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class FlutterSmallApi: FlutterSmallApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){ init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger self.binaryMessenger = binaryMessenger
@ -2336,4 +2394,24 @@ class FlutterSmallApi {
} }
} }
} }
func echo(_ aStringArg: String, completion: @escaping (Result<String, FlutterError>) -> Void) {
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString", binaryMessenger: binaryMessenger, codec: codec)
channel.sendMessage([aStringArg] as [Any?]) { response in
guard let listResponse = response as? [Any?] else {
completion(.failure(FlutterError(code: "channel-error", message: "Unable to establish connection on channel.", details: "")))
return
}
if (listResponse.count > 1) {
let code: String = listResponse[0] as! String
let message: String? = nilOrValue(listResponse[1])
let details: String? = nilOrValue(listResponse[2])
completion(.failure(FlutterError(code: code, message: message, details: details)));
} else if (listResponse[0] == nil) {
completion(.failure(FlutterError(code: "null-error", message: "Flutter api returned null value for non-null return value.", details: "")))
} else {
let result = listResponse[0] as! String
completion(.success(result))
}
}
}
} }

View File

@ -4749,4 +4749,42 @@ void FlutterSmallApi::EchoWrappedList(
}); });
} }
void FlutterSmallApi::EchoString(
const std::string& a_string_arg,
std::function<void(const std::string&)>&& on_success,
std::function<void(const FlutterError&)>&& on_error) {
auto channel = std::make_unique<BasicMessageChannel<>>(
binary_messenger_,
"dev.flutter.pigeon.pigeon_integration_tests.FlutterSmallApi.echoString",
&GetCodec());
EncodableValue encoded_api_arguments = EncodableValue(EncodableList{
EncodableValue(a_string_arg),
});
channel->Send(encoded_api_arguments, [on_success = std::move(on_success),
on_error = std::move(on_error)](
const uint8_t* reply,
size_t reply_size) {
std::unique_ptr<EncodableValue> response =
GetCodec().DecodeMessage(reply, reply_size);
const auto& encodable_return_value = *response;
const auto* list_return_value =
std::get_if<EncodableList>(&encodable_return_value);
if (list_return_value) {
if (list_return_value->size() > 1) {
on_error(FlutterError(std::get<std::string>(list_return_value->at(0)),
std::get<std::string>(list_return_value->at(1)),
list_return_value->at(2)));
} else {
const auto& return_value =
std::get<std::string>(list_return_value->at(0));
on_success(return_value);
}
} else {
on_error(FlutterError("channel-error",
"Unable to establish connection on channel.",
EncodableValue("")));
}
});
}
} // namespace core_tests_pigeontest } // namespace core_tests_pigeontest

View File

@ -847,6 +847,9 @@ class FlutterSmallApi {
void EchoWrappedList(const TestMessage& msg, void EchoWrappedList(const TestMessage& msg,
std::function<void(const TestMessage&)>&& on_success, std::function<void(const TestMessage&)>&& on_success,
std::function<void(const FlutterError&)>&& on_error); std::function<void(const FlutterError&)>&& on_error);
void EchoString(const std::string& a_string,
std::function<void(const std::string&)>&& on_success,
std::function<void(const FlutterError&)>&& on_error);
private: private:
flutter::BinaryMessenger* binary_messenger_; flutter::BinaryMessenger* binary_messenger_;

View File

@ -2,7 +2,7 @@ name: pigeon
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
repository: https://github.com/flutter/packages/tree/main/packages/pigeon repository: https://github.com/flutter/packages/tree/main/packages/pigeon
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
version: 12.0.0 # This must match the version in lib/generator_tools.dart version: 12.0.1 # This must match the version in lib/generator_tools.dart
environment: environment:
sdk: ">=2.19.0 <4.0.0" sdk: ">=2.19.0 <4.0.0"