| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import 'package:flutter/services.dart'; |
| |
| import 'plugin_registry.dart'; |
| |
| /// A named channel for sending events to the framework-side using streams. |
| /// |
| /// This is the platform-side equivalent of [EventChannel]. Whereas |
| /// [EventChannel] receives a stream of events from platform plugins, this |
| /// channel sends a stream of events to the handler listening on the |
| /// framework-side. |
| /// |
| /// The channel [name] must not be null. If no [codec] is provided, then |
| /// [StandardMethodCodec] is used. If no [binaryMessenger] is provided, then |
| /// [pluginBinaryMessenger], which sends messages to the framework-side, |
| /// is used. |
| class PluginEventChannel<T> { |
| /// Creates a new plugin event channel. |
| const PluginEventChannel( |
| this.name, [ |
| this.codec = const StandardMethodCodec(), |
| BinaryMessenger binaryMessenger, |
| ]) : assert(name != null), |
| assert(codec != null), |
| _binaryMessenger = binaryMessenger; |
| |
| /// The logical channel on which communication happens. |
| /// |
| /// This must not be null. |
| final String name; |
| |
| /// The message codec used by this channel. |
| /// |
| /// This must not be null. This defaults to [StandardMethodCodec]. |
| final MethodCodec codec; |
| |
| /// The messenger used by this channel to send platform messages. |
| /// |
| /// This must not be null. If not provided, defaults to |
| /// [pluginBinaryMessenger], which sends messages from the platform-side |
| /// to the framework-side. |
| BinaryMessenger get binaryMessenger => |
| _binaryMessenger ?? pluginBinaryMessenger; |
| final BinaryMessenger _binaryMessenger; |
| |
| /// Set the stream controller for this event channel. |
| set controller(StreamController<T> controller) { |
| final _EventChannelHandler<T> handler = _EventChannelHandler<T>( |
| name, |
| codec, |
| controller, |
| binaryMessenger, |
| ); |
| binaryMessenger.setMessageHandler( |
| name, controller == null ? null : handler.handle); |
| } |
| } |
| |
| class _EventChannelHandler<T> { |
| _EventChannelHandler(this.name, this.codec, this.controller, this.messenger); |
| |
| final String name; |
| final MethodCodec codec; |
| final StreamController<T> controller; |
| final BinaryMessenger messenger; |
| |
| StreamSubscription<T> subscription; |
| |
| Future<ByteData> handle(ByteData message) { |
| final MethodCall call = codec.decodeMethodCall(message); |
| switch (call.method) { |
| case 'listen': |
| return _listen(); |
| case 'cancel': |
| return _cancel(); |
| } |
| return null; |
| } |
| |
| // TODO(hterkelsen): Support arguments. |
| Future<ByteData> _listen() async { |
| if (subscription != null) { |
| await subscription.cancel(); |
| } |
| subscription = controller.stream.listen((dynamic event) { |
| messenger.send(name, codec.encodeSuccessEnvelope(event)); |
| }, onError: (dynamic error) { |
| messenger.send(name, |
| codec.encodeErrorEnvelope(code: 'error', message: error.toString())); |
| }); |
| |
| return codec.encodeSuccessEnvelope(null); |
| } |
| |
| // TODO(hterkelsen): Support arguments. |
| Future<ByteData> _cancel() async { |
| if (subscription == null) { |
| return codec.encodeErrorEnvelope( |
| code: 'error', message: 'No active stream to cancel.'); |
| } |
| await subscription.cancel(); |
| subscription = null; |
| return codec.encodeSuccessEnvelope(null); |
| } |
| } |