
写在前面如果你写过鸿蒙 ArkUI 应用,大概率遇到过这个场景:你写了个聊天应用,用 HTTP 轮询每 3 秒拉一次消息——结果电量血崩、消息延迟 3 秒、服务器被打爆。你想「能不能服务器有消息就推过来」——这就是 WebSocket。你查文档发现「鸿蒙有 ohos.net.webSocket」——你点进去发现createWebSocket创建实例、connect(url)建连接、on(open/message/close/error)事件订阅、send(payload)发消息、close()断开——API 一脸懵。这是「HTTP 轮询」和「WebSocket 长连接」的分水岭。鸿蒙给的实时通讯答案是ohos.net.webSocket——createWebSocket拿实例、connect建连接、on订阅事件、send发消息、close断开。本文就用一个真机可跑的「建连接 发消息 收消息 断开」demo,把 WebSocket 从「听名字一脸懵」讲到「下个项目直接抄」。代码托管在 AtomGit,文末有链接,真机实拍截图作证。这是韶非 UI 系列第六篇,接续上五篇 HTTP 网络栈 文件 IO 能力调用 后台任务 关系数据库。适合人群:写过鸿蒙应用、被「HTTP 轮询电量血崩」折磨过的同学。不适合人群:还在学State的同学——出门左转看我的入门篇。一、先讲清楚:WebSocket 到底是啥一句话:WebSocket 是鸿蒙给应用建「全双工长连接」的原生机制,管「建连接 收发消息 断开」全流程。你之前写前端new WebSocket(url)是浏览器宿主 API——鸿蒙不是浏览器环境,没有这种。WebSocket 是鸿蒙专门给实时通讯的原生机制,底层是 TCP 长连接 WebSocket 协议握手,能力对标前端的「new WebSocketEventSource」但更精细可控。核心 API 一览:API作用一句话理解webSocket.createWebSocket()创建 WebSocket 实例「告诉系统我要用长连接」ws.connect(url)建连接「TCP 握手 WebSocket 升级」ws.on(open/message/close/error)事件订阅「连接建立/收消息/关闭/错误」ws.send(payload)发消息「string 或 ArrayBuffer」ws.close()主动断开「客户端先关」记住这五个,往下看。二、动手:一个建连接 发消息 收消息 断开的 demo2.1 import 创建 WebSocket 实例importwebSocketfromohos.net.webSocketimportcommonfromohos.app.ability.commonEntryComponentstruct Index{privatecontext:common.UIAbilityContextgetContext(this)ascommon.UIAbilityContextprivatews:webSocket.WebSocket|nullnullprivatewsUrl:stringwss://echo.websocket.org// ...}三个细节:import webSocket from ohos.net.webSocket——webSocket是 WebSocket 的入口模块ws: webSocket.WebSocket | null——存 WebSocket 实例,后续所有操作都走它wsUrl: string wss://echo.websocket.org——echo 服务器,发啥回啥,适合 demo2.2connecton:建连接 事件订阅asyncconnectWs():Promisevoid{this.stateLog建 WebSocket 连接中...try{// 创建 WebSocket 实例this.wswebSocket.createWebSocket()// on(open) 连接建立回调this.ws.on(open,(){this.connState已连接this.stateLogWebSocket 已连接,url ${this.wsUrl}})// on(message) 收消息回调this.ws.on(message,(err,value){this.recvCount// value 可能是 string 或 ArrayBufferconsttext:stringtypeofvaluestring?value:(二进制数据)this.totalRecvthis.recvCountthis.lastRecvtextthis.stateLog第${this.recvCount}次收到消息})// on(close) 连接关闭回调this.ws.on(close,(){this.connState已断开this.stateLogWebSocket 连接已关闭})// on(error) 错误回调this.ws.on(error,(err){this.connState连接错误this.stateLogWebSocket 错误:${err?.message??err}})// connect 发起连接,返回 Promisebooleanconstok:booleanawaitthis.ws.connect(this.wsUrl)if(!ok){this.stateLogWebSocket 连接失败返回 falsethis.wsnull}}catch(e){this.stateLog建连接失败:${e.message}this.wsnull}}connecton三个关键点:①on订阅 4 类事件ws.on(open,cb)// 连接建立ws.on(message,cb)// 收消息ws.on(close,cb)// 连接关闭ws.on(error,cb)// 错误事件回调是异步的——connect返回成功只表示握手发起,真正「连上了」看on(open)。②on(message)value 可能是 string 或 ArrayBufferws.on(message,(err,value){consttext:stringtypeofvaluestring?value:(二进制数据)// ...})文本消息是 string,二进制消息是 ArrayBuffer。新手最容易忘typeof判断,直接当 string 用,二进制消息就炸。③connect返回Promisebooleanconstok:booleanawaitthis.ws.connect(this.wsUrl)ok true表示握手发起成功,不代表「连上了」——「连上了」看on(open)。2.3send:发消息asyncsendMsg():Promisevoid{if(!this.ws){this.stateLog尚未建连接,无法发消息return}try{this.sendCountconstpayload:stringhello-${this.sendCount}-${Date.now()}// send 发消息,返回 Promisebooleanconstok:booleanawaitthis.ws.send(payload)if(ok){this.totalSentthis.sendCountthis.stateLog第${this.sendCount}次发送成功:${payload}}else{this.stateLog第${this.sendCount}次发送失败返回 false}}catch(e){this.stateLog发消息失败:${e.message}}}send三个关键点:①send(payload)支持 string 或 ArrayBufferawaitthis.ws.send(hello)// 文本awaitthis.ws.send(newArrayBuffer(8))// 二进制②send返回Promisebooleanconstok:booleanawaitthis.ws.send(payload)ok true表示发送成功底层 TCP 缓冲区接收了。③send不等回消息send是单向的——发出去就完。回消息看on(message)异步到达。2.4close:断开连接asynccloseWs():Promisevoid{if(!this.ws){this.stateLog尚未建连接,无需断开return}try{// close 主动断开,返回 Promisebooleanconstok:booleanawaitthis.ws.close()this.stateLog已断开ok${ok}this.connState已断开this.wsnull}catch(e){this.stateLog断开失败:${e.message}}}close三个关键点:①close返回Promisebooleanconstok:booleanawaitthis.ws.close()②close后会触发on(close)主动close和服务端断开都会触发on(close)——用这个回调统一处理「连接已关」。③close后ws实例不能复用close后ws实例作废,要重连得重新createWebSocketconnect。三、真机实拍:建连接 发消息 收消息全跑通我把这个 demo 装到真机上跑鸿蒙 6.1.1.125, API 24,依次点 ① 建连接 ② 发消息,下面两张都是真机实拍,没有任何 P 图。初始态:WebSocket Demo 标题 连接状态「未连接」 ① 建连接 / ② 发消息 / ③ 断开连接三按钮 总发送/总接收指标区 最近收到消息区 关键 API 说明区:点 ① 建连接 ② 发消息后状态:连接状态「已连接」 状态日志「WebSocket 已连接」 总发送/总接收指标更新 最近收到消息显示 echo 服务器返回内容:重点看第二张:连接状态「已连接」 总发送/总接收指标更新——createWebSocketconnectonsend全跑通了。最近收到消息显示 echo 服务器返回内容——on(message)真收到消息了。这是 WebSocket 五大 API 全跑通的真机证明。四、ohos.net.webSocketvs 前端new WebSocket:啥差异新手最容易纠结的问题:既然前端new WebSocket(url)那么标准,鸿蒙为啥要造自己的 WebSocket?维度前端new WebSocketohos.net.webSocket运行环境浏览器宿主鸿蒙原生运行环境实例创建new WebSocket(url)webSocket.createWebSocket()建连接构造函数内自动连await ws.connect(url)显式事件订阅ws.onopen cbws.on(open, cb)收消息ws.onmessage cbws.on(message, cb)发消息ws.send(data)同步 voidawait ws.send(data)Promise安全模型同源策略 wss鸿蒙沙箱 网络权限一句话决策:鸿蒙应用实时通讯必须用ohos.net.webSocket,不能用new WebSocket不存在。鸿蒙不是浏览器,这套原生 WebSocket 封装更安全可控。五、常见坑都是血泪坑症状解法用new WebSocket编译报错「找不到 WebSocket」鸿蒙用ohos.net.webSocket,没浏览器宿主 APIon(message)value 直接当 string二进制消息炸typeof value string判断connect成功就以为「连上了」on(open)还没触发就发消息看on(open)才算真连上close后复用ws实例报错「实例已关」重新createWebSocketconnect忘了网络权限建连接报权限错module.json5 加ohos.permission.INTERNET长连接不心跳运营商 NAT 超时断开30-60s 发一次心跳包收消息改State不在主线程UI 不更新setTimeout切主线程再改六、webSocket安全模型鸿蒙 WebSocket 受安全约束——网络权限 沙箱隔离:安全机制含义网络权限需ohos.permission.INTERNET才能建连接沙箱隔离应用级 WebSocket,其他应用默认访问不到wss 协议加密 WebSocket,生产环境必用证书校验wss 自签证书需on(message)校验这是鸿蒙安全模型的硬约束——比浏览器同源策略严,但比 iOS ATS 松鸿蒙允许 ws 明文 自签证书,生产环境建议 wss。七、完整代码仓库本文所有代码都已托管到AtomGit,欢迎 clone、提 issue、点 star:仓库地址:https://atomgit.com/JaneConan/arkui-websocket仓库包含:完整的「建连接 发消息 收消息 断开」demo 工程Index.ets主页面createWebSocketconnectonsendclose五姿势on(open/message/close/error)事件订阅 string/ArrayBuffer 类型判断可直接用 DevEco Studio 打开运行真机装普通应用必能跑,需配网络权限八、下一步该学什么?跑通这个 demo 之后,你的鸿蒙实时通讯就入门了。这是韶非 UI 系列第六篇,后续按这个顺序往下:媒体访问ohos.file.photoAccessHelper下一篇:访问相册、扫描媒体文件,应用调系统相册必学推送通知ohos.notificationManager:通知栏展示、点击拉起,离线触达必学相机ohos.multimedia.camera:预览、拍照、录像,相机应用必学动画ohos.arkui.animation:属性动画、转场动画,UI 进阶必学其他:ohos.multimedia.audio录音播放、ohos.bluetooth蓝牙、ohos.sensor传感器,应用领域专属写在最后ohos.net.webSocket的本质,是**「鸿蒙给应用建全双工长连接的原生机制」**——不是浏览器new WebSocket,是鸿蒙专门给实时通讯的原生机制,能力对标「new WebSocketEventSource」但更安全可控。代价是createWebSocket多一步、on事件订阅多一步。一旦你开始用 WebSocket 思维写实时应用,你会发现大部分「聊天应用收推」「股票应用实时报价」「协同编辑应用同步」的需求,都是createWebSocketconnectonsend的自然结果。代码量比 HTTP 轮询少一半,实时性高九成。代码已经给你了,仓库链接在上面。现在关掉这篇文章,打开 DevEco Studio,把 demo 跑起来,亲手点建连接发消息感受下全双工长连接。跑通了,回来评论区打个「1」,我看看有多少人真的动手了。作者:JaneConan仓库:https://atomgit.com/JaneConan/arkui-websocket协议:Apache-2.0,随便用,别告我