当前位置: 首页 > news >正文

HarmonyOS WebSocket全场景应用开发深度解析

注:适用版本(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 = false
  this.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


  // 初始化 WebSocket
  private 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, '&lt;')  
    .replace(/>/g, '&gt;')  
    .substring(0, 500); // 限制消息长度  
}  

           3. 防止频繁发送

private lastSendTime: number = 0

sendMessage() {
  if (Date.now() - this.lastSendTime < 1000) {
    promptAction.showToast({ message: '发送太频繁啦!' })
    return
  }
  // ...正常发送逻辑
  this.lastSendTime = Date.now()
}

五、总结

  1. 测试地址:先用wss://echo.websocket.org这种公共测试服务

  2. 真机调试:记得在手机设置里打开应用的网络权限

  3. 基础样式:先实现功能再美化界面

  4. 错误处理:关键操作添加try-catch防止崩溃

通过这个简化版,开发者可以快速搭建基础聊天功能,再逐步添加进阶特性。建议先跑通基础代码,再按需扩展功能!

相关文章:

  • vllm+openwebui,玩转私有化AI
  • 无人机监视系统工作原理与运行要点!
  • HAL_UARTEx_ReceiveToIdle_DMA 开启,但是无法进入空闲中断;
  • Day 25:股票的最大利润 + 1到n求和
  • Pyside6 开发 使用Qt Designer
  • getID3获取本地或远程视频时长
  • 如何高效利用 Postman Mock Server? 模拟 API 响应,加速开发
  • Google PLA 营销库存服务设计技术难点与要点
  • 【PySpark大数据分析概述】01 大数据分析概述
  • 编程技术水平横向和垂直发展的抉择全方位分析
  • 复习一下冒泡排序算法
  • 推荐:大模型靠啥理解文字?通俗解释:词嵌入embedding
  • 06-ADC
  • MYTOOL-电路模块
  • windows安装JDK并配置环境变量
  • Arduino示例代码讲解:Serial Event example 连续事件例子
  • 鸿蒙北向应用开发:deveco 5.0 kit化文件相关2
  • python经典类、新式类写法、多继承
  • docker save如何迁移镜像更节省空间?
  • 数据结构与算法:2,冒泡排序
  • 汽车网站推广策略/软文宣传
  • 淮南今日头条新闻/河南平价的seo整站优化定制
  • 太原网站科技公司/网站设计制作哪家好
  • wordpress产品目录插件/官网seo是什么意思
  • 个人网站建设公司/seo网站优化培训怎么做
  • 创建网站花费/哈尔滨百度推广联系人