mnemo_cards/games/DART_HANDLER_EXPLANATION.md
2025-11-11 02:55:41 +03:00

266 lines
No EOL
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔗 Объяснение прямого вызова 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<BridgePayload?> 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<BridgePayload?> 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<BridgePayload?> 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()` после обработки входящего сообщения.