| // 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' show Completer; |
| import 'dart:isolate' show ReceivePort; |
| import 'dart:ui' as ui; |
| |
| import 'package:flutter/foundation.dart'; |
| import 'binary_messenger.dart'; |
| import 'binding.dart'; |
| |
| /// A [BinaryMessenger] for use on background (non-root) isolates. |
| class BackgroundIsolateBinaryMessenger extends BinaryMessenger { |
| BackgroundIsolateBinaryMessenger._(); |
| |
| final ReceivePort _receivePort = ReceivePort(); |
| final Map<int, Completer<ByteData?>> _completers = |
| <int, Completer<ByteData?>>{}; |
| int _messageCount = 0; |
| |
| /// The existing instance of this class, if any. |
| /// |
| /// Throws if [ensureInitialized] has not been called at least once. |
| static BinaryMessenger get instance { |
| if (_instance == null) { |
| throw StateError( |
| 'The BackgroundIsolateBinaryMessenger.instance value is invalid ' |
| 'until BackgroundIsolateBinaryMessenger.ensureInitialized is ' |
| 'executed.'); |
| } |
| return _instance!; |
| } |
| |
| static BinaryMessenger? _instance; |
| |
| /// Ensures that [BackgroundIsolateBinaryMessenger.instance] has been initialized. |
| /// |
| /// The argument should be the value obtained from [ServicesBinding.rootIsolateToken] |
| /// on the root isolate. |
| /// |
| /// This function is idempotent (calling it multiple times is harmless but has no effect). |
| static void ensureInitialized(ui.RootIsolateToken token) { |
| if (_instance == null) { |
| ui.PlatformDispatcher.instance.registerBackgroundIsolate(token); |
| final BackgroundIsolateBinaryMessenger portBinaryMessenger = |
| BackgroundIsolateBinaryMessenger._(); |
| _instance = portBinaryMessenger; |
| portBinaryMessenger._receivePort.listen((dynamic message) { |
| try { |
| final List<dynamic> args = message as List<dynamic>; |
| final int identifier = args[0] as int; |
| final Uint8List bytes = args[1] as Uint8List; |
| final ByteData byteData = ByteData.sublistView(bytes); |
| portBinaryMessenger._completers |
| .remove(identifier)! |
| .complete(byteData); |
| } catch (exception, stack) { |
| FlutterError.reportError(FlutterErrorDetails( |
| exception: exception, |
| stack: stack, |
| library: 'services library', |
| context: |
| ErrorDescription('during a platform message response callback'), |
| )); |
| } |
| }); |
| } |
| } |
| |
| @override |
| Future<void> handlePlatformMessage(String channel, ByteData? data, |
| ui.PlatformMessageResponseCallback? callback) { |
| throw UnimplementedError('handlePlatformMessage is deprecated.'); |
| } |
| |
| @override |
| Future<ByteData?>? send(String channel, ByteData? message) { |
| final Completer<ByteData?> completer = Completer<ByteData?>(); |
| _messageCount += 1; |
| final int messageIdentifier = _messageCount; |
| _completers[messageIdentifier] = completer; |
| ui.PlatformDispatcher.instance.sendPortPlatformMessage( |
| channel, |
| message, |
| messageIdentifier, |
| _receivePort.sendPort, |
| ); |
| return completer.future; |
| } |
| |
| @override |
| void setMessageHandler(String channel, MessageHandler? handler) { |
| throw UnsupportedError( |
| 'Background isolates do not support setMessageHandler(). Messages from the host platform always go to the root isolate.'); |
| } |
| } |