Support unpacking platform error events (#12938)
diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 941641b..8e7a1d2 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart
@@ -268,7 +268,7 @@ /// * a decoded data event (possibly null) for each successful event /// received from the platform plugin; /// * an error event containing a [PlatformException] for each error event - /// received from the platform plugin; + /// received from the platform plugin. /// /// Errors occurring during stream activation or deactivation are reported /// through the [FlutterError] facility. Stream activation happens only when @@ -279,10 +279,15 @@ StreamController<dynamic> controller; controller = new StreamController<dynamic>.broadcast(onListen: () async { BinaryMessages.setMessageHandler(name, (ByteData reply) async { - if (reply == null) + if (reply == null) { controller.close(); - else - controller.add(codec.decodeEnvelope(reply)); + } else { + try { + controller.add(codec.decodeEnvelope(reply)); + } on PlatformException catch (e) { + controller.addError(e); + } + } }); try { await methodChannel.invokeMethod('listen', arguments);
diff --git a/packages/flutter/test/services/platform_channel_test.dart b/packages/flutter/test/services/platform_channel_test.dart index bde93d0..d5e845a 100644 --- a/packages/flutter/test/services/platform_channel_test.dart +++ b/packages/flutter/test/services/platform_channel_test.dart
@@ -161,14 +161,14 @@ const MessageCodec<dynamic> jsonMessage = const JSONMessageCodec(); const MethodCodec jsonMethod = const JSONMethodCodec(); const EventChannel channel = const EventChannel('ch', jsonMethod); + void emitEvent(dynamic event) { + BinaryMessages.handlePlatformMessage( + 'ch', + event, + (ByteData reply) {}, + ); + } test('can receive event stream', () async { - void emitEvent(dynamic event) { - BinaryMessages.handlePlatformMessage( - 'ch', - event, - (ByteData reply) {}, - ); - } bool canceled = false; BinaryMessages.setMockMessageHandler( 'ch', @@ -176,13 +176,13 @@ final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message); if (methodCall['method'] == 'listen') { final String argument = methodCall['args']; - emitEvent(jsonMessage.encodeMessage(<dynamic>[argument + '1'])); - emitEvent(jsonMessage.encodeMessage(<dynamic>[argument + '2'])); + emitEvent(jsonMethod.encodeSuccessEnvelope(argument + '1')); + emitEvent(jsonMethod.encodeSuccessEnvelope(argument + '2')); emitEvent(null); - return jsonMessage.encodeMessage(<dynamic>[null]); + return jsonMethod.encodeSuccessEnvelope(null); } else if (methodCall['method'] == 'cancel') { canceled = true; - return jsonMessage.encodeMessage(<dynamic>[null]); + return jsonMethod.encodeSuccessEnvelope(null); } else { fail('Expected listen or cancel'); } @@ -193,5 +193,33 @@ await new Future<Null>.delayed(Duration.ZERO); expect(canceled, isTrue); }); + test('can receive error event', () async { + BinaryMessages.setMockMessageHandler( + 'ch', + (ByteData message) async { + final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message); + if (methodCall['method'] == 'listen') { + final String argument = methodCall['args']; + emitEvent(jsonMethod.encodeErrorEnvelope(code: '404', message: 'Not Found.', details: argument)); + return jsonMethod.encodeSuccessEnvelope(null); + } else if (methodCall['method'] == 'cancel') { + return jsonMethod.encodeSuccessEnvelope(null); + } else { + fail('Expected listen or cancel'); + } + }, + ); + final List<dynamic> events = <dynamic>[]; + final List<dynamic> errors = <dynamic>[]; + channel.receiveBroadcastStream('hello').listen(events.add, onError: errors.add); + await new Future<Null>.delayed(Duration.ZERO); + expect(events, isEmpty); + expect(errors, hasLength(1)); + expect(errors[0], const isInstanceOf<PlatformException>()); + final PlatformException error = errors[0]; + expect(error.code, '404'); + expect(error.message, 'Not Found.'); + expect(error.details, 'hello'); + }); }); }