# 🔗 Объяснение прямого вызова Dart кода из JavaScript ## 📋 **Новый подход: Прямой вызов Dart функции** ### 🎯 **Принцип:** Вместо создания заглушки, мы устанавливаем настоящий Dart обработчик **до** инициализации JavaScript bridge, обеспечивая его готовность к моменту первого вызова. ### 📜 **JavaScript код (hostBridgeScript):** ```javascript window.flutterBridge = { // Send message from Web to Host sendMessage: function(message) { console.log('[Flutter Bridge] Отправка сообщения в Flutter Host:', message); window.flutter_inappwebview.callHandler('flutterBridge', message); }, // Receive message from Host to Web - ПРЯМОЙ ВЫЗОВ DART receiveMessage: function(message) { console.log('[Flutter Bridge] Получение сообщения от Flutter Host:', message); // Прямой вызов Dart функции window.dartHandler(message); } }; ``` ### 🔄 **Порядок инициализации:** #### 1. **Установка Dart обработчика** (WebBridge._setupDartHandler()) ```dart // В web_bridge.dart - ВЫПОЛНЯЕТСЯ ПЕРВЫМ void _setupDartHandler() { js.context['dartHandler'] = (String message) { // Настоящий Dart обработчик final bridgeMessage = BridgeMessage.fromJson(jsonDecode(message)); _bridgeManager!.handleIncomingMessage(bridgeMessage); }; } ``` #### 2. **Инициализация BridgeManager** (WebBridge._initializeBridgeManager()) ```dart // В web_bridge.dart - ВЫПОЛНЯЕТСЯ ВТОРЫМ _bridgeManager!.initialize(); // WebTransport.initialize() без заглушки ``` ### ✅ **Преимущества нового подхода:** - **Нет заглушки** - исключены ошибки "Dart обработчик не определен" - **Прямой вызов** - JavaScript сразу вызывает настоящий Dart код - **Простота** - меньше промежуточных звеньев - **Надежность** - нет проблем с timing'ом --- ## 🎯 **Где устанавливаются настоящие Payload Handlers?** ### 📍 **Место установки:** Настоящие payload handlers устанавливаются в **Dart коде** в методе `_registerHandlers()` класса `WebBridge`. ### 🔧 **Процесс установки:** #### 1. **Создание BridgeManager** ```dart // В web_bridge.dart _bridgeManager = BridgeManagerFactory.createWebManager( evaluateJavaScript: (script) { ... }, sendToHost: (jsonString) { ... }, ); ``` #### 2. **Регистрация handlers** ```dart // В web_bridge.dart -> _registerHandlers() _bridgeManager!.registerHandler('ping', PingHandler(sendPayload)); _bridgeManager!.registerHandler('ping_response', PingResponseHandler()); _bridgeManager!.registerHandler('user_info_response', UserInfoResponseHandler()); _bridgeManager!.registerHandler('login_response', LoginResponseHandler()); _bridgeManager!.registerHandler('quiz_submission_response', QuizResponseHandler()); ``` #### 3. **Настройка callback** ```dart // В web_bridge.dart _bridgeManager!.onPayloadReceived = (payload) { debugPrint('📥 [WebBridge] Получен payload через callback: ${payload.runtimeType}'); onPayloadReceived?.call(payload); }; ``` --- ## 🎯 **Где происходит вызов Dart кода из JS (payload handlers)?** ### 📍 **Точка входа:** Вызов Dart кода из JavaScript происходит в методе `_handleIncomingMessage()` класса `BridgeManager`. ### 🔄 **Полная цепочка вызова:** #### 1. **JavaScript → Dart** (в web_bridge.dart): ```dart // Настоящий Dart обработчик, установленный в _setupDartHandler() js.context['dartHandler'] = (String message) { // 1. Парсим JSON final json = jsonDecode(message); // 2. Создаем BridgeMessage final bridgeMessage = BridgeMessage.fromJson(json); // 3. Передаем в BridgeManager _bridgeManager!.handleIncomingMessage(bridgeMessage); }; ``` #### 2. **BridgeManager → Payload Handler** (в bridge_manager.dart): ```dart // В BridgeManager._handleIncomingMessage() void _handleIncomingMessage(BridgeMessage message) { // 1. Находим handler по типу final type = message.type; final handler = _handlers[type]; // ← Здесь происходит поиск зарегистрированного handler if (handler != null) { // 2. Десериализуем payload final payload = PayloadRegistry.deserialize(message); if (payload != null) { // 3. Вызываем callback if (onPayloadReceived != null) { onPayloadReceived!.call(payload); } // 4. ВЫЗЫВАЕМ НАСТОЯЩИЙ PAYLOAD HANDLER ← ЗДЕСЬ! handler.handle(payload).then((response) { if (response != null) { sendPayload(response); } }); } } } ``` #### 3. **Payload Handler выполняется** (в payload_handlers.dart): ```dart // Пример: PingHandler.handle() class PingHandler implements PayloadHandler { @override Future handle(BridgePayload payload) async { if (payload is PingPayload) { // ← ЗДЕСЬ ВЫПОЛНЯЕТСЯ БИЗНЕС-ЛОГИКА! debugPrint('🏓 [PingHandler] Обработка ping: "${payload.message}"'); // Отправляем pong обратно final pongPayload = payload.toPong(); _sendPayload(pongPayload); } return null; } } ``` --- ## 🔄 **Полная цепочка обработки сообщений:** ### 📥 **Входящее сообщение (Host → Web):** ``` 1. Flutter Host отправляет BridgeMessage ↓ 2. JavaScript: window.flutterBridge.receiveMessage(message) ↓ 3. JavaScript: window.dartHandler(message) ← ПРЯМОЙ ВЫЗОВ DART ↓ 4. Dart: js.context['dartHandler'](message) ← В web_bridge.dart ↓ 5. Dart: BridgeMessage.fromJson(jsonDecode(message)) ↓ 6. Dart: _bridgeManager!.handleIncomingMessage(bridgeMessage) ← В bridge_manager.dart ↓ 7. Dart: BridgeManager находит handler по типу payload ↓ 8. Dart: handler.handle(payload) ← НАСТОЯЩИЙ PAYLOAD HANDLER! ← В payload_handlers.dart ``` ### 📤 **Исходящее сообщение (Web → Host):** ``` 1. Dart: sendPayload(payload) ↓ 2. Dart: _bridgeManager!.sendPayload(payload) ↓ 3. Dart: BridgeManager создает BridgeMessage ↓ 4. Dart: jsonEncode(bridgeMessage.toJson()) ↓ 5. Dart: sendToHost(jsonString) ↓ 6. JavaScript: flutterBridge.callMethod('sendMessage', [jsonString]) ↓ 7. Flutter Host получает сообщение ``` --- ## 🎯 **Примеры Payload Handlers:** ### 🏓 **PingHandler** (обрабатывает входящие ping): ```dart class PingHandler implements PayloadHandler { final Function(BridgePayload) _sendPayload; @override Future handle(BridgePayload payload) async { if (payload is PingPayload) { // Получили ping, отправляем pong обратно final pongPayload = payload.toPong(); _sendPayload(pongPayload); } return null; } } ``` ### 👤 **UserInfoResponseHandler** (обрабатывает ответы с данными пользователя): ```dart class UserInfoResponseHandler implements PayloadHandler { @override Future handle(BridgePayload payload) async { if (payload is UserInfoResponsePayload) { // Обрабатываем полученные данные пользователя debugPrint('Данные пользователя: ${payload.userInfo}'); } return null; } } ``` --- ## 🔑 **Ключевые моменты:** ### ✅ **Новый подход:** - **Нет заглушки** - исключены ошибки "Dart обработчик не определен" - **Прямой вызов** - JavaScript сразу вызывает настоящий Dart код - **Правильный порядок** - Dart обработчик устанавливается до инициализации bridge ### ✅ **Payload Handlers:** - Устанавливаются в **Dart коде** - Обрабатывают **типизированные payload'ы** - Содержат **бизнес-логику** приложения - Регистрируются в **BridgeManager** - **Вызываются** в `BridgeManager._handleIncomingMessage()` ### ✅ **Порядок инициализации:** 1. `_setupDartHandler()` → Настоящий Dart обработчик установлен 2. `_bridgeManager!.initialize()` → JavaScript bridge готов 3. `_registerHandlers()` → Payload handlers зарегистрированы ### ✅ **Точка вызова Payload Handlers:** - **Место:** `BridgeManager._handleIncomingMessage()` - **Условие:** `handler.handle(payload)` - **Контекст:** После десериализации payload и вызова callback --- **Итог:** Убрана заглушка, теперь JavaScript напрямую вызывает Dart функцию. Dart обработчик устанавливается до инициализации bridge, что исключает ошибки timing'а. Настоящие payload handlers вызываются в `BridgeManager._handleIncomingMessage()` после обработки входящего сообщения.