diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 941641bf5f..8e7a1d213f 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -268,7 +268,7 @@ class EventChannel { /// * 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 @@ class EventChannel { StreamController controller; controller = new StreamController.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 bde93d085a..d5e845a90b 100644 --- a/packages/flutter/test/services/platform_channel_test.dart +++ b/packages/flutter/test/services/platform_channel_test.dart @@ -161,14 +161,14 @@ void main() { const MessageCodec 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 @@ void main() { final Map methodCall = jsonMessage.decodeMessage(message); if (methodCall['method'] == 'listen') { final String argument = methodCall['args']; - emitEvent(jsonMessage.encodeMessage([argument + '1'])); - emitEvent(jsonMessage.encodeMessage([argument + '2'])); + emitEvent(jsonMethod.encodeSuccessEnvelope(argument + '1')); + emitEvent(jsonMethod.encodeSuccessEnvelope(argument + '2')); emitEvent(null); - return jsonMessage.encodeMessage([null]); + return jsonMethod.encodeSuccessEnvelope(null); } else if (methodCall['method'] == 'cancel') { canceled = true; - return jsonMessage.encodeMessage([null]); + return jsonMethod.encodeSuccessEnvelope(null); } else { fail('Expected listen or cancel'); } @@ -193,5 +193,33 @@ void main() { await new Future.delayed(Duration.ZERO); expect(canceled, isTrue); }); + test('can receive error event', () async { + BinaryMessages.setMockMessageHandler( + 'ch', + (ByteData message) async { + final Map 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 events = []; + final List errors = []; + channel.receiveBroadcastStream('hello').listen(events.add, onError: errors.add); + await new Future.delayed(Duration.ZERO); + expect(events, isEmpty); + expect(errors, hasLength(1)); + expect(errors[0], const isInstanceOf()); + final PlatformException error = errors[0]; + expect(error.code, '404'); + expect(error.message, 'Not Found.'); + expect(error.details, 'hello'); + }); }); }