美文网首页
Flutter-WebSocket策略

Flutter-WebSocket策略

作者: SmallHer | 来源:发表于2025-03-04 15:57 被阅读0次

一,程序入口绑定url

void main() async {
  ...
  WebSocketManager().url = XXConfig.webSocketAlphaUrl;
 ...
  runApp(config);
}

二,登录成功后注册WebSocket,比如在TabPage中

 @override
  void initState() {
    super.initState();
    ...
    // 创建链接
    if (context.mounted) {
      WebSocketManager().connect(context: context);
    }
  }
@override
  void dispose() {
    super.dispose();
    WebSocketManager().close();
  }
@override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      print("应用回到前台");
      WebSocketManager().checkConnect();
    } else if (state == AppLifecycleState.paused) {
      print("应用退到后台");
    } else if (state == AppLifecycleState.detached) {
      print("应用退出");
    }
  }

三,WebSocketManager中实现逻辑

心跳间隔3秒;
断连后重连,重连间隔3秒,次数最大10次,达到最大时倒计时100秒后重连;
发送特定连接前判断连接状态;
只维持一个计时器

class WebSocketManager {
  static WebSocketManager? _instance;
  static WebSocketChannel? _channel;
  String? roomId = "";
  String url = "";

  ///timer
  int _countdown = 3; // 心跳计时数
  int _reCountdown = 0; // 重连计时数
  static Timer? _countdownTimer; // 计时器
  /// 重连次数上限
  final int MAX_RECONNECT_ATTEMPTS = 10;
   /// 重连次数
  int _reconnectAttempts = 0;
  bool lockReconnect = false;
  String? token = "";
  BuildContext? context;

  factory WebSocketManager() {
    _instance ??= WebSocketManager._();
    return _instance!;
  }

  WebSocketManager._();

  ///判断是否断开,断开重连
  void checkConnect() {
    if (_channel == null) {
      _reconnectAttempts = 0;
      reConnect();
    }
  }

  /// 连接
  void connect({BuildContext? context}) {
    if (context != null) {
      ///初次链接
      this.context = context;
      token = UserManager.instance.userInfo?.token;
    }
    /// 判断是否已经连接
    if (_channel != null) {
      print("已经连接,请勿重新连接");
      return;
    }
    /// 连接
    _channel = WebSocketChannel.connect(
      Uri.parse(url),
    );
    /// 开始计时器
    startRecordTime();
    
    _countdown = 3;
    
    /// 收到消息
    onMessage.listen((message) {
      _reconnectAttempts = 0;
      // 处理接收到的消息
      handleMessage(message);
    }, onError: (error) {
      print("连接服务器失败error=$error");
      reConnect();
    } ,onDone: () {
      print("重连");
      reConnect();
    });
  }
  /// 重连
  void reConnect() {
    if (_reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
      print("重连次数已达上限");
      _reCountdown = 100;
      _reconnectAttempts = 0;
      return;
    }
    if (lockReconnect) {
      return;
    }
    lockReconnect = true;
    _reCountdown = 3;
  }

  void reConnectAction() {
    // 关闭之前的连接
      close();
      // 重连次数加一
      _reconnectAttempts++;
      //重连
      connect();
      lockReconnect = false;
      print("重连次数:${_reconnectAttempts}");
  }

  // 发送心跳
  void sendLink() {
    if ((token?.length ?? 0) > 0) {
      Map<String, dynamic> map = {
        "Authorization": "Bearer $token",
        "code": 10000,
        "data": {"prescriptionOrderId": roomId ?? ""}
      };
      _channel?.sink.add(jsonEncode(map));
    }
  }

  // 进入处方编辑
  void sendEnterEdit(String id, BuildContext context) {
    if (_channel == null) {
      connect();
      sendEnterEdit(id, context);
      return;
    }
    var token = UserManager.instance.userInfo?.token;
    Map<String, dynamic> map = {
      "Authorization": "Bearer $token",
      "code": 10101,
      "data": {"prescriptionOrderId": id}
    };
    roomId = id;
    _channel?.sink.add(jsonEncode(map));

    print("-=-=======map${map}");

  }

