HarmonyOS WebSocket实时通信:从基础原理到复杂场景实践

HarmonyOS WebSocket实时通信:从基础原理到复杂场景实践

引言:实时通信在移动应用中的重要性

在当今的移动应用生态中,实时通信能力已经成为众多应用的核心需求。从即时聊天、在线游戏到实时数据监控、协同编辑,实时通信技术支撑着现代应用的用户体验。HarmonyOS作为新一代的分布式操作系统,为开发者提供了强大的WebSocket通信能力,使得构建高性能实时应用成为可能。

与传统的HTTP轮询相比,WebSocket提供了真正的全双工通信通道,显著降低了延迟和带宽消耗。本文将深入探讨在HarmonyOS应用中实现WebSocket通信的完整技术栈,涵盖从基础连接到复杂场景的最佳实践。

WebSocket协议基础与HarmonyOS实现架构

WebSocket协议核心特性

WebSocket协议(RFC 6455)在单个TCP连接上提供全双工通信通道,具有以下核心特性:

  • 低延迟通信:建立连接后,客户端和服务器可以随时发送数据,无需HTTP握手开销
  • 双向通信:服务器可以主动向客户端推送数据,突破HTTP请求-响应模式的限制
  • 轻量级帧结构:数据帧开销极小,通常只有2-10字节的协议头部
  • 跨域支持:天然支持跨域通信,简化了分布式应用开发

HarmonyOS WebSocket架构设计

HarmonyOS的WebSocket实现基于分层的架构设计:

复制代码
应用层
  ↓
WebSocket API接口层
  ↓
网络通信管理层  
  ↓
Socket传输层
  ↓
TCP/IP协议栈

这种分层设计使得开发者可以专注于业务逻辑,而无需关心底层的网络细节和连接管理。

HarmonyOS WebSocket API详解

核心类与接口

HarmonyOS提供了@ohos.net.socket模块来处理WebSocket通信,主要包含以下核心类:

  • WebSocket:主要的WebSocket客户端类
  • WebSocketRequest:连接请求配置类
  • WebSocketReadyState:连接状态枚举
  • WebSocketCloseInfo:连接关闭信息类

连接建立与配置

typescript 复制代码
import socket from '@ohos.net.socket';
import { BusinessError } from '@ohos.base';

class WebSocketManager {
  private webSocket: socket.WebSocket | null = null;
  private readonly RECONNECT_INTERVAL = 3000;
  private readonly MAX_RECONNECT_ATTEMPTS = 5;
  private reconnectAttempts = 0;
  private isManualClose = false;

  // 创建WebSocket连接
  async connect(url: string, protocols?: string[]): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        let request: socket.WebSocketRequest = {
          url: url,
          header: {
            'User-Agent': 'HarmonyOS-WebSocket-Client/1.0',
            'Origin': 'myapp://bundleName'
          },
          protocols: protocols
        };

        this.webSocket = socket.constructWebSocketInstance();
        
        this.webSocket.on('open', (err: BusinessError) => {
          if (err) {
            reject(err);
            return;
          }
          console.info('WebSocket连接已建立');
          this.reconnectAttempts = 0;
          resolve();
        });

        this.webSocket.on('message', (data: string | ArrayBuffer) => {
          this.handleMessage(data);
        });

        this.webSocket.on('close', (code: number, reason: string) => {
          console.info(`WebSocket连接关闭: ${code}, ${reason}`);
          this.handleClose(code, reason);
        });

        this.webSocket.on('error', (err: BusinessError) => {
          console.error(`WebSocket错误: ${JSON.stringify(err)}`);
          this.handleError(err);
        });

        this.webSocket.connect(request, (err: BusinessError) => {
          if (err) {
            reject(err);
          }
        });
      } catch (error) {
        reject(error);
      }
    });
  }
}

消息收发机制

WebSocket支持文本和二进制两种消息格式,HarmonyOS提供了相应的发送和接收方法:

typescript 复制代码
class WebSocketManager {
  // 发送文本消息
  sendTextMessage(message: string): boolean {
    if (!this.webSocket || this.webSocket.readyState !== socket.WebSocketReadyState.OPEN) {
      console.error('WebSocket未连接,无法发送消息');
      return false;
    }

    try {
      this.webSocket.send(message, (err: BusinessError) => {
        if (err) {
          console.error('发送消息失败:', err);
          return false;
        }
        console.info('消息发送成功');
      });
      return true;
    } catch (error) {
      console.error('发送消息异常:', error);
      return false;
    }
  }

