注:适用版本(Harmony OS NEXT / 5.0 / API 12+ )
一、最终效果预览
二、基础代码结构
@Entry
@Component
struct ChatApp {@State messages: Message[] = [] // 所有聊天记录@State inputText: string = "" // 输入框内容@State isConnected: boolean = false // 是否在线private ws: webSocket.WebSocket | null = null// 建立连接private connect() {this.ws = webSocket.createWebSocket()this.ws.connect('wss://toolin.cn/echo')// 四个关键监听this.ws.on('open', () => this.isConnected = true)this.ws.on('message', (data) => {this.messages = [...this.messages, new Message('received', data.message)]})this.ws.on('close', () => this.isConnected = false)this.ws.on('error', (err) => console.error('出错啦:', err))}// 发送消息private sendMessage() {if (this.inputText && this.isConnected) {this.ws?.send(this.inputText)this.messages = [...this.messages, new Message('sent', this.inputText)]this.inputText = ""}}build() { /* 界面代码 */ }
}
三、核心功能
1、连接状态管理
// 显示连接状态
Text(this.isConnected ? '🟢 在线' : '🔴 离线').fontColor(this.isConnected ? Color.Green : Color.Red)// 连接/断开按钮
Button(this.isConnected ? '断开连接' : '点击连接').onClick(() => {this.isConnected ? this.ws?.close() : this.connect()})
2、消息收发演示
// 消息输入框
TextInput({ text: this.inputText, placeholder: '说点什么...'}).onChange((text) => this.inputText = text)// 发送按钮
Button('发送').onClick(() => this.sendMessage())// 消息气泡样式
List() {ForEach(this.messages, (msg) => {ListItem() {Text(`${msg.type === 'sent' ? '我' : '对方'}: ${msg.content}`).backgroundColor(msg.type === 'sent' ? '#e3f2fd' : '#ffffff').padding(10).borderRadius(8)}})
}
3、自动重连机制(心跳机制)
// 简单重连逻辑
private reconnect() {setTimeout(() => {console.log('尝试重新连接...')this.connect()}, 3000) // 3秒后重试
}// 在连接断开时触发
this.ws.on('close', () => {this.isConnected = falsethis.reconnect() // 自动重连
})
四、源码详情
import webSocket from '@ohos.net.webSocket' // 导入 WebSocket 模块
import { promptAction } from '@kit.ArkUI' // 导入弹窗模块export class Message { // 定义消息类type: 'sent' | 'received' // 消息类型,发送或接收content: string // 消息内容timestamp: number // 消息时间戳constructor(type: 'sent' | 'received', content: string) { // 构造函数this.type = type // 设置消息类型this.content = content // 设置消息内容this.timestamp = new Date().getTime() // 设置当前时间戳}
}@Entry // 标记为入口组件
@Component // 标记为组件
struct WebSocketDemo { // 定义 WebSocketDemo 组件// WebSocket 连接状态@State isConnected: boolean = false // 初始化为未连接// 消息输入框内容@State inputMessage: string = '' // 初始化为空字符串// 消息记录列表@State messages: Message[] = [] // 初始化为空数组// WebSocket 对象private ws: webSocket.WebSocket | null = null // 初始化为 null// 初始化 WebSocketprivate initWebSocket() {const wsUrl = 'wss://toolin.cn/echo' // 使用公共测试服务器try {this.ws = webSocket.createWebSocket() // 创建 WebSocket 实例// 注册事件监听this.ws.on('open', () => { // 监听连接打开事件this.isConnected = true // 设置连接状态为已连接this.addMessage('received', '连接已建立') // 添加连接成功消息})this.ws.on('message', (data) => { // 监听消息事件// 检查 data 对象是否包含 message 属性if (data && data.message) {this.addMessage('received', `收到消息: ${data.message}`) // 添加收到的消息} else {console.error('Received unexpected data:', data) // 输出错误日志}})this.ws.on('close', () => { // 监听连接关闭事件this.isConnected = false // 设置连接状态为未连接this.addMessage('received', '连接已关闭') // 添加连接关闭消息})this.ws.on('error', (err: Error) => { // 监听错误事件console.error('WebSocket 错误:', err) // 输出错误日志this.showAlert(`错误: ${err.message}`) // 显示错误弹窗})// 发起连接this.ws.connect(wsUrl) // 连接到 WebSocket 服务器} catch (error) {this.showAlert(`初始化失败: ${error.message}`) // 显示初始化失败弹窗}}// 添加消息到列表private addMessage(type: 'sent' | 'received', content: string) {this.messages = [...this.messages, new Message(type, content)] // 将新消息添加到消息列表}// 显示弹窗private async showAlert(message: string) {const res = await promptAction.showDialog({ // 显示弹窗title: '提示', // 弹窗标题message: message, // 弹窗内容buttons: [ // 弹窗按钮{ text: '取消', color: '#999999' }, // 取消按钮{ text: '确定', color: '#007aff' } // 确定按钮]})}build() {Column() { // 垂直布局// 连接状态显示Text(this.isConnected ? '已连接' : '未连接') // 显示连接状态.fontColor(this.isConnected ? Color.Green : Color.Red) // 设置字体颜色.margin(10) // 设置外边距// 控制按钮Row() { // 水平布局Button(this.isConnected ? '断开连接' : '建立连接') // 根据连接状态显示按钮文本.onClick(() => { // 点击事件处理if (this.isConnected) {this.ws?.close() // 关闭 WebSocket 连接this.ws = null // 将 WebSocket 对象设置为 null} else {this.initWebSocket() // 初始化 WebSocket 连接}}).margin(5) // 设置外边距Button('清空记录') // 清空记录按钮.onClick(() => this.messages = []) // 清空消息列表.margin(5) // 设置外边距}// 消息输入区TextInput({ text: this.inputMessage,placeholder:'请输入消息'}) // 文本输入框.onChange((value: string) => this.inputMessage = value) // 输入内容变化时更新 inputMessage.margin(10) // 设置外边距.height(60) // 设置高度.width('90%') // 设置宽度Button('发送消息') // 发送消息按钮.onClick(() => { // 点击事件处理if (this.inputMessage.trim() && this.isConnected) { // 检查输入内容和连接状态this.ws?.send(this.inputMessage) // 发送消息this.addMessage('sent', this.inputMessage) // 添加发送的消息this.inputMessage = '' // 清空输入框}}).margin(10) // 设置外边距// 消息记录列表List({ space: 10 }) { // 列表布局ForEach(this.messages, (msg: Message) => { // 遍历消息列表ListItem() { // 列表项Column() { // 垂直布局Text(`${msg.type === 'sent' ? '[发送]' : '[接收]'} ${msg.content}`) // 显示消息类型和内容.fontSize(14) // 设置字体大小.fontColor(msg.type === 'sent' ? Color.Blue : Color.Gray) // 设置字体颜色Text(new Date(msg.timestamp).toLocaleTimeString()) // 显示消息时间.fontSize(10) // 设置字体大小.fontColor(Color.Gray) // 设置字体颜色}.padding(10) // 设置内边距.width('100%') // 设置宽度.alignItems(msg.type === 'sent' ? HorizontalAlign.End : HorizontalAlign.Start) // 设置对齐方式}})}.layoutWeight(1) // 设置布局权重.divider({ strokeWidth: 1, color: '#eee' }) // 设置分隔线}.width('100%') // 设置宽度.height('100%') // 设置高度.padding(10) // 设置内边距.backgroundColor('#f0f0f0') // 设置背景颜色}
}
五、问题优化
1、权限配置问题
存在原因:
网络请求失败
控制台报错PERMISSION_DENIED
解决方法:module.josn5配置文件中配置网络权限
// module.json5 配置
"requestPermissions": [ { "name": "ohos.permission.INTERNET", }
]
2、 消息安全性风险
// 消息内容过滤
private sanitizeMessage(content: string): string { return content .replace(/</g, '<') .replace(/>/g, '>') .substring(0, 500); // 限制消息长度
}
3. 防止频繁发送
private lastSendTime: number = 0sendMessage() {if (Date.now() - this.lastSendTime < 1000) {promptAction.showToast({ message: '发送太频繁啦!' })return}// ...正常发送逻辑this.lastSendTime = Date.now()
}
五、总结
-
测试地址:先用
wss://echo.websocket.org
这种公共测试服务 -
真机调试:记得在手机设置里打开应用的网络权限
-
基础样式:先实现功能再美化界面
-
错误处理:关键操作添加try-catch防止崩溃
通过这个简化版,开发者可以快速搭建基础聊天功能,再逐步添加进阶特性。建议先跑通基础代码,再按需扩展功能!