Skip to content

Commit

Permalink
[pigeon] Channel name in flutter error. (flutter#5273)
Browse files Browse the repository at this point in the history
Adds the channel name in the connection error message on all platforms host and flutter api methods.

Also fixes a bug with error handling for swift flutter api void methods.

Also adds method to all generators to help clean up duplicated code.

fixes flutter/flutter#136277
  • Loading branch information
tarrinneal authored Nov 10, 2023
1 parent a682189 commit da3bf27
Show file tree
Hide file tree
Showing 38 changed files with 3,171 additions and 2,717 deletions.
9 changes: 9 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 13.1.0

* [swift] Fixes Flutter Api void return error handling.
* This shouldn't be breaking for anyone, but if you were incorrectly getting
success responses, you may now be failing (correctly).
* Adds method channel name to error response when channel fails to connect.
* Reduces code generation duplication.
* Changes some methods to only be generated if needed.

## 13.0.0

* **Breaking Change** [objc] Eliminates boxing of non-nullable primitive types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ protected static ArrayList<Object> wrapError(@NonNull Throwable exception) {
return errorList;
}

@NonNull
protected static FlutterError createConnectionError(@NonNull String channelName) {
return new FlutterError(
"channel-error", "Unable to establish connection on channel: " + channelName + ".", "");
}

public enum Code {
ONE(0),
TWO(1);
Expand Down Expand Up @@ -341,11 +347,10 @@ public MessageFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) {
}

public void flutterMethod(@Nullable String aStringArg, @NonNull Result<String> result) {
final String channelName =
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod";
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod",
getCodec());
new BasicMessageChannel<>(binaryMessenger, channelName, getCodec());
channel.send(
new ArrayList<Object>(Collections.singletonList(aStringArg)),
channelReply -> {
Expand All @@ -369,9 +374,7 @@ public void flutterMethod(@Nullable String aStringArg, @NonNull Result<String> r
result.success(output);
}
} else {
result.error(
new FlutterError(
"channel-error", "Unable to establish connection on channel.", ""));
result.error(createConnectionError(channelName));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ private fun wrapError(exception: Throwable): List<Any?> {
}
}

private fun createConnectionError(channelName: String): FlutterError {
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")}

/**
* Error class for passing custom error details to Flutter via a thrown PlatformException.
* @property code The error code.
Expand Down Expand Up @@ -189,7 +192,8 @@ class MessageFlutterApi(private val binaryMessenger: BinaryMessenger) {
}
}
fun flutterMethod(aStringArg: String?, callback: (Result<String>) -> Unit) {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod", codec)
val channelName = "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
channel.send(listOf(aStringArg)) {
if (it is List<*>) {
if (it.size > 1) {
Expand All @@ -201,7 +205,7 @@ class MessageFlutterApi(private val binaryMessenger: BinaryMessenger) {
callback(Result.success(output));
}
} else {
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
callback(Result.failure(createConnectionError(channelName)));
}
}
}
Expand Down
21 changes: 13 additions & 8 deletions packages/pigeon/example/app/ios/Runner/Messages.g.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ import FlutterMacOS
#error("Unsupported platform.")
#endif

private func isNullish(_ value: Any?) -> Bool {
return value is NSNull || value == nil
}

private func wrapResult(_ result: Any?) -> [Any?] {
return [result]
}
Expand All @@ -36,6 +32,14 @@ private func wrapError(_ error: Any) -> [Any?] {
]
}

private func createConnectionError(withChannelName channelName: String) -> FlutterError {
return FlutterError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "")
}

private func isNullish(_ value: Any?) -> Bool {
return value is NSNull || value == nil
}

private func nilOrValue<T>(_ value: Any?) -> T? {
if value is NSNull { return nil }
return value as! T?
Expand Down Expand Up @@ -175,18 +179,19 @@ class ExampleHostApiSetup {
}
/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
protocol MessageFlutterApiProtocol {
func flutterMethod(aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void)
func flutterMethod(aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void)
}
class MessageFlutterApi: MessageFlutterApiProtocol {
private let binaryMessenger: FlutterBinaryMessenger
init(binaryMessenger: FlutterBinaryMessenger){
self.binaryMessenger = binaryMessenger
}
func flutterMethod(aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void) {
let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod", binaryMessenger: binaryMessenger)
func flutterMethod(aString aStringArg: String?, completion: @escaping (Result<String, FlutterError>) -> Void) {
let channelName: String = "dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger)
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: "")))
completion(.failure(createConnectionError(withChannelName:channelName)))
return
}
if (listResponse.count > 1) {
Expand Down
48 changes: 28 additions & 20 deletions packages/pigeon/example/app/lib/src/messages.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
import 'package:flutter/services.dart';

PlatformException _createConnectionError(String channelName) {
return PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel: "$channelName".',
);
}

List<Object?> wrapResponse(
{Object? result, PlatformException? error, bool empty = false}) {
if (empty) {
Expand Down Expand Up @@ -97,16 +104,16 @@ class ExampleHostApi {
static const MessageCodec<Object?> codec = _ExampleHostApiCodec();

Future<String> getHostLanguage() async {
const String channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage';
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.getHostLanguage',
codec,
binaryMessenger: _binaryMessenger);
channelName,
codec,
binaryMessenger: _binaryMessenger,
);
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
throw _createConnectionError(channelName);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
Expand All @@ -124,16 +131,17 @@ class ExampleHostApi {
}

Future<int> add(int arg_a, int arg_b) async {
const String channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add';
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.add', codec,
binaryMessenger: _binaryMessenger);
channelName,
codec,
binaryMessenger: _binaryMessenger,
);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_a, arg_b]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
throw _createConnectionError(channelName);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
Expand All @@ -151,17 +159,17 @@ class ExampleHostApi {
}

Future<bool> sendMessage(MessageData arg_message) async {
const String channelName =
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage';
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.pigeon_example_package.ExampleHostApi.sendMessage',
codec,
binaryMessenger: _binaryMessenger);
channelName,
codec,
binaryMessenger: _binaryMessenger,
);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_message]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
throw _createConnectionError(channelName);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
Expand Down
46 changes: 27 additions & 19 deletions packages/pigeon/example/app/macos/Runner/messages.g.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@
#error File requires ARC to be enabled.
#endif

@implementation PGNCodeBox
- (instancetype)initWithValue:(PGNCode)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
@end

static NSArray *wrapResult(id result, FlutterError *error) {
if (error) {
return @[
Expand All @@ -34,11 +24,31 @@ - (instancetype)initWithValue:(PGNCode)value {
}
return @[ result ?: [NSNull null] ];
}

static FlutterError *createConnectionError(NSString *channelName) {
return [FlutterError
errorWithCode:@"channel-error"
message:[NSString stringWithFormat:@"%@/%@/%@",
@"Unable to establish connection on channel: '",
channelName, @"'."]
details:@""];
}

static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
id result = array[key];
return (result == [NSNull null]) ? nil : result;
}

@implementation PGNCodeBox
- (instancetype)initWithValue:(PGNCode)value {
self = [super init];
if (self) {
_value = value;
}
return self;
}
@end

@interface PGNMessageData ()
+ (PGNMessageData *)fromList:(NSArray *)list;
+ (nullable PGNMessageData *)nullableFromList:(NSArray *)list;
Expand Down Expand Up @@ -213,11 +223,12 @@ - (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)bina
}
- (void)flutterMethodAString:(nullable NSString *)arg_aString
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion {
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
messageChannelWithName:
@"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod"
binaryMessenger:self.binaryMessenger
codec:PGNMessageFlutterApiGetCodec()];
NSString *channelName =
@"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi.flutterMethod";
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel messageChannelWithName:channelName
binaryMessenger:self.binaryMessenger
codec:PGNMessageFlutterApiGetCodec()];
[channel sendMessage:@[ arg_aString ?: [NSNull null] ]
reply:^(NSArray<id> *reply) {
if (reply != nil) {
Expand All @@ -230,10 +241,7 @@ - (void)flutterMethodAString:(nullable NSString *)arg_aString
completion(output, nil);
}
} else {
completion(nil, [FlutterError
errorWithCode:@"channel-error"
message:@"Unable to establish connection on channel."
details:@""]);
completion(nil, createConnectionError(channelName));
}
}];
}
Expand Down
64 changes: 35 additions & 29 deletions packages/pigeon/example/app/windows/runner/messages.g.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ using flutter::EncodableList;
using flutter::EncodableMap;
using flutter::EncodableValue;

FlutterError CreateConnectionError(const std::string channel_name) {
return FlutterError(
"channel-error",
"Unable to establish connection on channel: '" + channel_name + "'.",
EncodableValue(""));
}

// MessageData

MessageData::MessageData(const Code& code, const EncodableMap& data)
Expand Down Expand Up @@ -263,39 +270,38 @@ void MessageFlutterApi::FlutterMethod(
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_,
const std::string channel_name =
"dev.flutter.pigeon.pigeon_example_package.MessageFlutterApi."
"flutterMethod",
&GetCodec());
"flutterMethod";
auto channel = std::make_unique<BasicMessageChannel<>>(
binary_messenger_, channel_name, &GetCodec());
EncodableValue encoded_api_arguments = EncodableValue(EncodableList{
a_string_arg ? EncodableValue(*a_string_arg) : EncodableValue(),
});
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("")));
}
});
channel->Send(
encoded_api_arguments, [channel_name, 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(CreateConnectionError(channel_name));
}
});
}

} // namespace pigeon_example
Loading

0 comments on commit da3bf27

Please sign in to comment.