  // 发送二进制数据
  sendBinaryData(data: ArrayBuffer): boolean {
    if (!this.webSocket || this.webSocket.readyState !== socket.WebSocketReadyState.OPEN) {
      return false;
    }

    try {
      this.webSocket.send(data, (err: BusinessError) => {
        if (err) {
          console.error('发送二进制数据失败:', err);
        }
      });
      return true;
    } catch (error) {
      console.error('发送二进制数据异常:', error);
      return false;
    }
  }

  // 处理接收到的消息
  private handleMessage(data: string | ArrayBuffer): void {
    if (typeof data === 'string') {
      console.info('收到文本消息:', data);
      this.processTextMessage(data);
    } else {
      console.info('收到二进制数据,长度:', data.byteLength);
      this.processBinaryMessage(data);
    }
  }

  private processTextMessage(message: string): void {
    try {
      const parsed = JSON.parse(message);
      // 根据消息类型分发给不同的处理器
      this.dispatchMessage(parsed);
    } catch (error) {
      console.error('消息解析失败:', error);
    }
  }

  private processBinaryMessage(data: ArrayBuffer): void {
    // 处理二进制数据,如图片、音频等
    const view = new Uint8Array(data);
    this.handleBinaryData(view);
  }
}

实战案例:构建分布式实时数据监控系统

场景描述与架构设计

我们构建一个分布式环境下的实时数据监控系统,该系统需要:

  • 在多个设备间同步监控数据
  • 支持设备动态加入和离开
  • 实现数据的高可靠性传输
  • 支持大规模并发连接

系统架构

复制代码
监控数据源 → WebSocket网关 → HarmonyOS设备集群
                    ↓
             数据持久化存储

消息协议设计

为了实现可靠的实时通信,我们需要设计一套完整的消息协议:

typescript 复制代码
// 消息类型枚举
enum MessageType {
  HEARTBEAT = 'heartbeat',
  DATA_UPDATE = 'data_update',
  DEVICE_JOIN = 'device_join',
  DEVICE_LEAVE = 'device_leave',
  COMMAND = 'command',
  ACK = 'acknowledgement'
}

// 基础消息接口
interface BaseMessage {
  type: MessageType;
  messageId: string;
  timestamp: number;
  sourceDevice: string;
  version: string;
}

// 数据更新消息
interface DataUpdateMessage extends BaseMessage {
  type: MessageType.DATA_UPDATE;
  payload: {
    metric: string;
    value: number;
    unit: string;
    tags: Record<string, string>;
  };
}

// 设备状态消息
interface DeviceStatusMessage extends BaseMessage {
  type: MessageType.DEVICE_JOIN | MessageType.DEVICE_LEAVE;
  payload: {
    deviceId: string;
    deviceType: string;
    capabilities: string[];
  };
}

// 命令消息
interface CommandMessage extends BaseMessage {
  type: MessageType.COMMAND;
  payload: {
    command: string;
    parameters: Record<string, any>;
    targetDevices?: string[];
  };
}

type WebSocketMessage = DataUpdateMessage | DeviceStatusMessage | CommandMessage;

连接管理与重连策略

在分布式环境中,网络不稳定是常见问题,需要实现智能的重连机制:

typescript 复制代码
class RobustWebSocketManager extends WebSocketManager {
  private heartbeatInterval: number = 0;
  private readonly HEARTBEAT_INTERVAL_MS = 30000;
  private lastPongTime: number = 0;
  private isConnectionStable: boolean = false;

  // 增强的连接方法
  async connectWithRetry(url: string, protocols?: string[]): Promise<void> {
    try {
      await this.connect(url, protocols);
      this.startHeartbeat();
      this.monitorConnectionHealth();
    } catch (error) {
      console.error('初始连接失败,开始重连:', error);
      await this.scheduleReconnect();
    }
  }

  private async scheduleReconnect(): Promise<void> {
    if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS || this.isManualClose) {
      console.info('达到最大重连次数或手动关闭,停止重连');
      return;
    }

    this.reconnectAttempts++;
    const delay = this.calculateReconnectDelay();
    
    console.info(`等待 ${delay}ms 后尝试第 ${this.reconnectAttempts} 次重连`);
    
