Line data Source code
1 : import 'dart:async'; 2 : 3 : import 'package:combine/src/isolate_events.dart'; 4 : import 'package:combine/src/isolate_messenger/internal_isolate_messenger/internal_isolate_messenger.dart'; 5 : import 'package:combine/src/method_channel_middleware/isolated_method_channel_middleware.dart'; 6 : import 'package:flutter/services.dart'; 7 : import 'package:uuid/uuid.dart'; 8 : 9 : /// This class receives messages from [MethodChannel.setMessageHandler] 10 : /// registered in [MethodChannelSetup] and sends messages received from Isolate. 11 : class UIMethodChannelMiddleware { 12 : /// Creates new middleware and sets [instance]. 13 5 : UIMethodChannelMiddleware( 14 : this._binaryMessenger, 15 : this._isolateMessenger, 16 5 : ) : _idGenerator = const Uuid().v4, 17 : _methodChannels = {}; 18 : 19 : static UIMethodChannelMiddleware? instance; 20 : 21 : final BinaryMessenger _binaryMessenger; 22 : final Set<String> _methodChannels; 23 : final IdGenerator _idGenerator; 24 : final InternalIsolateMessenger _isolateMessenger; 25 : final _messageHandlersCompleter = <String, Completer<ByteData>>{}; 26 : StreamSubscription<IsolateEvent>? _methodChannelEventsSubscription; 27 : 28 : /// Starts listening for [IsolateEvent]s from Isolate and sets middleware for [MethodChannel]. 29 5 : void initialize() { 30 : instance = this; 31 5 : _bindPlatformMessageHandlers(); 32 15 : _methodChannelEventsSubscription = _isolateMessenger.messagesStream 33 15 : .where((event) => event is IsolateEvent) 34 5 : .cast<IsolateEvent>() 35 10 : .listen(_listenForMethodChannelEvents); 36 : } 37 : 38 : /// Free all resources and remove middleware from [MethodChannel]. 39 5 : Future<void> dispose() async { 40 15 : await _methodChannelEventsSubscription?.cancel(); 41 5 : _unbindPlatformMessageHandlers(); 42 : } 43 : 44 5 : void _listenForMethodChannelEvents(IsolateEvent event) { 45 5 : switch (event.runtimeType) { 46 5 : case InvokePlatformChannelEvent: 47 : final invokeEvent = event as InvokePlatformChannelEvent; 48 20 : _send(invokeEvent.channel, invokeEvent.data, invokeEvent.id); 49 : break; 50 5 : case MethodChannelResponseEvent: 51 : final responseEvent = event as MethodChannelResponseEvent; 52 15 : _methodChannelResponse(responseEvent.id, responseEvent.data); 53 : break; 54 : } 55 : } 56 : 57 : /// Send response from IsolateBloc's MessageChannel to the main 58 : /// Isolate's platform channel. 59 5 : void _methodChannelResponse(String id, ByteData? response) { 60 10 : final completer = _messageHandlersCompleter.remove(id); 61 : assert( 62 5 : completer != null, 63 : "Failed to send response from Isolate MessageChannel " 64 : "to the main Isolate's platform channel.\n", 65 : ); 66 5 : completer?.complete(response); 67 : } 68 : 69 : /// Send event to the platform and send response to the IsolateBloc's Isolate. 70 5 : Future<void> _send(String channel, ByteData? message, String id) async { 71 10 : if (!_methodChannels.contains(channel)) { 72 5 : _addPlatformMessageHandler(channel); 73 : } 74 : 75 15 : final response = await _binaryMessenger.send(channel, message); 76 15 : _isolateMessenger.send(PlatformChannelResponseEvent(response, id)); 77 : } 78 : 79 5 : void _bindPlatformMessageHandlers() { 80 15 : _methodChannels.forEach(_bindPlatformMessageHandler); 81 : } 82 : 83 5 : void _addPlatformMessageHandler(String channel) { 84 10 : _methodChannels.add(channel); 85 5 : _bindPlatformMessageHandler(channel); 86 : } 87 : 88 5 : void _bindPlatformMessageHandler(String channel) { 89 15 : _binaryMessenger.setMessageHandler(channel, (message) { 90 5 : final completer = Completer<ByteData>(); 91 10 : final id = _idGenerator(); 92 10 : _messageHandlersCompleter[id] = completer; 93 15 : _isolateMessenger.send(InvokeMethodChannelEvent(message, channel, id)); 94 : 95 5 : return completer.future; 96 : }); 97 : } 98 : 99 5 : void _unbindPlatformMessageHandlers() { 100 10 : for (final channel in _methodChannels) { 101 10 : _binaryMessenger.setMessageHandler(channel, null); 102 : } 103 : } 104 : }