Flutter for OpenHarmony:shelf_web_socket 快速构建 WebSocket 服务端,实现端到端实时通信(WebSocket 服务器) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:shelf_web_socket 快速构建 WebSocket 服务端,实现端到端实时通信(WebSocket 服务器) 深度解析与鸿蒙适配指南

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

在这里插入图片描述

前言

在移动应用开发中,我们通常扮演“客户端”的角色,去连接远程的 WebSocket 服务。但有时,我们需要在设备本身运行一个微型服务器,例如用于局域网内的设备发现、P2P 文件传输信令,或者在调试模式下作为数据广播源。

shelf_web_socket 是基于 Dart 标准 Web 服务器框架 shelf 的 WebSocket 处理器。它能让你在 Flutter 应用(包括 OpenHarmony)中轻松启动一个能够处理 WebSocket 连接的 HTTP 服务。

一、核心概念

  • Shelf: Dart 的 Web 服务器中间件管道框架(类似 Express.js)。
  • Handler: 处理请求并返回响应的函数。
  • WebSocketChannel: 下层封装,让 WebSocket 操作像 Stream 一样简单。

建立连接 ws://ip:port

协议升级请求 (Upgrade Request)

升级成功 (Success)

数据流/接收端 (Stream/Sink)

WebSocket 客户端\n(App/浏览器)

鸿蒙应用\n(shelf_web_socket)

处理器 (shelf handler)

通信通道 (WebSocketChannel)

二、集成与基础用法

2.1 添加依赖

dependencies:shelf: ^1.4.0 shelf_web_socket: ^3.0.0 web_socket_channel: ^3.0.0 

2.2 启动基础服务

import'package:shelf/shelf_io.dart'as shelf_io;import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';voidmain()async{// 定义 WebSocket 处理器var handler =webSocketHandler((WebSocketChannel webSocket){ webSocket.stream.listen((message){print('收到消息: $message'); webSocket.sink.add('服务端已收到: $message');});});// 启动服务,监听所有 IP (0.0.0.0)var server =await shelf_io.serve(handler,'0.0.0.0',8080);print('WebSocket 服务已启动: ws://${server.address.host}:${server.port}');}
在这里插入图片描述

三、进阶场景与示例

3.1 示例一:广播消息

实现一个聊天室功能,将一个客户端发来的消息广播给所有连接者。

import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';finalList<WebSocketChannel> _clients =[];var broadcastHandler =webSocketHandler((WebSocketChannel webSocket){ _clients.add(webSocket);print('新客户端连接,当前在线: ${_clients.length}'); webSocket.stream.listen((message){// 广播给其他客户端for(var client in _clients){if(client != webSocket){ client.sink.add(message);}}}, onDone:(){ _clients.remove(webSocket);print('客户端断开,剩余: ${_clients.length}');});});
在这里插入图片描述

3.2 示例二:鉴权校验

在建立连接前检查 Header 中的 Token。

import'package:shelf/shelf.dart';import'package:shelf_web_socket/shelf_web_socket.dart';HandlerauthMiddleware(Handler innerHandler){return(Request request){if(request.headers['Authorization']!='Bearer my_secret_token'){returnResponse.forbidden('未授权访问');}returninnerHandler(request);};}// 使用 Pipeline 组装// var handler = Pipeline().addMiddleware(authMiddleware).addHandler(wsHandler);
在这里插入图片描述

3.3 示例三:处理二进制数据

WebSocket 不仅能传字符串,还能传字节流(如图片片段)。