    setTimeout(async () => {
      try {
        await this.connect(this.currentUrl!, this.currentProtocols);
        this.startHeartbeat();
      } catch (error) {
        console.error(`第 ${this.reconnectAttempts} 次重连失败:`, error);
        await this.scheduleReconnect();
      }
    }, delay);
  }

  private calculateReconnectDelay(): number {
    // 指数退避策略,最大延迟30秒
    const baseDelay = this.RECONNECT_INTERVAL;
    const maxDelay = 30000;
    const delay = Math.min(baseDelay * Math.pow(1.5, this.reconnectAttempts - 1), maxDelay);
    
    // 添加随机抖动,避免多个客户端同时重连
    const jitter = delay * 0.1 * Math.random();
    return delay + jitter;
  }

  // 心跳机制
  private startHeartbeat(): void {
    this.stopHeartbeat();
    
    this.heartbeatInterval = setInterval(() => {
      if (this.webSocket?.readyState === socket.WebSocketReadyState.OPEN) {
        const heartbeatMsg = {
          type: MessageType.HEARTBEAT,
          messageId: this.generateMessageId(),
          timestamp: Date.now(),
          sourceDevice: this.deviceId
        };
        
        this.sendTextMessage(JSON.stringify(heartbeatMsg));
        this.lastPongTime = Date.now();
      }
    }, this.HEARTBEAT_INTERVAL_MS) as unknown as number;
  }

  private stopHeartbeat(): void {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = 0;
    }
  }

  // 连接健康监测
  private monitorConnectionHealth(): void {
    const checkInterval = setInterval(() => {
      if (!this.webSocket) {
        clearInterval(checkInterval);
        return;
      }

      const timeSinceLastPong = Date.now() - this.lastPongTime;
      if (timeSinceLastPong > this.HEARTBEAT_INTERVAL_MS * 2) {
        console.warn('连接可能已断开,尝试重新连接');
        this.handleConnectionLoss();
        clearInterval(checkInterval);
      }
    }, this.HEARTBEAT_INTERVAL_MS);
  }
}

消息可靠性保证

在实时监控系统中,关键数据的丢失是不可接受的。我们需要实现消息确认机制:

typescript 复制代码
class ReliableMessageHandler {
  private pendingAcks: Map<string, { message: any, timestamp: number, retries: number }> = new Map();
  private readonly MAX_RETRIES = 3;
  private readonly ACK_TIMEOUT = 5000;

  // 发送可靠消息
  async sendReliableMessage(message: WebSocketMessage, websocketManager: WebSocketManager): Promise<boolean> {
    return new Promise((resolve) => {
      const messageId = message.messageId;
      
      // 添加到待确认队列
      this.pendingAcks.set(messageId, {
        message: message,
        timestamp: Date.now(),
        retries: 0
      });

      // 设置超时检查
      const timeoutId = setTimeout(() => {
        this.handleMessageTimeout(messageId, websocketManager, resolve);
      }, this.ACK_TIMEOUT);

      // 发送消息
      const sent = websocketManager.sendTextMessage(JSON.stringify(message));
      
      if (!sent) {
        clearTimeout(timeoutId);
        this.pendingAcks.delete(messageId);
        resolve(false);
      }
    });
  }

  private handleMessageTimeout(messageId: string, websocketManager: WebSocketManager, resolve: (success: boolean) => void): void {
    const pending = this.pendingAcks.get(messageId);
    if (!pending) {
      resolve(false);
      return;
    }

    if (pending.retries >= this.MAX_RETRIES) {
      console.error(`消息 ${messageId} 达到最大重试次数`);
      this.pendingAcks.delete(messageId);
      resolve(false);
      return;
    }

    // 重试发送
    pending.retries++;
    pending.timestamp = Date.now();
    
    console.info(`重试发送消息 ${messageId}, 第 ${pending.retries} 次`);
    websocketManager.sendTextMessage(JSON.stringify(pending.message));
    
    // 重新设置超时
    setTimeout(() => {
      this.handleMessageTimeout(messageId, websocketManager, resolve);
    }, this.ACK_TIMEOUT);
  }

  // 处理确认消息
  handleAcknowledgment(ackMessage: any): void {
    const messageId = ackMessage.originalMessageId;
    if (this.pendingAcks.has(messageId)) {
      console.info(`消息 ${messageId} 已确认`);
      this.pendingAcks.delete(messageId);
    }
  }
}

高级特性与性能优化

消息压缩与批处理

对于高频数据监控场景,我们需要优化网络传输效率:

