FlutterBridge监听修改一对多

This commit is contained in:
zhulixiao
2026-01-27 10:00:40 +08:00
parent d71234da78
commit e54e11fef1

View File

@@ -4,6 +4,7 @@ import 'dart:html' as html;
import 'package:js/js.dart';
import 'package:web_tools/utils/model/model.dart';
import 'package:flutter/foundation.dart';
// h5交互通知 原生 {type:'enum',data:'所需参数,可无'}
enum ToFlutterAppEnum {
@@ -105,12 +106,9 @@ enum WebInteractionType {
taskKeyOtherPage('TaskKeyOtherPage'), // 其他页面
taskKeyMineBackpack('TaskKeyMineBackpack'), // 我的装扮背包页面(或者是称号)
taskKeyMineWallet('TaskKeyMineWallet'), // 我的钱包页面
unknown('unknown'),
;
unknown('unknown');
const WebInteractionType(
this.code,
);
const WebInteractionType(this.code);
final String code; //服务端 key
factory WebInteractionType.fromCode(String? code) => values.firstWhere(
@@ -146,7 +144,9 @@ class FlutterBridge {
// 取消监听 'translateResult' 类型的消息
FlutterBridge.instance.off(FromJsEnum.translateResult.code);
* */
final _messageListeners = <String, Function(Map<String, dynamic>)>{};
// final _messageListeners = <String, Function(Map<String, dynamic>)>{};
// 1. 修改这里Value 从 Function 变成 List<Function>
final _messageListeners = <String, List<Function(Map<String, dynamic>)>>{};
var textMap = <String, String>{}; //多语言翻译
FlutterBridge._internal() {
@@ -160,8 +160,19 @@ class FlutterBridge {
try {
final Map<String, dynamic> data = jsonDecode(event.data);
final String? type = data['type'];
// 找到监听列表,遍历调用
if (type != null && _messageListeners.containsKey(type)) {
_messageListeners[type]?.call(data);
final listeners = _messageListeners[type];
if (listeners != null && listeners.isNotEmpty) {
// 使用 List.from 浅拷贝一份进行遍历,防止在回调中移除监听导致并发修改异常
for (final callback in List.from(listeners)) {
try {
callback(data); // 这里的 data 是已经解析好的 Map
} catch (e) {
print("Error in listener callback: $e");
}
}
}
}
print('Invalid message format from Flutter: $type');
} catch (e) {
@@ -170,8 +181,19 @@ class FlutterBridge {
} else {
try {
final String? type = event.data['type'];
// 找到监听列表,遍历调用
if (type != null && _messageListeners.containsKey(type)) {
_messageListeners[type]?.call(event.data);
final listeners = _messageListeners[type];
if (listeners != null && listeners.isNotEmpty) {
// 使用 List.from 浅拷贝一份进行遍历,防止在回调中移除监听导致并发修改异常
for (final callback in List.from(listeners)) {
try {
callback(event.data); // 这里的 data 是已经解析好的 Map
} catch (e) {
print("Error in listener callback: $e");
}
}
}
}
print('Invalid message format from Flutter: $type');
} catch (e) {
@@ -181,24 +203,56 @@ class FlutterBridge {
});
}
// 注册监听某个 type 的消息
void on(String type, Function(Map<String, dynamic>) callback) {
if (_messageListeners.containsKey(type)) {
print("Listener for '$type' is already registered.");
return; // 如果已经注册了这个类型的监听器,就不再重复添加
}
_messageListeners[type] = callback;
print("Listener for '$type' has been registered.");
/// 仅监听一次,触发后自动移除
void once(String type, Function(Map<String, dynamic>) callback) {
// 定义一个引用,用于在回调内部取消自己
VoidCallback? cancelRef;
// 注册监听
cancelRef = on(type, (data) {
// 1. 立即移除监听
cancelRef?.call();
// 2. 执行真正的业务回调
callback(data);
});
}
// 取消监听某个 type 的消息
void off(String type) {
/// 3. 核心修改on 方法
/// 返回一个 VoidCallback调用它即可取消本次监听
VoidCallback on(String type, Function(Map<String, dynamic>) callback) {
if (!_messageListeners.containsKey(type)) {
print("No listener found for '$type'.");
return; // 如果没有找到监听器,直接返回
_messageListeners[type] = [];
}
_messageListeners[type]!.add(callback);
print(
"Listener added for '$type'. Total listeners: ${_messageListeners[type]!.length}",
);
// 返回一个闭包,用于精确移除当前的 callback
return () {
if (_messageListeners.containsKey(type)) {
_messageListeners[type]?.remove(callback);
print(
"One listener removed for '$type'. Remaining: ${_messageListeners[type]?.length}",
);
// 如果该类型没有监听者了,可以选择清理 key
if (_messageListeners[type]!.isEmpty) {
_messageListeners.remove(type);
print("Listener for '$type' has been removed.");
}
}
};
}
/// 4. 兼容旧代码的 off 方法
/// 警告:这会移除该类型下的【所有】监听器
void off(String type) {
if (_messageListeners.containsKey(type)) {
_messageListeners.remove(type);
print("All listeners for '$type' have been removed.");
}
}
// 发送消息给 App通过 WebView 调用 JS 方法)
@@ -238,25 +292,30 @@ class FlutterBridge {
void toRecharge() => sendToFlutter(ToFlutterAppEnum.toRecharge.code, {});
void toRedDiamond() => sendToFlutter(ToFlutterAppEnum.toRedDiamond.code, {});
void jumpToH5(String path, String title) => sendToFlutter(
ToFlutterAppEnum.jumpToH5.code, {'path': path, 'title': title});
ToFlutterAppEnum.jumpToH5.code,
{'path': path, 'title': title},
);
void toHomepage(String userId) =>
sendToFlutter(ToFlutterAppEnum.toHomepage.code, {'userId': userId});
void toMonthCardPay(String googleProductId, String iosProductId,
{otherUserId = ''}) =>
sendToFlutter(ToFlutterAppEnum.toMonthCardPay.code, {
void toMonthCardPay(
String googleProductId,
String iosProductId, {
otherUserId = '',
}) => sendToFlutter(ToFlutterAppEnum.toMonthCardPay.code, {
'googleProductId': googleProductId,
'iosProductId': iosProductId,
'otherUserId': otherUserId,
});
void checkGameState(String gameCode) => sendToFlutter(
ToFlutterAppEnum.checkGameState.code, {'gameCode': gameCode});
ToFlutterAppEnum.checkGameState.code,
{'gameCode': gameCode},
);
void share({
required String activityId, // 活动id
required bool needShareReport, // 是否需要上报分享数据
ShareCardModel? shareCardModel, // 分享上方卡片 数据,参考客户端参数
}) =>
sendToFlutter(ToFlutterAppEnum.share.code, {
}) => sendToFlutter(ToFlutterAppEnum.share.code, {
"activityId": activityId,
"shareReportKey": needShareReport ? "ActivityShared" : "",
...shareCardModel?.toJson() ?? {},
@@ -268,14 +327,19 @@ class FlutterBridge {
//解析 URL 并跳转
void taskCommandJump({required String scheme, required String activityId}) =>
sendToFlutter(ToFlutterAppEnum.showCommandJump.code,
{"scheme": scheme, "activityId": activityId});
sendToFlutter(ToFlutterAppEnum.showCommandJump.code, {
"scheme": scheme,
"activityId": activityId,
});
//跳转至网页
void taskToWebViewPage(
{required String linkUrl, required String activityId}) =>
sendToFlutter(ToFlutterAppEnum.showToWebViewPage.code,
{"linkUrl": linkUrl, "activityId": activityId});
void taskToWebViewPage({
required String linkUrl,
required String activityId,
}) => sendToFlutter(ToFlutterAppEnum.showToWebViewPage.code, {
"linkUrl": linkUrl,
"activityId": activityId,
});
void checkStartBroadcaster() =>
sendToFlutter(ToFlutterAppEnum.checkStartBroadcaster.code, {});
@@ -296,7 +360,7 @@ class FlutterBridge {
/** 在直播间或聊天室停留观看n分钟 */
void shouldWatchDuration() =>
sendToFlutter(ToFlutterAppEnum.shouldWatchDuration.code, {});
/** 在直播间或聊天室发送n条公屏消息 */
/** 在直播间或聊天室发送n条公屏消息 */
void shouldSendPublicMessage() =>
sendToFlutter(ToFlutterAppEnum.shouldSendPublicMessage.code, {});
/** 在直播间或聊天室上麦互动n分钟 */
@@ -311,7 +375,7 @@ class FlutterBridge {
/** 分享n次直播间或聊天室至任意平台 */
void shouldShareRoom() =>
sendToFlutter(ToFlutterAppEnum.shouldShareRoom.code, {});
/** 佩戴任意装扮 */
/** 佩戴任意装扮 */
void shouldWearDecoration() =>
sendToFlutter(ToFlutterAppEnum.shouldWearDecoration.code, {});
/** 前往语音房 */