blob: 9563ea97cd92f8e54fd20e6713d71a3008125582 [file] [log] [blame]
// 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.
// @dart = 2.8
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
typedef _MessageHandler = Future<ByteData> Function(ByteData);
/// This class registers web platform plugins.
///
/// An instance of this class is available as [webPluginRegistry].
class PluginRegistry {
/// Creates a plugin registry.
///
/// The argument selects the [BinaryMessenger] to use. An
/// appropriate value would be [pluginBinaryMessenger].
PluginRegistry(this._binaryMessenger);
final BinaryMessenger _binaryMessenger;
/// Creates a registrar for the given plugin implementation class.
Registrar registrarFor(Type key) => Registrar(_binaryMessenger);
/// Registers this plugin handler with the engine, so that unrecognized
/// platform messages are forwarded to the registry, where they can be
/// correctly dispatched to one of the registered plugins.
///
/// Code generated by the `flutter` tool automatically calls this method
/// for the global [webPluginRegistry] at startup.
///
/// Only one [PluginRegistry] can be registered at a time. Calling this
/// method a second time silently unregisters the first [PluginRegistry]
/// and replaces it with the new one.
///
/// This method uses a function called `webOnlySetPluginHandler` in
/// the [dart:ui] library. That function is only available when
/// compiling for the web.
void registerMessageHandler() {
// The function below is only defined in the Web dart:ui.
// ignore: undefined_function
ui.webOnlySetPluginHandler(_binaryMessenger.handlePlatformMessage);
}
}
/// A registrar for a particular plugin.
///
/// Gives access to a [BinaryMessenger] which has been configured to receive
/// platform messages from the framework side.
class Registrar {
/// Creates a registrar with the given [BinaryMessenger].
Registrar(this.messenger);
/// A [BinaryMessenger] configured to receive platform messages from the
/// framework side.
///
/// 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.messenger,
/// );
/// final MyPlugin instance = MyPlugin();
/// channel.setMethodCallHandler(instance.handleMethodCall);
/// }
/// // ...
/// }
/// ```
final BinaryMessenger messenger;
}
/// The default plugin registry for the web.
///
/// Uses [pluginBinaryMessenger] as the [BinaryMessenger].
final PluginRegistry webPluginRegistry = PluginRegistry(pluginBinaryMessenger);
/// A [BinaryMessenger] which does the inverse of the default framework
/// messenger.
///
/// Instead of sending messages from the framework to the engine, this
/// receives messages from the framework and dispatches them to registered
/// plugins.
class _PlatformBinaryMessenger extends BinaryMessenger {
final Map<String, _MessageHandler> _handlers = <String, _MessageHandler>{};
/// Receives a platform message from the framework.
@override
Future<void> handlePlatformMessage(
String channel,
ByteData data,
ui.PlatformMessageResponseCallback callback,
) async {
ByteData response;
try {
final MessageHandler handler = _handlers[channel];
if (handler != null) {
response = await handler(data);
}
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'flutter web plugins',
context: ErrorDescription('during a framework-to-plugin message'),
));
} finally {
if (callback != null) {
callback(response);
}
}
}
/// Sends a platform message from the platform side back to the framework.
@override
Future<ByteData> send(String channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>();
ui.window.onPlatformMessage(channel, message, (ByteData reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'flutter web plugins',
context: ErrorDescription('during a plugin-to-framework message'),
));
}
});
return completer.future;
}
@override
void setMessageHandler(String channel, MessageHandler handler) {
if (handler == null)
_handlers.remove(channel);
else
_handlers[channel] = handler;
}
@override
bool checkMessageHandler(String channel, MessageHandler handler) => _handlers[channel] == handler;
@override
void setMockMessageHandler(
String channel,
Future<ByteData> Function(ByteData message) handler,
) {
throw FlutterError(
'Setting mock handlers is not supported on the platform side.',
);
}
@override
bool checkMockMessageHandler(String channel, MessageHandler handler) {
throw FlutterError(
'Setting mock handlers is not supported on the platform side.',
);
}
}
/// The default [BinaryMessenger] for Flutter web plugins.
///
/// This is the value used for [webPluginRegistry]'s [PluginRegistry]
/// constructor argument.
final BinaryMessenger pluginBinaryMessenger = _PlatformBinaryMessenger();