typescript 复制代码
class MessageOptimizer {
  private messageQueue: any[] = [];
  private batchInterval: number = 0;
  private readonly BATCH_INTERVAL_MS = 100;
  private readonly MAX_BATCH_SIZE = 50;

  constructor(private websocketManager: WebSocketManager) {}

  // 启动批处理
  startBatching(): void {
    this.batchInterval = setInterval(() => {
      this.processBatch();
    }, this.BATCH_INTERVAL_MS) as unknown as number;
  }

  stopBatching(): void {
    if (this.batchInterval) {
      clearInterval(this.batchInterval);
      this.batchInterval = 0;
      // 处理剩余消息
      this.processBatch();
    }
  }

  // 添加消息到批处理队列
  addToBatch(message: any): void {
    this.messageQueue.push(message);
    
    // 如果队列达到最大大小,立即处理
    if (this.messageQueue.length >= this.MAX_BATCH_SIZE) {
      this.processBatch();
    }
  }

  private processBatch(): void {
    if (this.messageQueue.length === 0) return;

    const batch = this.messageQueue.splice(0, this.MAX_BATCH_SIZE);
    const compressedBatch = this.compressBatch(batch);
    
    this.websocketManager.sendTextMessage(JSON.stringify(compressedBatch));
  }

  private compressBatch(messages: any[]): any {
    // 简单的批量和压缩处理
    if (messages.length === 1) {
      return messages[0];
    }

    // 提取公共字段以减少重复数据
    const baseMessage = { ...messages[0] };
    const variations = messages.map(msg => {
      const variation: any = {};
      Object.keys(msg).forEach(key => {
        if (msg[key] !== baseMessage[key]) {
          variation[key] = msg[key];
        }
      });
      return variation;
    });

    return {
      type: 'batch',
      base: baseMessage,
      variations: variations,
      count: messages.length,
      timestamp: Date.now()
    };
  }
}

分布式会话管理

在多个HarmonyOS设备间保持会话同步:

typescript 复制代码
class DistributedSessionManager {
  private sessions: Map<string, DeviceSession> = new Map();
  private readonly syncInterval: number = 0;

  constructor(private websocketManager: WebSocketManager) {
    this.setupSessionSync();
  }

  // 创建设备会话
  createSession(deviceId: string, capabilities: string[]): DeviceSession {
    const session: DeviceSession = {
      deviceId,
      capabilities,
      isActive: true,
      lastSeen: Date.now(),
      subscription: new Set()
    };

    this.sessions.set(deviceId, session);
    
    // 广播设备加入消息
    this.broadcastDeviceStatus(deviceId, 'join');
    
    return session;
  }

  // 处理设备离开
  handleDeviceLeave(deviceId: string): void {
    const session = this.sessions.get(deviceId);
    if (session) {
      session.isActive = false;
      this.broadcastDeviceStatus(deviceId, 'leave');
      
      // 延迟清理,避免频繁的加入离开
      setTimeout(() => {
        if (!session.isActive) {
          this.sessions.delete(deviceId);
        }
      }, 30000);
    }
  }

  // 设置会话同步
  private setupSessionSync(): void {
    // 定期同步会话状态
    this.syncInterval = setInterval(() => {
      this.syncSessions();
    }, 60000) as unknown as number;
  }

  private syncSessions(): void {
    const activeSessions = Array.from(this.sessions.values())
      .filter(session => session.isActive)
      .map(session => ({
        deviceId: session.deviceId,
        capabilities: session.capabilities,
        lastSeen: session.lastSeen
      }));

    const syncMessage = {
      type: 'session_sync',
      sessions: activeSessions,
      timestamp: Date.now()
    };

    this.websocketManager.sendTextMessage(JSON.stringify(syncMessage));
  }

  private broadcastDeviceStatus(deviceId: string, status: 'join' | 'leave'): void {
    const message = {
      type: status === 'join' ? MessageType.DEVICE_JOIN : MessageType.DEVICE_LEAVE,
      deviceId,
      timestamp: Date.now()
    };

    this.websocketManager.sendTextMessage(JSON.stringify(message));
  }
}

interface DeviceSession {
  deviceId: string;
  capabilities: string[];
  isActive: boolean;
  lastSeen: number;
  subscription: Set<string>;
}

安全性与错误处理

安全通信实践

typescript 复制代码
class SecureWebSocketManager extends RobustWebSocketManager {
  private cryptoManager: CryptoManager;

  constructor() {
    super();
    this.cryptoManager = new CryptoManager();
  }

