import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import 'package:flutter/cupertino.dart'; typedef MessageCallback = void Function(dynamic message); typedef ErrorCallback = void Function(dynamic error); typedef DoneCallback = void Function(); typedef ConnectedCallback = void Function(); typedef ReconnectCallback = void Function(ReconnectStatus); enum ReconnectStatus { start, trying, success } class WebSocketService with WidgetsBindingObserver { // 单例 static final WebSocketService _instance = WebSocketService._internal(); static bool doReconnect = false; factory WebSocketService() => _instance; WebSocketService._internal(); // 初始化/销毁生命周期 void init() { WidgetsBinding.instance.addObserver(this); } void dispose() { WidgetsBinding.instance.removeObserver(this); _reconnectTimer?.cancel(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { if (doReconnect) { // 亮屏,主动检测连接 _socket?.close(); _socket = null; _startReconnect(); doReconnect = false; } } else if (state == AppLifecycleState.paused) { doReconnect = true; // 锁屏时暂停计时器 _reconnectTimer?.cancel(); _reconnectTimer = null; } } WebSocket? _socket; String? _url; bool _isConnecting = false; bool _manuallyClosed = false; Timer? _reconnectTimer; final List _messageListeners = []; final List _errorListeners = []; final List _doneListeners = []; final List _connectedListeners = []; final List _reconnectListeners = []; bool _hasTriggeredStart = false; /// 建立连接 Future connect(String url) async { _url = url; _manuallyClosed = false; _hasTriggeredStart = false; _triggerReconnectCallback(ReconnectStatus.start); await _tryConnect(); } /// 发送消息 void send(String message) { if (_socket != null && _socket!.readyState == WebSocket.open) { _socket!.add(message); } else { for (var listener in _errorListeners) { listener("WebSocket 未连接,无法发送: $message"); } } } /// 手动关闭 Future close() async { _manuallyClosed = true; _reconnectTimer?.cancel(); _reconnectTimer = null; await _socket?.close(); _socket = null; _hasTriggeredStart = false; } /// 添加监听 void addMessageListener(MessageCallback listener) => _messageListeners.add(listener); void removeMessageListener(MessageCallback listener) => _messageListeners.remove(listener); void addErrorListener(ErrorCallback listener) => _errorListeners.add(listener); void removeErrorListener(ErrorCallback listener) => _errorListeners.remove(listener); void addDoneListener(DoneCallback listener) => _doneListeners.add(listener); void removeDoneListener(DoneCallback listener) => _doneListeners.remove(listener); void addConnectedListener(ConnectedCallback listener) => _connectedListeners.add(listener); void removeConnectedListener(ConnectedCallback listener) => _connectedListeners.remove(listener); void addReconnectListener(ReconnectCallback listener) => _reconnectListeners.add(listener); void removeReconnectListener(ReconnectCallback listener) => _reconnectListeners.remove(listener); /// 内部尝试连接 Future _tryConnect() async { if (_socket != null && _socket!.readyState == WebSocket.open) return; if (_isConnecting) return; _isConnecting = true; _triggerReconnectCallback(ReconnectStatus.trying); try { _socket = await WebSocket.connect(_url!); // 连接成功回调 for (var callback in _connectedListeners) callback(); _triggerReconnectCallback(ReconnectStatus.success); _hasTriggeredStart = false; _socket!.listen( (data) { dynamic msg; try { msg = jsonDecode(data); } catch (_) { msg = data.toString(); } for (var listener in _messageListeners) listener(msg); }, onError: (error) { for (var listener in _errorListeners) listener(error); _startReconnect(); }, onDone: () { for (var listener in _doneListeners) listener(); _startReconnect(); }, cancelOnError: true, ); } catch (e) { for (var listener in _errorListeners) listener(e); _startReconnect(); } finally { _isConnecting = false; } } /// 开始重连 void _startReconnect() { if (_manuallyClosed) return; if (_reconnectTimer?.isActive ?? false) return; if (!_hasTriggeredStart) { _triggerReconnectCallback(ReconnectStatus.start); _hasTriggeredStart = true; } _reconnectTimer = Timer.periodic(const Duration(seconds: 5), (timer) { if (_socket == null || _socket!.readyState != WebSocket.open) { _triggerReconnectCallback(ReconnectStatus.trying); _tryConnect(); } else { timer.cancel(); _reconnectTimer = null; } }); } /// 触发重连状态回调 void _triggerReconnectCallback(ReconnectStatus status) { for (var listener in _reconnectListeners) { listener(status); } } }