import'dart:typed_data';var binaryHandler =webSocketHandler((WebSocketChannel webSocket){ webSocket.stream.listen((message){if(message isList<int>){print('收到二进制数据,长度: ${message.length}');// 处理二进制逻辑...}else{print('收到文本: $message');}});});
在这里插入图片描述

四、OpenHarmony 平台适配

4.1 网络权限

作为服务端,你需要监听端口,这同样需要 Internet 权限。

"requestPermissions":[{"name":"ohos.permission.INTERNET"}]

4.2 后台运行限制

移动操作系统通常限制应用在后台运行服务。如果你的 WebSocket 服务需要长期运行,建议在前台 Service 中启动,或仅在 App 前台可见时运行。

五、完整实战示例:局域网即时画板服务端

本示例将在 OpenHarmony 设备上启动一个 WebSocket 服务。任何连接到该服务的客户端(可以是另一个 App 或浏览器)发送的坐标点,都会被广播给其他人,实现多端协同绘图。

5.1 示例代码

import'dart:async';import'dart:io';import'package:flutter/material.dart';import'package:shelf/shelf_io.dart'as shelf_io;import'package:shelf_web_socket/shelf_web_socket.dart';import'package:web_socket_channel/web_socket_channel.dart';voidmain(){runApp(constMaterialApp(home:ServerPage()));}classServerPageextendsStatefulWidget{constServerPage({super.key});@overrideState<ServerPage>createState()=>_ServerPageState();}class _ServerPageState extendsState<ServerPage>{HttpServer? _server;finalList<WebSocketChannel> _sockets =[];finalList<String> _logs =[];String _ipInfo ='获取中...';@overridevoidinitState(){super.initState();_getIpAddress();}Future<void>_getIpAddress()async{try{final interfaces =awaitNetworkInterface.list(type:InternetAddressType.IPv4);final ip = interfaces.first.addresses.first.address;setState(()=> _ipInfo = ip);}catch(e){setState(()=> _ipInfo ='无法获取 IP');}}// 启动服务Future<void>_startServer()async{var handler =webSocketHandler((WebSocketChannel webSocket){ _sockets.add(webSocket);_log('新连接接入'); webSocket.stream.listen((message){_log('广播数据: $message');// 广播坐标数据for(var socket in _sockets){if(socket != webSocket){ socket.sink.add(message);}}}, onDone:(){ _sockets.remove(webSocket);_log('连接断开');});});try{ _server =await shelf_io.serve(handler,InternetAddress.anyIPv4,8080);_log('服务启动于 ws://$_ipInfo:8080');}catch(e){_log('启动失败: $e');}}Future<void>_stopServer()async{await _server?.close(force:true);for(var s in _sockets){await s.sink.close();} _sockets.clear(); _server =null;_log('服务已停止');}void_log(String msg){if(!mounted)return;setState((){ _logs.insert(0,'[${DateTime.now().hour}:${DateTime.now().minute}] $msg');});}@overridevoiddispose(){_stopServer();super.dispose();}@overrideWidgetbuild(BuildContext context){returnScaffold( appBar:AppBar(title:constText('WebSocket Server')), body:Column( children:[Container( padding:constEdgeInsets.all(20), color:Colors.blue[50], child:Column( children:[Text('本机 IP: $_ipInfo', style:constTextStyle(fontSize:18, fontWeight:FontWeight.bold)),constSizedBox(height:10),Row( mainAxisAlignment:MainAxisAlignment.center, children:[ElevatedButton( onPressed: _server ==null? _startServer :null, child:constText('启动服务'),),constSizedBox(width:20),ElevatedButton( style:ElevatedButton.styleFrom(backgroundColor:Colors.red[100]), onPressed: _server !=null? _stopServer :null, child:constText('停止'),),],),],),),constDivider(),Expanded( child:ListView.builder( itemCount: _logs.length, itemBuilder:(context, index)=>ListTile( leading:constIcon(Icons.info_outline, size:16), title:Text(_logs[index], style:constTextStyle(fontSize:14)),),),),],),);}}
在这里插入图片描述

六、总结

通过 shelf_web_socket,我们让 OpenHarmony 手机不仅仅是信息的消费者,更成为了信息的生产者和中转站。

最佳实践

  1. 异常处理:Websocket 连接很容易因网络波动断开,务必处理 onDoneonError
  2. 资源释放:在组件销毁或应用退出时,务必关闭 Server 和所有 Channel连接,防止端口占用。
  3. 心跳机制:为了保持连接活性,建议在应用层实现 Ping/Pong 心跳包。

Read more

飞书机器人接入效率提升300%?Seedance 2.0企业级集成方案(2024最新APIv3适配实录)

第一章:飞书机器人接入效率提升300%?Seedance 2.0企业级集成方案(2024最新APIv3适配实录) Seedance 2.0 是面向中大型企业的飞书机器人集成中间件,深度适配飞书开放平台 2024 年发布的 API v3 全新架构。相比传统 Webhook 模式下平均 8–12 小时的手动配置流程,该方案通过自动化凭证管理、事件路由预编译与并发消息分发引擎,将单机器人接入耗时压缩至平均 2.6 小时,实测效率提升达 300%。 核心能力升级要点 * 支持飞书 Bot Token + App Ticket 双通道自动轮换,规避 v2 中因 token 过期导致的 72 小时服务中断风险 * 内置事件 Schema 自发现机制,可动态解析 message、card_

机器人笔记——轨迹规划

机器人笔记——轨迹规划

前言 之前的文章讲过到了关节是持续运动的,雅可比矩阵正是描述关节运动与机器人末端运动映射关系的有力工具。然而有了如何映射的工具仅仅是分析机器人运动的开始,要知道空间两点间的运动轨迹是多样的,因此就产生了轨迹规划的概念。这里讲的轨迹规划可以理解为寻求最优路径的过程,下文对其展开介绍。  前序内容 * 机构自由度的计算 * 齐次变换与齐次变换矩阵的计算 * 机器人正运动学——学习笔记 * 机器人正运动学实例——PUMA560机械臂(附Matlab机器人工具箱建模代码) * 机器人逆运动学——以六自由度机器人为例(详解、易懂,附全部Matlab代码) * 双平行四边形码垛机械臂的运动学正逆解——简化方法(附完整Matlab代码、解析过程) * 机器人笔记——关于atan2与atan的区别 * 雅可比矩阵——机器人笔记(简化、易懂) 1. 什么是机器人轨迹规划? 想要解答这个问题,我们先来看什么是轨迹。 轨迹:就是机器人手臂(末端点或操作点)的位置、速度、加速度对于时间的历程; 我们在意的其实是,机器人末端轨迹对于工件的状态或相对关系,就像下面右侧图一样

HunyuanOCR能否接入RPA机器人?UiPath与影刀兼容性测试

HunyuanOCR能否接入RPA机器人?UiPath与影刀兼容性测试 在企业自动化迈向“无人值守”的今天,一个看似简单却频繁出现的难题正在困扰着RPA工程师:如何让机器人“看懂”屏幕上那些无法复制的文字? 比如财务人员每天要处理上百张扫描发票,信息藏在图片里;客服系统弹出的验证码截图需要自动识别;跨国业务中混杂中英日韩多语种的合同文本等待提取……这些非结构化视觉数据,正是传统RPA的“盲区”。而解决这一瓶颈的关键,正是将OCR能力深度融入自动化流程。 近年来,随着大模型技术的发展,OCR不再只是简单的文字识别工具。腾讯推出的HunyuanOCR,作为基于混元多模态架构打造的端到端轻量级专家模型,正以其出色的泛化能力和低部署门槛,成为增强RPA视觉感知能力的理想候选者。 那么问题来了——它真的能在真实生产环境中,稳定对接主流RPA平台吗?我们以国内广泛使用的影刀RPA和国际主流的UiPath为例,从部署、调用到集成路径进行了完整验证。 为什么是HunyuanOCR? 传统的OCR方案往往采用“检测+识别”两阶段级联架构,例如PP-OCR系列搭配LayoutParser做版

Arrow游戏叙事设计工具:可视化创作让剧情设计变得简单高效

Arrow游戏叙事设计工具:可视化创作让剧情设计变得简单高效 【免费下载链接】ArrowGame Narrative Design Tool 项目地址: https://gitcode.com/gh_mirrors/arrow/Arrow Arrow游戏叙事设计工具是一款基于Godot 4引擎的专业级可视化创作平台,专为游戏开发者和叙事设计师打造。通过直观的节点式界面,Arrow让复杂的剧情分支和对话系统设计变得简单易懂,彻底改变了传统脚本编写的繁琐流程。 Arrow启动界面展现了专业的科技感和现代设计风格,深灰背景与霓虹红、青色彩形成强烈视觉冲击 🎯 为什么选择Arrow作为你的叙事设计工具? 核心优势:可视化操作界面 Arrow采用节点式设计理念,每个剧情元素都以独立节点的形式呈现。从对话内容到条件分支,所有叙事组件都清晰可见,让创作者能够轻松把握整个故事脉络,无需面对复杂的代码编写。 技术领先:基于Godot 4引擎 作为专为Godot 4引擎优化的工具,Arrow充分利用了现代游戏引擎的强大功能。版本标识"v3.x [GD4]"不仅体现了工具的成熟度,更展示