  // 发送加密消息
  async sendEncryptedMessage(payload: any, recipientDeviceId?: string): Promise<boolean> {
    try {
      const encryptedPayload = await this.cryptoManager.encrypt(
        JSON.stringify(payload),
        recipientDeviceId
      );

      const secureMessage = {
        type: 'secure_data',
        payload: encryptedPayload,
        recipient: recipientDeviceId,
        timestamp: Date.now(),
        messageId: this.generateMessageId()
      };

      return this.sendReliableMessage(secureMessage, this);
    } catch (error) {
      console.error('加密消息发送失败:', error);
      return false;
    }
  }

  // 处理接收到的加密消息
  private async handleSecureMessage(secureMessage: any): Promise<void> {
    try {
      const decryptedData = await this.cryptoManager.decrypt(secureMessage.payload);
      const payload = JSON.parse(decryptedData);
      
      // 验证消息来源
      if (await this.verifyMessageSource(secureMessage, payload)) {
        this.dispatchMessage(payload);
      } else {
        console.warn('消息来源验证失败,丢弃消息');
      }
    } catch (error) {
      console.error('安全消息处理失败:', error);
    }
  }
}

完整的错误处理框架

typescript 复制代码
class WebSocketErrorHandler {
  private errorCallbacks: Map<string, (error: any) => void> = new Map();

  registerErrorHandler(errorType: string, callback: (error: any) => void): void {
    this.errorCallbacks.set(errorType, callback);
  }

  handleError(error: any, context?: string): void {
    const errorType = this.classifyError(error);
    const callback = this.errorCallbacks.get(errorType);
    
    if (callback) {
      callback(error);
    } else {
      this.handleUnclassifiedError(error, context);
    }
    
    // 记录错误日志
    this.logError(error, context);
  }

  private classifyError(error: any): string {
    if (error.code) {
      switch (error.code) {
        case 1006: return 'connection_abnormal';
        case 1011: return 'server_error';
        case 1012: return 'service_restart';
        default: return 'network_error';
      }
    }
    
    if (error.message?.includes('timeout')) return 'timeout';
    if (error.message?.includes('SSL')) return 'ssl_error';
    
    return 'unknown_error';
  }

  private handleUnclassifiedError(error: any, context?: string): void {
    console.error(`未处理的WebSocket错误 [${context}]:`, error);
    
    // 可以上报到监控系统
    this.reportToMonitoring(error, context);
  }

  private logError(error: any, context?: string): void {
    const logEntry = {
      timestamp: new Date().toISOString(),
      context: context || 'unknown',
      error: {
        message: error.message,
        code: error.code,
        stack: error.stack
      },
      deviceInfo: this.getDeviceInfo()
    };
    
    // 保存到本地日志或发送到日志服务器
    this.persistLog(logEntry);
  }
}

测试与调试策略

单元测试示例

typescript 复制代码
import { describe, it, expect, beforeEach, afterEach } from 'deccjsunit';

describe('WebSocketManager Tests', () => {
  let websocketManager: WebSocketManager;
  let mockWebSocket: any;

  beforeEach(() => {
    websocketManager = new WebSocketManager();
    // 设置mock WebSocket
    mockWebSocket = {
      readyState: 0,
      connect: () => {},
      send: () => {},
      close: () => {}
    };
  });

  afterEach(() => {
    websocketManager.disconnect();
  });

  it('should establish connection successfully', async () => {
    const testUrl = 'ws://localhost:8080';
    
    await websocketManager.connect(testUrl);
    
    expect(websocketManager.isConnected()).toBeTrue();
  });

  it('should handle connection errors gracefully', async () => {
    const invalidUrl = 'ws://invalid-url:9999';
    
    try {
      await websocketManager.connect(invalidUrl);
      expect(true).toBeFalse(); // 不应该执行到这里
    } catch (error) {
      expect(error).toBeDefined();
      expect(websocketManager.isConnected()).toBeFalse();
    }
  });

  it('should send and receive messages correctly', async () => {
    const testMessage = { type: 'test', data: 'hello' };
    let receivedMessage: any = null;
    
    websocketManager.onMessage((message) => {
      receivedMessage = message;
    });
    
    await websocketManager.sendMessage(testMessage);
    
    // 模拟收到回复
    websocketManager.handleMessage(JSON.stringify({ type: 'response', data: 'world' }));
    
    expect(receivedMessage).not.toBeNull();
    expect(receivedMessage.data).toBe('world');
  });
});

