欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

在这里插入图片描述

前言

如果你的后端使用 Node.js,那么你大概率在使用 Socket.IO
Socket.IO 不仅仅是 WebSocket,它是一套极其强大的实时通信框架,内置了长轮询回退、自动重连、房间(Room)、命名空间(Namespace)以及二进制流支持。

socket_io_client 是官方移植到 Dart 的客户端库,完全兼容 JS 版 Socket.IO 的协议。

对于 OpenHarmony 开发者,如果你的业务需要与现有的 Node.js 实时服务(如客服系统、实时游戏服务器)对接,使用这个库可以帮你省去大量解析底层协议的麻烦。

一、核心原理

Socket.IO 的强大在于其多层协议栈

Engine.IO Protocol

尝试

HTTP Long Polling

WebSocket

Socket.IO Protocol

Event: chat

Event: noti

鸿蒙 App

连接层

升级协议

长轮询 (备份方案)

WebSocket (首选)

业务层

/chat 命名空间

/news 命名空间

二、OpenHarmony 适配说明

socket_io_client 底层依赖 Dart 的 HTTP 和 WebSocket API。
OpenHarmony 上:

  1. Transport 兼容性:默认情况下库会先尝试 HTTP 长轮询,再升级到 WebSocket。这在鸿蒙上完全工作正常。
  2. 配置建议:为了性能,建议在配置中强制开启 ['websocket'] 作为 only transport,跳过长轮询握手阶段,减少连接耗时。

三、基础用例

3.1 建立连接

import 'package:socket_io_client/socket_io_client.dart' as IO;

void connect() {
  // 1. 配置选项
  IO.Socket socket = IO.io('http://localhost:3000', 
    IO.OptionBuilder()
      .setTransports(['websocket']) // 鸿蒙推荐:强制 Websocket
      .disableAutoConnect()         // 手动连接
      .setExtraHeaders({'token': 'jwt_xyz'}) // 鉴权
      .build()
  );

  // 2. 监听系统事件
  socket.onConnect((_) {
    print('✅ 连接成功 (ID: ${socket.id})');
  });
  
  socket.onDisconnect((_) => print('断开连接'));
  socket.onConnectError((err) => print('连接错误: $err'));

  // 3. 启动
  socket.connect();
}

在这里插入图片描述

3.2 发送与接收

// 发送简单消息
socket.emit('chat message', 'Hello from Harmony');

// 发送对象 (自动 JSON 序列化)
socket.emit('login', {'username': 'wang', 'pass': '123'});

// 发送带有回调的消息 (Ack)
socket.emitWithAck('update_profile', {'age': 25}, ack: (data) {
  print('服务器确认收到,并返回: $data');
});

// 监听业务事件
socket.on('new_msg', (data) {
  print('收到新消息: $data');
});

在这里插入图片描述

四、完整实战示例:鸿蒙实时协作画板

这个示例模拟了一个多人实时画板。当用户在鸿蒙设备上触摸屏幕时,会将坐标点实时发送给服务器;同时监听其他用户的绘图事件并在本地重绘。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;

// 模拟画笔数据模型
class PaintPoint {
  final double x;
  final double y;
  final int color;
  
  PaintPoint(this.x, this.y, this.color);
  
  Map<String, dynamic> toJson() => {'x': x, 'y': y, 'c': color};
  
  factory PaintPoint.fromJson(Map<String, dynamic> json) {
    return PaintPoint(
      (json['x'] as num).toDouble(),
      (json['y'] as num).toDouble(),
      json['c'] as int,
    );
  }
}

class CollaborationBoard extends StatefulWidget {
  
  _CollaborationBoardState createState() => _CollaborationBoardState();
}

class _CollaborationBoardState extends State<CollaborationBoard> {
  late IO.Socket socket;
  List<PaintPoint> otherPoints = []; // 其他人的轨迹

  
  void initState() {
    super.initState();
    _initSocket();
  }

  void _initSocket() {
    socket = IO.io('https://paint-server.example.com', 
      IO.OptionBuilder().setTransports(['websocket']).build()
    );

    socket.onConnect((_) => print('画板服务已连接'));

    // 监听别人的绘画事件
    socket.on('draw_event', (data) {
      if (mounted) {
        setState(() {
          otherPoints.add(PaintPoint.fromJson(data));
        });
      }
    });
    
    socket.connect();
  }

  // 本地手指移动
  void _onPanUpdate(DragUpdateDetails details) {
    // 1. 获取本地坐标
    final point = PaintPoint(
      details.localPosition.dx, 
      details.localPosition.dy, 
      0xFFFF0000 // 红色
    );
    
    // 2. 实时发送给服务器
    socket.emit('draw_event', point.toJson());
    
    // 3. 本地也画出来 (略)
  }

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanUpdate: _onPanUpdate,
      child: CustomPaint(
        painter: MyPainter(otherPoints),
        size: Size.infinite,
      ),
    );
  }

  
  void dispose() {
    socket.dispose(); // 务必断开
    super.dispose();
  }
}

// 简单的画布绘制器
class MyPainter extends CustomPainter {
  final List<PaintPoint> points;
  MyPainter(this.points);

  
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..strokeWidth = 5.0..strokeCap = StrokeCap.round;
    
    for (var p in points) {
      paint.color = Color(p.color);
      canvas.drawPoints(PointMode.posts, [Offset(p.x, p.y)], paint);
    }
  }

  
  bool shouldRepaint(MyPainter oldDelegate) => true;
}

在这里插入图片描述

五、总结

socket_io_client 让你在 OpenHarmony 上拥有了完整的 Socket.IO 客服端能力。
它的 API 设计非常贴合 JS 原版,前端开发者上手几乎没有门槛。

避坑指南
在鸿蒙真机调试时,如果遇到连接不上,首先检查:

  1. 如果你连的是 localhost,请确保手机和电脑在同一局域网,并使用电脑 IP(如 192.168.1.100)而不是 127.0.0.1
  2. 确保 module.json5 的网络权限已开启。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