  // 离开房间
  void sendLeaveEdit( BuildContext context) {
    if (_channel == null) {
      connect();
      sendLeaveEdit(context);
      return;
    }
    if (roomId == "") {
      return;
    }
    var token = UserManager.instance.userInfo?.token;
    Map<String, dynamic> map = {
      "Authorization": "Bearer $token",
      "code": 10102,
      "data": {"prescriptionOrderId": roomId}
    };
    roomId = "";
    _channel?.sink.add(jsonEncode(map));

    print("-=-=-========-=-=-=-=map: ${map}");

  }

  // 处理接收到的消息
  void handleMessage(dynamic message) {
    print(DateTime.now().toString().substring(11, 19)+ "------------------心跳------:" + message.toString());
    WebSocketBean bean = WebSocketBean.fromJson(jsonDecode(message));
    /// 正常则心跳
    if (bean.code == 100001) {
      _countdown = 3;
    } else if (bean.code == 10000) {
      reConnect();
    }  else if (bean.code == 100002) {
      if (context != null) {
        if (context!.mounted) {
          UserManager.instance.clearCache();
          context!.removeAndPush(LoginRouterName.login);
        }
      }
    } else {
      XxEventBus.instance().fire(WebSocketNotification(bean));
    }
  }
  ///开始心跳
  void startRecordTime() {
    if (_countdownTimer != null) {
      return;
    }
    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (_countdown <= 1) {
        sendLink();
      } else {
        _countdown -= 1;
      }

      if (_reCountdown == 1) {
        reConnectAction();
        _reCountdown = 0;
      } else if (_reCountdown > 1) {
        _reCountdown -= 1;
      }
    });
  }

  Stream<dynamic> get onMessage => _channel?.stream ?? Stream.empty();

  void close() {
    _channel?.sink.close();
    _countdownTimer?.cancel();
    _countdownTimer = null;
    _channel = null;
  }
}

四,退出登录时close

 WebSocketManager().close();

五,wss:需要过滤签名认证

Android:
在android/app/src/main/res/xml/下创建network_security_config.xml文件
network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">wss://ws_ass_alpha.xiaoroujiankang.com</domain>
         <domain includeSubdomains="true">wss://ws_ass.xiaoroujiankang.com</domain>
    </domain-config>
</network-security-config>

AndroidManifest.xml文件中添加

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="*****"
        android:networkSecurityConfig="@xml/network_security_config"
    ...

相关文章

  • 谈判中迫使对方让步的策略

    软硬策略(红白脸策略) 制造竞争策略 虚张声势策略 各个击破策略 吹毛求疵策略(先苦后甜) 积少成多策略 最后通牒策略

  • 《伍尔福克教育心理学》读书笔记十

    学习策略包括:元认知策略、认知策略、资源管理策略 一、认知策略包括:(一)复述策略(二)精细加工策略(三)组织策略...

  • 学生学习策略

    学生学习大策略。 考试的策略,记忆的策略,记单词的策略,预习听课作业策略,各科学习的策略。 复习的策略,阅读的策略...

  • 淘宝营销策略有哪些?天晓网络来教你

    淘宝营销策略包括六大方面:产品策略丶品牌策略丶价格策略丶促销策略丶服务策略以及客户关系管理策略。 产品策略 1 什...

  • 读2022年版课程标准

    学习策略,学习策略主要包括元认知策略,认知策略,交际策略,情感管理策略等,其中,元认知策略有助于学生计划监控,评价...

  • Bibox—CTA策略参数详解

    CTA策略简介 Bibox CTA策略分为基础策略和高阶策略 分类 基础策略:双均线、MACD、均线止盈高阶策略:...

  • 路由策略

    路由策略和策略路由 什么是路由策略?路由策略和策略路由有什么区别? 如何配置路由策略? https://blog....

  • 设计模式——策略模式

    策略模式 IStrategy 抽象策略 StrategyOne 具体策略 StrategyTwo 具体策略 Str...

  • 学习策略

    考试大纲:了解学习策略分类,掌握认识策略、元认识策略和资源管理策略。 学习策略的含义及特点 …… 学习策略分类: ...

  • 策略PM入门学习索引

    策略PM入门学习(一)策略PM入门学习(二)策略PM入门学习(三)策略PM入门学习(四)策略PM入门学习(五)策略...

网友评论

      本文标题:Flutter-WebSocket策略

      本文链接:https://www.haomeiwen.com/subject/ikvhmjtx.html