性能监控与指标收集

typescript 复制代码
class WebSocketPerformanceMonitor {
  private metrics: PerformanceMetrics = {
    messageCount: 0,
    totalBytes: 0,
    connectionUptime: 0,
    reconnectCount: 0,
    averageLatency: 0
  };

  private connectionStartTime: number = 0;
  private latencyMeasurements: number[] = [];

  startMonitoring(): void {
    this.connectionStartTime = Date.now();
    setInterval(() => this.updateMetrics(), 5000);
  }

  recordMessageSent(messageSize: number): void {
    this.metrics.messageCount++;
    this.metrics.totalBytes += messageSize;
  }

  recordMessageReceived(): void {
    this.metrics.messageCount++;
  }

  recordLatency(latency: number): void {
    this.latencyMeasurements.push(latency);
    
    // 保持最近100次测量
    if (this.latencyMeasurements.length > 100) {
      this.latencyMeasurements.shift();
    }
    
    this.metrics.averageLatency = this.calculateAverageLatency();
  }

  recordReconnect(): void {
    this.metrics.reconnectCount++;
  }

  private updateMetrics(): void {
    this.metrics.connectionUptime = Date.now() - this.connectionStartTime;
    
    // 可以上报到监控系统
    this.reportMetrics();
  }

  private calculateAverageLatency(): number {
    if (this.latencyMeasurements.length === 0) return 0;
    
    const sum = this.latencyMeasurements.reduce((a, b) => a + b, 0);
    return sum / this.latencyMeasurements.length;
  }

  getMetrics(): PerformanceMetrics {
    return { ...this.metrics };
  }
}

interface PerformanceMetrics {
  messageCount: number;
  totalBytes: number;
  connectionUptime: number;
  reconnectCount: number;
  averageLatency: number;
}

总结与最佳实践

通过本文的深入探讨,我们了解了在HarmonyOS应用中实现WebSocket实时通信的完整技术栈。以下是一些关键的最佳实践总结:

  1. 连接管理:实现智能的重连机制和心跳保活,确保连接稳定性
  2. 消息可靠性:对于关键数据,实现确认机制和重传策略
  3. 性能优化:使用消息批处理和压缩减少网络开销
  4. 安全性:实施端到端加密和消息验证机制
  5. 错误处理:建立完整的错误分类和处理框架
  6. 监控指标:收集关键性能指标用于系统优化

HarmonyOS的WebSocket API为开发者提供了强大的基础能力,结合本文介绍的高级特性和最佳实践,可以构建出高性能、高可靠的实时通信应用。随着HarmonyOS生态的不断发展,WebSocket技术在分布式场景中的应用将会更加广泛和重要。

在实际开发中,建议根据具体业务需求选择合适的特性组合,并在测试环境中充分验证系统的稳定性和性能表现。通过持续优化和改进,可以打造出卓越的用户体验。

复制代码
这篇文章深入探讨了HarmonyOS中WebSocket实时通信的完整实现方案,涵盖了从基础API使用到高级特性的各个方面。文章通过实际的代码示例展示了如何在HarmonyOS应用中构建可靠、高效的实时通信系统,并提供了性能优化、错误处理和安全通信的最佳实践。
相关推荐
二流小码农5 小时前
鸿蒙开发:支持自定义组件的跑马灯
android·ios·harmonyos
2013编程爱好者7 小时前
【HUAWEI】HUAWEI Mate 70 Air详解
华为·harmonyos
爱笑的眼睛1111 小时前
HarmonyOS USB设备管理深度探索:从基础到高级应用
华为·harmonyos
爱笑的眼睛1113 小时前
HarmonyOS文件压缩与解压缩API深度解析与实践
华为·harmonyos
柒儿吖16 小时前
Qt for HarmonyOS 水平进度条组件开发实战
开发语言·qt·harmonyos
xiaocao_102318 小时前
鸿蒙手机上有没有轻便好用的备忘录APP?
华为·智能手机·harmonyos
qq_3168377520 小时前
华为CCE k8s 使用nfs-subdir-external-provisioner 创建pvc时自动创建pv
windows·华为·kubernetes
程序员老刘1 天前
4:2:1!老刘的三季度项目报告
flutter·harmonyos·客户端
深盾科技1 天前
鸿蒙应用构建体系深度解析:ABC、HAP、HAR、HSP与APP的技术全貌
华为·harmonyos