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