plugin_registry.dart 7.21 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:ui' as ui;
7
import 'dart:ui_web' as ui_web;
8 9 10 11

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

12 13 14 15 16 17
// Examples can assume:
// import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// import 'package:flutter/services.dart';
// import 'dart:ui_web' as ui_web;
// void handleFrameworkMessage(String name, ByteData? data, PlatformMessageResponseCallback? callback) { }

18
/// A registrar for Flutter plugins implemented in Dart.
19
///
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/// Plugins for the web platform are implemented in Dart and are
/// registered with this class by code generated by the `flutter` tool
/// when compiling the application.
///
/// This class implements [BinaryMessenger] to route messages from the
/// framework to registered plugins.
///
/// Use this [BinaryMessenger] when creating platform channels in order for
/// them to receive messages from the platform side. For example:
///
/// ```dart
/// class MyPlugin {
///   static void registerWith(Registrar registrar) {
///     final MethodChannel channel = MethodChannel(
///       'com.my_plugin/my_plugin',
///       const StandardMethodCodec(),
///       registrar, // the registrar is used as the BinaryMessenger
///     );
///     final MyPlugin instance = MyPlugin();
///     channel.setMethodCallHandler(instance.handleMethodCall);
///   }
41 42 43 44 45
///
///   Future<dynamic> handleMethodCall(MethodCall call) async {
///     // ...
///   }
///
46 47 48 49 50
///   // ...
/// }
/// ```
class Registrar extends BinaryMessenger {
  /// Creates a [Registrar].
51
  ///
52 53 54 55 56 57 58 59 60 61 62 63 64 65
  /// The argument is ignored. To create a test [Registrar] with custom behavior,
  /// subclass the [Registrar] class and override methods as appropriate.
  Registrar([
    @Deprecated(
      'This argument is ignored. '
      'This feature was deprecated after v1.24.0-7.0.pre.'
    )
    BinaryMessenger? binaryMessenger,
  ]);

  /// Registers the registrar's message handler
  /// ([handlePlatformMessage]) with the engine, so that plugin
  /// messages are correctly dispatched to the relevant registered
  /// plugin.
66
  ///
67 68 69 70
  /// Only one handler can be registered at a time. Calling this
  /// method a second time silently unregisters any
  /// previously-registered handler and replaces it with the handler
  /// from this object.
71
  ///
72 73
  /// This method uses a function called `setPluginHandler` in
  /// the [dart:ui_web] library. That function is only available when
74
  /// compiling for the web.
75
  void registerMessageHandler() {
76
    ui_web.setPluginHandler(handleFrameworkMessage);
77 78
  }

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  /// Receives a platform message from the framework.
  ///
  /// This method has been replaced with the more clearly-named [handleFrameworkMessage].
  @Deprecated(
    'Use handleFrameworkMessage instead. '
    'This feature was deprecated after v1.24.0-7.0.pre.'
  )
  @override
  Future<void> handlePlatformMessage(
    String channel,
    ByteData? data,
    ui.PlatformMessageResponseCallback? callback,
  ) => handleFrameworkMessage(channel, data, callback);

  /// Message handler for web plugins.
  ///
  /// This method is called when handling messages from the framework.
96
  ///
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
  /// If a handler has been registered for the given `channel`, it is
  /// invoked, and the value it returns is passed to `callback` (if that
  /// is non-null). Then, the method's future is completed.
  ///
  /// If no handler has been registered for that channel, then the
  /// callback (if any) is invoked with null, then the method's future
  /// is completed.
  ///
  /// Messages are not buffered (unlike platform messages headed to
  /// the framework, which are managed by [ChannelBuffers]).
  ///
  /// This method is registered as the message handler by code
  /// autogenerated by the `flutter` tool when the application is
  /// compiled, if any web plugins are used. The code in question is
  /// the following:
112
  ///
113
  /// ```dart
114
  /// ui_web.setPluginHandler(handleFrameworkMessage);
115
  /// ```
116
  Future<void> handleFrameworkMessage(
117
    String channel,
118 119
    ByteData? data,
    ui.PlatformMessageResponseCallback? callback,
120
  ) async {
121
    ByteData? response;
122
    try {
123
      final MessageHandler? handler = _handlers[channel];
124 125 126 127 128 129 130
      if (handler != null) {
        response = await handler(data);
      }
    } catch (exception, stack) {
      FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: stack,
131 132
        library: 'flutter web plugins',
        context: ErrorDescription('during a framework-to-plugin message'),
133 134
      ));
    } finally {
135 136 137
      if (callback != null) {
        callback(response);
      }
138 139 140
    }
  }

141 142 143 144 145 146 147 148 149
  /// Returns `this`.
  @Deprecated(
    'This property is redundant. It returns the object on which it is called. '
    'This feature was deprecated after v1.24.0-7.0.pre.'
  )
  BinaryMessenger get messenger => this;

  final Map<String, MessageHandler> _handlers = <String, MessageHandler>{};

150 151
  /// Sends a platform message from the platform side back to the framework.
  @override
152 153
  Future<ByteData?> send(String channel, ByteData? message) {
    final Completer<ByteData?> completer = Completer<ByteData?>();
154
    ui.channelBuffers.push(channel, message, (ByteData? reply) {
155 156 157 158 159 160
      try {
        completer.complete(reply);
      } catch (exception, stack) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
161
          library: 'flutter web plugins',
162 163 164 165 166
          context: ErrorDescription('during a plugin-to-framework message'),
        ));
      }
    });
    return completer.future;
167 168 169
  }

  @override
170
  void setMessageHandler(String channel, MessageHandler? handler) {
171
    if (handler == null) {
172
      _handlers.remove(channel);
173
    } else {
174
      _handlers[channel] = handler;
175
    }
176 177 178
  }
}

179 180 181 182
/// This class was previously separate from [Registrar] but was merged into it
/// as part of a simplification of the web plugins API.
@Deprecated(
  'Use Registrar instead. '
183
  'This feature was deprecated after v1.26.0-18.0.pre.'
184 185 186 187 188
)
class PluginRegistry extends Registrar {
  /// Creates a [Registrar].
  ///
  /// The argument is ignored.
189 190 191 192
  @Deprecated(
    'Use Registrar instead. '
    'This feature was deprecated after v1.26.0-18.0.pre.'
  )
193 194 195
  PluginRegistry([
    @Deprecated(
      'This argument is ignored. '
196
      'This feature was deprecated after v1.26.0-18.0.pre.'
197 198
    )
    BinaryMessenger? binaryMessenger,
199
  ]) : super();
200 201 202 203

  /// Returns `this`. The argument is ignored.
  @Deprecated(
    'This method is redundant. It returns the object on which it is called. '
204
    'This feature was deprecated after v1.26.0-18.0.pre.'
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
  )
  Registrar registrarFor(Type key) => this;
}

/// The default plugin registrar for the web.
final Registrar webPluginRegistrar = PluginRegistry();

/// A deprecated alias for [webPluginRegistrar].
@Deprecated(
  'Use webPluginRegistrar instead. '
  'This feature was deprecated after v1.24.0-7.0.pre.'
)
PluginRegistry get webPluginRegistry => webPluginRegistrar as PluginRegistry;

/// A deprecated alias for [webPluginRegistrar].
@Deprecated(
  'Use webPluginRegistrar instead. '
  'This feature was deprecated after v1.24.0-7.0.pre.'
)
BinaryMessenger get pluginBinaryMessenger => webPluginRegistrar;