- 示例工程
- 前端
- 移动开发
- 跨平台
【免费下载链接】uni-app
A cross-platform framework using Vue.js
导读
uni-websocket是 uni-app / uni-app x 生态中一个以 UTS 插件形态交付的 WebSocket 连接管理模块,通过同一套uni.connectSocket、uni.sendSocketMessage、uni.closeSocket等 API 屏蔽了 Android(Kotlin)、iOS(Swift)、HarmonyOS(ArkTS)三端底层实现的差异。本文以仓库中的 模块 readme 为骨架,结合 接口声明 与各平台实现源码,完整讲解 UTS 语言与 UTS 插件的基本机制、模块提供的全部 WebSocket API 与参数语义、三端底层实现原理、错误码体系,并给出可直接落地的连接、收发、关闭与监听完整代码示例,帮助读者既会用 API,也看得懂其底层是如何做到"一套代码多端运行"的。
一、模块概览:一个"UTS 插件"形态的 WebSocket 连接管理模块
按仓库内 readme 的定义,uni-websocket模块的职责一句话概括为:实现 WebSocket 连接管理功能。它不是一个普通的 JS 组件,而是一个典型的UTS 插件——即使用 UTS 语言编写的 uni_modules 插件,其核心目的是允许 uni-app / uni-app x 开发者使用 UTS 语法来调用扩展 API(封装原生系统的 API 或三方 SDK)。
从 package.json 可以确认该插件的元信息:
id/displayName:uni-websocket,版本1.0.0;engines.HBuilderX:要求^3.6.8及以上版本;dcloudext.type:"uts",即这是一个 UTS 类型插件;dcloudext.sale:regular 与 sourcecode 价格均为0.00,即免费开源插件;uni_modules.platforms:在客户端侧覆盖 Vue(vue2/vue3)、App(app-android / app-ios)、H5 与各大小程序平台,属于全平台型插件。
值得关注的是uni_modules["uni-ext-api"]一节,它向 uni-app 框架声明了本插件注入到uni.命名空间下的 7 个扩展 API,并且对 App 三端(kotlin / swift / arkts)均标记为true:
| 声明 API | App-Android (kotlin) | App-iOS (swift) | App-Harmony (arkts) | | -- | -- | -- | -- | |connectSocket| true | true | true | |sendSocketMessage| true | true | true | |closeSocket| true | true | true | |onSocketOpen| true | true | true | |onSocketMessage| true | true | true | |onSocketClose| true | true | true | |onSocketError| true | true | true |
也就是说,插件一旦被工程引入,开发者即可在 App 三端直接调用这些uni.xxx全局 API,无需关心底层是 OkHttp 还是 Starscream。
二、地基:UTS 语言是什么、为什么能跨端
要理解uni-websocket为什么能做到"一份源码跑三端原生",必须先理解其编写语言 UTS。readme 中给出了权威说明,这里结合仓库实践展开:
UTS(uni type script)是一门跨平台的、高性能的、强类型的现代编程语言。它可以被编译为不同平台的编程语言:
| 目标平台 | 编译产物语言 | | -- | -- | | Android | Kotlin | | iOS | Swift | | HarmonyOS(鸿蒙) | ArkTS | | Web / 小程序 | JavaScript |
UTS 采用了与 TypeScript 基本一致的语法规范,并支持绝大部分 ES6 API;但为了跨端,UTS 做了一些约束和特定平台的增补。过去在 JS 引擎下运行支持的语法,大部分在 UTS 的处理下也可以平滑地在 Kotlin 和 Swift 中使用;但有些能力无法抹平,此时需要使用条件编译。
与 uni-app 的条件编译类似,UTS 也支持条件编译——写在条件编译块里的代码,可以调用平台特有的扩展语法。在uni-websocket源码中就可以看到这种写法的实际应用,例如 unierror.uts 中:
export class ConnectSocketFailImpl extends UniError implements ConnectSocketFail { // #ifdef APP-ANDROID override errCode: ConnectSocketErrorCode // #endif constructor(errCode : ConnectSocketErrorCode) { super(); this.errSubject = UniWebsocketErrorSubject; this.errCode = errCode; this.errMsg = ConnectUniErrors[errCode] ?? "" } }// #ifdef APP-ANDROID与// #endif之间的override声明只会在 Android 平台参与编译,iOS / HarmonyOS 编译时会被剔除,这正是 UTS 条件编译抹平平台差异的直观例证。
仓库内还提供了 uts 与 ts 的差异文档、UTS 语言官方文档 等资料,需要系统学习 UTS 的读者可继续查阅。
三、UTS 插件机制:utssdk 目录如何按平台组织代码
readme 明确指出:UTS 插件的实现代码主要位于utssdk目录下,并按平台进行分离和组织。原文档中的目录说明表是理解该插件目录结构的钥匙,完整继承如下:
| 目录/文件 | 目标平台 | 实现语言 | 作用描述 | | -- | -- | -- | -- | |utssdk/app-android| Android | UTS, Kotlin, Java | 存放 UTS 插件在 Android 平台上的具体实现源码 | |utssdk/app-ios| iOS | UTS, Swift | 存放 UTS 插件在 iOS 平台上的具体实现源码 | |utssdk/app-harmony| HarmonyOS (鸿蒙) | UTS, ArkTS | 存放 UTS 插件在 HarmonyOS 平台上的具体实现源码 | |utssdk/*.uts| 多平台共用 | UTS | 存放使用 UTS 语言编写的、可供所有平台共用的实现源码 |
对照仓库中uni-websocket插件的实际文件树,这张表完全成立:
src/uni_modules/uni-websocket/ ├── package.json # 插件元信息与 uni-ext-api 声明 ├── readme.md # 模块说明文档 ├── changelog.md # 更新日志 └── utssdk/ ├── interface.uts # 公共:全部 API 与类型的声明 ├── interface.type.uts # 公共:SocketDataOptions(string | ArrayBuffer) ├── protocol.uts # 公共:参数协议校验 ├── unierror.uts # 公共:UniError 错误对象与错误码映射 ├── app-android/ │ ├── index.uts # Android 平台导出实现 │ ├── config.json # Android 原生依赖配置 │ └── websocket/ │ ├── WebSocketManager.uts │ └── WebsockerClient.uts ├── app-ios/ │ ├── index.uts # iOS 平台导出实现 │ ├── config.json │ └── frameworks/ # Starscream.xcframework、websocket.xcframework │ └── websocket/ # iOS 侧 WebSocketManager.uts / WebsockerClient.uts └── app-harmony/ └── index.uts # HarmonyOS 平台导出实现这里可以总结出 UTS 插件的三条约定,读者开发自己的 UTS 插件时可复用:
- 公共逻辑下沉到
utssdk/*.uts:类型声明、协议校验、错误定义等跨平台共享内容放在 utssdk 根目录,三端共用; - 平台实现按目录隔离:
app-android、app-ios、app-harmony三个子目录分别放置各自平台的实现,互不干扰; - 每平台入口是
index.uts:平台目录下的index.uts负责对外导出该平台的 API 实现,uni-app 编译器按目标平台自动选择对应目录。
3.1 平台原生依赖的声明方式
原生依赖放在各平台目录下的config.json中,例如 app-android/config.json:
{ "dependencies": [ "com.squareup.okhttp3:okhttp:3.12.12" ], "minSdkVersion": "19" }这说明 Android 平台实现基于 OkHttp 3.12.12,并声明了最低支持的minSdkVersion为 19(Android 4.4+)。而 iOS 平台则通过frameworks/目录内置了Starscream(一款纯 Swift 实现的 WebSocket 客户端库)的 xcframework,分别提供真机(ios-arm64)与模拟器(ios-arm64_x86_64-simulator)两个分片——这是 UTS 插件"混编原生语言/三方 SDK"的标准做法,相关规范可参考仓库内的 uts 插件原生语言混编开发文档。
四、WebSocket API 全貌:7 个全局 API + SocketTask 对象
uni-websocket的全部接口形态定义在公共文件 interface.uts 中。它声明了两类能力:
- 全局 API(
uni.前缀调用,共 7 个); - SocketTask 对象(
uni.connectSocket的返回值,提供 6 个方法)。
4.1 全局 API 一览
| API | 签名 | 说明 | | -- | -- | -- | |uni.connectSocket(options)|(options: ConnectSocketOptions) => SocketTask| 创建 WebSocket 连接,返回 SocketTask | |uni.onSocketOpen(callback)|(result: OnSocketOpenCallbackResult) => void| 监听连接打开事件(已废弃,用 SocketTask 的 onOpen 替换) | |uni.onSocketMessage(callback)|(result: OnSocketMessageCallbackResult) => void| 监听收到服务器消息(已废弃,用 onMessage 替换) | |uni.sendSocketMessage(options)|(options: SendSocketMessageOptions) => void| 通过连接发送数据(已废弃,用 SocketTask 的 send 替换) | |uni.onSocketError(callback)|(result: OnSocketErrorCallbackResult) => void| 监听连接错误(已废弃,用 onError 替换) | |uni.closeSocket(options)|(options: CloseSocketOptions) => void| 关闭连接(已废弃,用 SocketTask 的 close 替换) | |uni.onSocketClose(callback)|(result: OnSocketCloseCallbackResult) => void| 监听连接关闭(已废弃,用 onClose 替换) |
接口注释中明确标注:除connectSocket外的 6 个全局 API 均已废弃(@deprecated),官方推荐的新用法是"先uni.connectSocket拿到SocketTask,再通过 task 的onOpen / onMessage / send / close / onError / onClose管理本次连接"。旧式全局 API 仍可用,但会作用于最近一次创建的连接(见下文源码分析)。
4.2ConnectSocketOptions参数详解
connectSocket的入参类型定义在 interface.uts,各字段语义如下:
| 参数 | 类型 | 必填 | 默认值 | 说明 | | -- | -- | -- | -- | -- | |url|string| 是 | - | 开发者服务器接口地址 | |header|UTSJSONObject \| null| 否 |null| HTTP 请求 Header,header 中不能设置 Referer| |protocols|string[] \| null| 否 |null| 子协议数组(WebSocket Subprotocol) | |success|(result: ConnectSocketSuccess) => void \| null| 否 |null| 调用成功的回调 | |fail|(result: ConnectSocketFail) => void \| null| 否 |null| 调用失败的回调 | |complete|(result: any) => void \| null| 否 |null| 调用结束(成功、失败都会执行)的回调 |
对应的参数协议校验在 protocol.uts 中实现:
export const ConnectSocketApiProtocol = new Map<string, ProtocolOptions>([ [ 'url', { type: 'string', required: true } ], [ 'header', { type: 'object', required: false } ], [ 'protocols',{ type: 'string[]',required: false } ], ]); export const ConnectSocketApiOptions: ApiOptions<ConnectSocketOptions> = { formatArgs: new Map<string, Function>([ [ 'url', function (url: string, params: ConnectSocketOptions) { if (url == null) { throw new Error('url is required') } } ] ]), }即:url为必填字符串,缺失时直接抛出'url is required';header必须是对象;protocols必须是字符串数组。
4.3SendSocketMessageOptions参数详解
export type SendSocketMessageOptions = { data: any, // 需要发送的内容,app 平台从 4.61 版本开始支持 ArrayBuffer success?: ((result: GeneralCallbackResult) => void) | null, fail?: ((result: SendSocketMessageFail) => void) | null, complete?: ((result: any) => void) | null };data的类型在 interface.type.uts 中定义为SocketDataOptions:
export type SocketDataOptions = String | ArrayBuffer;即支持发送字符串与ArrayBuffer(二进制)两种数据;其中 app 平台从 4.61 版本开始支持ArrayBuffer(该版本信息同时标注于 interface.uts 的注释中)。
4.4CloseSocketOptions参数详解
export type CloseSocketOptions = { code?: number | null, // 关闭连接的状态号,默认 1000(表示正常连接关闭) reason?: string | null, // 可读的关闭原因,必须是不长于 123 字节的 UTF-8 文本(不是字符) success?: ..., fail?: ..., complete?: ... };需要注意两个约束:
code未指定时默认取值1000(正常关闭);reason是最多 123 字节的 UTF-8 文本,且以字节数而非字符数计量,中文等多字节字符要特别留意。
4.5 SocketTask 对象
connectSocket返回的SocketTask(定义于 interface.uts)是对单条连接的操作句柄,提供:
| 方法 | 说明 | | -- | -- | |send(options: SendSocketMessageOptions)| 通过该连接发送数据 | |close(options: CloseSocketOptions)| 关闭该连接 | |onOpen(callback)| 监听该连接打开事件,回调参数含header(连接成功的 HTTP 响应 Header) | |onClose(callback)| 监听该连接关闭,回调参数含code(关闭状态号)与reason(关闭原因) | |onError(callback)| 监听该连接错误,回调参数含errMsg| |onMessage(callback)| 监听该连接收到服务器消息,回调参数含data(app 4.61 起可为 ArrayBuffer) |
监听回调的类型细节(如OnSocketOpenCallbackResult.header、OnSocketCloseCallbackResult.code/reason、OnSocketMessageCallbackResult.data)均可在上述文件对应位置找到完整注释,这里不再赘述。
五、三端源码实现:单例管理 + 平台客户端
5.1 Android:WebSocketManager 单例 + OkHttp 客户端
Android 平台的入口 app-android/index.uts 非常薄,7 个 API 全部委托给WebSocketManager单例:
export const connectSocket : ConnectSocket = (options : ConnectSocketOptions) : SocketTask => { return WebSocketManager.getInstance().connectSocket(options); } export const sendSocketMessage : SendSocketMessage = (options : SendSocketMessageOptions) : void => { return WebSocketManager.getInstance().sendSocketMessage(options); } // ... onSocketOpen / onSocketMessage / onSocketClose / onSocketError 同理WebSocketManager.uts 内部是一个经典的单例管理器,核心数据结构有两组:
socketTasks: SocketTask[]:保存所有连接任务。源码注释明确说明:"当 uni. 开头调用的时候,只作用于 0 元素;这个 task 数组,当 error 或者 close 的时候,会删除"——这就是"旧式全局 API 作用于最近一次连接"的源码级依据(L112-L113);taskMap: Map<WebsockerClient, SocketTask>:维护底层客户端对象与任务对象的绑定关系,用于回调事件反查对应 task。
connectSocket的调用链为(L137-L151):
- 创建
WebsockerClient(封装 OkHttp 的 WebSocket); - 包装为
SimpleSocketTask并注册进socketTasks与taskMap; - 立即回调
success(errMsg: "connectSocket:ok")与complete; - 调用
webscoketClient.connect()发起真实连接; - 返回 task 给调用方。
SimpleSocketTask(L4-L97) 实现了SocketTask接口,内部维护 open / close / error / message 四类回调数组,并提供dispatchXxx方法供底层客户端事件统一派发;send/close在底层客户端为空时(连接已失效)会构造错误结果并依次回调fail与complete。
事件回调(onOpen/onMessage/onClose/onError)的统一处理逻辑为(以onClose为例,L239-L261):
- 通过
taskMap反查 task; - 若该 task 是
socketTasks[0]且全局回调已注册,则同时触发全局onSocketClose; - 将 task 从
socketTasks中移除,并从taskMap中删除绑定; - 向 task 自身的
onClose回调派发{ code, reason }。
从源码结构可以推断:该设计既兼容了旧的全局uni.onSocketXxx监听方式,也保证了基于 SocketTask 的多连接场景下各连接事件互不串扰。
5.2 iOS:基于 Starscream 的同一套 Manager 结构
iOS 平台目录utssdk/app-ios下同样存在WebSocketManager.uts/WebsockerClient.uts以及入口index.uts,并内置了Starscream.xcframework与封装好的websocket.xcframework(分别提供真机与模拟器架构的二进制分片)。可以推断 iOS 实现沿用了与 Android 相同的 Manager + Client 架构,仅将底层网络库替换为 Starscream。UTS 在此平台会被编译为 Swift,Starscream 正是以 Swift 编写的主流 WebSocket 客户端库,这也与 readme 中"iOS 平台编译为 Swift"的描述一致。
5.3 HarmonyOS:独立入口 index.uts
utssdk/app-harmony目录下有独立的index.uts入口,UTS 在此平台编译为 ArkTS,说明鸿蒙侧拥有独立的 WebSocket 实现路径,无需依赖 Android / iOS 的网络栈。鸿蒙平台 UTS 插件开发注意事项可参考仓库内的 uts 插件 HarmonyOS 平台开发注意事项。
六、错误码体系:Connect 与 Send 的 4 个错误码
公共文件 unierror.uts 集中定义了错误主题与错误码映射:
连接类错误(ConnectSocketErrorCode):
| 错误码 | 说明 | 错误消息(errMsg) | | -- | -- | -- | |600009| URL 格式不合法 |invalid URL|
发送类错误(SendSocketMessageErrorCode):
| 错误码 | 说明 | 错误消息(errMsg) | | -- | -- | -- | |10001| 发送数据超限,发送队列不能超过 16M 大小 |The queue memory exceeds 16 MiB and the connection will be closed| |10002| websocket 未连接 |webSocket is not connected| |602001| websocket 系统错误 |websocket system error|
对应的失败对象ConnectSocketFailImpl/SendSocketMessageFailImpl均继承自UniError,构造函数中会设置errSubject = 'uni-websocket'、errCode与errMsg(L39-L61)。其中errMsg的英文文案The queue memory exceeds 16 MiB...提示了一个重要的工程事实:单连接发送队列上限为 16 MiB,超限会直接关闭连接,因此高频推送场景务必控制发送速率与单条消息体积。
另外,在 WebSocketManager.uts 中,closeSocket在未建立连接时返回的错误消息为closeSocket:fail WebSocket is not connected(L173-L175),send在未连接时则构造errCode = 10002的失败对象(L50),两者可在业务侧作为"是否已连接"的兜底判断。
七、实战:完整可运行的 WebSocket 使用示例
7.1 推荐用法:基于 SocketTask
这是官方推荐的新式用法(接口注释中的 @example 即为此形态,见 interface.uts):
// 1. 创建连接 const task = uni.connectSocket({ url: "ws://192.168.12.106:8080/ws", complete: (e) => { console.log("socket :", e); } }); // 2. 监听连接打开 task.onOpen((res) => { console.log('WebSocket连接已打开!', res.header); }); // 3. 监听服务器消息(app 4.61 起 res.data 可为 string 或 ArrayBuffer) task.onMessage((res) => { console.log('收到服务器内容:' + res.data); }); // 4. 监听错误与关闭 task.onError((res) => { console.log('WebSocket错误:', res.errMsg); }); task.onClose((res) => { console.log('WebSocket 已关闭!code=' + res.code + ' reason=' + res.reason); }); // 5. 发送数据(需在连接打开之后) task.send({ data: "halo" }); // 发送二进制数据(app 4.61+) task.send({ data: arrayBuffer }); // 6. 关闭连接(code 默认 1000 正常关闭) task.close({ code: 1000, reason: "bye" });7.2 兼容用法:全局 API(已废弃)
接口注释中保留了旧式全局 API 的完整示例形态(interface.uts):
uni.onSocketOpen(function (res) { console.log('WebSocket连接已打开!'); }); uni.onSocketError(function (res) { console.log('WebSocket连接打开失败,请检查!'); }); uni.sendSocketMessage({ data: msg }); uni.onSocketMessage(function (res) { console.log('收到服务器内容:' + res.data); }); uni.closeSocket(); uni.onSocketClose(function (res) { console.log('WebSocket 已关闭!'); });注意:全局 API 只作用于最近一次创建的连接(源码见 WebSocketManager.uts 中始终取socketTasks[0]的逻辑),因此多连接场景请务必使用 SocketTask 形态,避免事件串线。
7.3 工程接入与版本前提
- 将
uni-websocket作为 uni_modules 插件引入工程后,uni.connectSocket等 API 即可在 App 三端使用;H5 / 小程序端则由 uni-app 框架自身能力提供,无需本插件(package.json 中uni-ext-api仅声明 app 平台 kotlin / swift / arkts 为 true)。 - 版本前提:HBuilderX
^3.6.8;App 端ArrayBuffer收发需 uni-app x 4.61 及以上;鸿蒙侧 uniVer 4.23 / unixVer 4.61 起可用(版本标注见 interface.uts 中各 API 的 @uniPlatform 注释)。 - Android 端最低支持 Android 4.4(minSdkVersion 19)。
八、使用注意事项与最佳实践
综合接口注释与源码,总结以下工程要点:
- 优先使用 SocketTask 而非全局 API:6 个
uni.onSocketXxx/uni.sendSocketMessage/uni.closeSocket均已标记废弃,且只作用于最近连接;SocketTask 形态支持多连接隔离。 - 发送时机:发送数据必须在连接打开(
onOpen回调触发)之后进行;未连接时send会以errCode 10002(webSocket is not connected)回调fail。 - 发送队列上限 16 MiB:超过 16 MiB 会触发
10001错误并关闭连接,需控制消息大小与频率。 - header 限制:
header中不能设置Referer。 - 关闭参数约束:
code默认 1000;reason为不超过123 字节的 UTF-8 文本。 - URL 校验:
url必填,格式不合法时返回错误码600009(invalid URL)。 - 连接生命周期:连接 error 或 close 后,任务会从管理器的
socketTasks数组中移除(见 WebSocketManager.uts),如需重连需重新调用connectSocket;可结合onClose/onError实现指数退避的重连策略。 - 二进制支持:收发
ArrayBuffer(二进制帧)需要 app 4.61+,做即时通讯的图片 / 音频上行场景可直接使用。
九、延伸阅读
- 模块本体:uni-websocket readme、package.json
- 接口与类型:interface.uts、interface.type.uts
- 参数协议与错误:protocol.uts、unierror.uts
- Android 实现:app-android/index.uts、WebSocketManager.uts
- 官方 API 文档:WebSocket 全局 API 文档、WebSocket API 文档
- UTS 相关:UTS 语言介绍、uts 和 ts 的差异、uts 插件开发文档、uts 插件原生语言混编开发文档、uts 插件 Android 平台开发注意事项、uts 插件 iOS 平台开发注意事项、uts 插件 HarmonyOS 平台开发注意事项
- 示例工程
- 前端
- 移动开发
- 跨平台
【免费下载链接】uni-app
A cross-platform framework using Vue.js
相关推荐
uni-route 页面路由管理 UTS 插件:uni-app x 跨端路由 API 的架构与源码解析
uni route 页面路由管理 UTS 插件:uni app x 跨端路由 API 的架构与源码解析 uni route 是 uni app 仓库中以 uni
示例工程前端移动开发跨平台uni-app x 腾讯定位 UTS 插件 uni-location-tencent 接入指南与源码解析
uni app x 腾讯定位 UTS 插件 uni location tencent 接入指南与源码解析 本文以 uni app 开源仓库中的 uni loca
示例工程前端移动开发跨平台uni-app 中的 uni-navigationBar UTS 插件:导航栏 API 的跨端实现与源码解析
uni app 中的 uni navigationBar UTS 插件:导航栏 API 的跨端实现与源码解析 uni navigationBar 是 uni a
示例工程前端移动开发跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考