# Android端直播间弹幕接口对接分析报告 > **分析时间**: 2024-12-29 > **分析范围**: 直播间弹幕和WebSocket实时通信功能 > **状态**: 🟡 部分完成,需要优化 --- ## 📊 接口对接状态总览 | 功能模块 | 后端接口 | Android端实现 | 对接状态 | 问题说明 | |---------|---------|--------------|---------|---------| | 获取历史弹幕 | ✅ 已实现 | ✅ 已定义 | ⚠️ 未调用 | ApiService中已定义接口,但未在Activity中调用 | | 发送弹幕消息 | ✅ 已实现 | ✅ 已定义 | ⚠️ 未调用 | ApiService中已定义接口,但未在Activity中调用 | | WebSocket弹幕实时推送 | ✅ 已实现 | ✅ 已实现 | ✅ 已对接 | 使用WebSocket实时接收弹幕 | | WebSocket在线人数统计 | ✅ 已实现 | ❌ 未实现 | ❌ 未对接 | 缺少在线人数WebSocket连接 | --- ## 🔍 详细分析 ### 1. 获取历史弹幕接口 ⚠️ #### 后端接口 ``` GET /api/front/live/public/rooms/{roomId}/messages 参数: - roomId: 房间ID(路径参数) - limit: 获取数量(查询参数,默认50) 返回: ApiResponse> ``` **后端实现位置**: `LiveRoomController.java` 第105-116行 ```java @GetMapping("/public/rooms/{roomId}/messages") public CommonResult> getMessages( @PathVariable Integer roomId, @RequestParam(defaultValue = "50") Integer limit) { if (roomId == null) return CommonResult.failed("参数错误"); List messages = liveChatService.getRoomMessages(roomId, limit); List result = messages.stream() .map(ChatMessageResponse::from) .collect(Collectors.toList()); return CommonResult.success(result); } ``` #### Android端实现 **接口定义**: `ApiService.java` 第67-71行 ```java @GET("api/front/live/public/rooms/{roomId}/messages") Call>> getRoomMessages( @Path("roomId") String roomId, @Query("limit") int limit); ``` **问题**: - ✅ ApiService中已定义接口 - ❌ RoomDetailActivity中未调用此接口 - ❌ 进入直播间时没有加载历史弹幕 - ⚠️ 目前使用模拟数据生成弹幕(`startChatSimulation()`方法) **TODO标记**: `RoomDetailActivity.java` 第514行 ```java // TODO: 接入后端接口 - 初始化时获取历史弹幕消息 // 接口路径: GET /api/rooms/{roomId}/messages ``` --- ### 2. 发送弹幕消息接口 ⚠️ #### 后端接口 ``` POST /api/front/live/public/rooms/{roomId}/messages 参数: - roomId: 房间ID(路径参数) - message: 消息内容(请求体) - visitorId: 访客ID(请求体,可选) - nickname: 昵称(请求体,可选) 返回: ApiResponse ``` **后端实现位置**: `LiveRoomController.java` 第118-143行 ```java @PostMapping("/public/rooms/{roomId}/messages") public CommonResult sendMessage( @PathVariable Integer roomId, @RequestBody Map body) { String content = body.get("message"); String visitorId = body.get("visitorId"); String nickname = body.get("nickname"); // ... 保存消息逻辑 } ``` #### Android端实现 **接口定义**: `ApiService.java` 第73-76行 ```java @POST("api/front/live/public/rooms/{roomId}/messages") Call> sendRoomMessage( @Path("roomId") String roomId, @Body Map body); ``` **问题**: - ✅ ApiService中已定义接口 - ❌ RoomDetailActivity中未调用此接口 - ✅ 目前使用WebSocket发送弹幕(`sendChatViaWebSocket()`方法) - ⚠️ 建议保留HTTP接口作为WebSocket失败时的降级方案 --- ### 3. WebSocket弹幕实时推送 ✅ #### 后端WebSocket端点 ``` ws://localhost:8080/ws/live/chat/{roomId} 功能: - 实时弹幕消息广播 - 消息格式: JSON - 敏感词过滤 ``` **后端实现位置**: - WebSocket配置: `WebSocketConfig.java` - 消息处理: `LiveChatWebSocketHandler.java` #### Android端实现 **方式1: RoomDetailActivity直接实现** ✅ - 位置: `RoomDetailActivity.java` 第87-88行 - WebSocket URL: `ws://192.168.1.164:8081/ws/live/chat/{roomId}` - 连接方法: `connectWebSocket()` 第249-308行 - 发送方法: `sendChatViaWebSocket()` 第383-401行 - 心跳机制: `startHeartbeat()` 第311-329行 **方式2: LiveChatClient封装** ✅ - 位置: `LiveChatClient.java` - 提供了完整的WebSocket客户端封装 - 支持连接、发送、接收、断开等操作 **状态**: ✅ 已完整实现 - ✅ WebSocket连接正常 - ✅ 消息发送和接收正常 - ✅ 心跳保活机制完善 - ✅ 自动重连机制完善 - ✅ 错误处理完善 --- ### 4. WebSocket在线人数统计 ❌ #### 后端WebSocket端点 ``` ws://localhost:8080/ws/live/{roomId}?clientId={clientId} 功能: - 实时在线人数统计 - 心跳保活机制 - 用户去重 ``` **后端实现位置**: - WebSocket配置: `LiveRoomWebSocketConfig.java` - 在线人数服务: `LiveRoomOnlineServiceImpl.java` - 消息处理: `LiveRoomWebSocketHandler.java` **后端接口**: ```java // 获取在线人数 GET /api/live/online/count/{roomId} // 手动广播人数 POST /api/live/online/broadcast/{roomId} ``` #### Android端实现 **状态**: ❌ 未实现 **问题**: - ❌ 没有连接在线人数WebSocket - ❌ 没有发送心跳保活 - ❌ 没有接收在线人数更新 - ⚠️ 目前使用模拟数据显示观看人数 **TODO标记**: `RoomDetailActivity.java` 第656行 ```java // TODO: 接入后端接口 - 获取实时观看人数 // 接口路径: GET /api/rooms/{roomId}/viewers/count // 建议使用WebSocket实时推送观看人数变化,或每10-15秒轮询一次 ``` --- ## 🔧 需要修复的问题 ### 问题1: 未加载历史弹幕 🔴 高优先级 **影响**: 用户进入直播间时看不到之前的弹幕消息 **解决方案**: ```java // 在 RoomDetailActivity.onCreate() 或 onStart() 中添加 private void loadHistoryMessages() { if (TextUtils.isEmpty(roomId)) return; ApiClient.getService(this).getRoomMessages(roomId, 50) .enqueue(new Callback>>() { @Override public void onResponse(Call>> call, Response>> response) { if (response.isSuccessful() && response.body() != null && response.body().isOk()) { List messages = response.body().getData(); if (messages != null) { for (ChatMessageResponse msg : messages) { addChatMessage(new ChatMessage( msg.getNickname(), msg.getContent() )); } } } } @Override public void onFailure(Call>> call, Throwable t) { Log.e("RoomDetail", "加载历史弹幕失败: " + t.getMessage()); } }); } ``` **调用位置**: 在`connectWebSocket()`之前调用,确保先显示历史消息 --- ### 问题2: 未实现在线人数WebSocket ⚠️ 中优先级 **影响**: 无法实时显示观看人数变化 **解决方案**: ```java // 1. 添加在线人数WebSocket连接 private WebSocket onlineWebSocket; private static final String WS_ONLINE_BASE_URL = "ws://192.168.1.164:8081/ws/live/"; private void connectOnlineWebSocket() { if (TextUtils.isEmpty(roomId)) return; // 生成唯一的clientId String clientId = AuthStore.getUserId(this) + "_" + System.currentTimeMillis(); Request request = new Request.Builder() .url(WS_ONLINE_BASE_URL + roomId + "?clientId=" + clientId) .build(); onlineWebSocket = wsClient.newWebSocket(request, new WebSocketListener() { @Override public void onOpen(WebSocket webSocket, okhttp3.Response response) { Log.d("OnlineWS", "在线人数WebSocket连接成功"); // 启动心跳 startOnlineHeartbeat(); } @Override public void onMessage(WebSocket webSocket, String text) { try { JSONObject json = new JSONObject(text); String type = json.optString("type", ""); if ("online_count".equals(type)) { int count = json.optInt("count", 0); handler.post(() -> { binding.topViewerCount.setText(String.valueOf(count)); }); } else if ("pong".equals(type)) { Log.d("OnlineWS", "收到在线人数心跳响应"); } } catch (JSONException e) { Log.e("OnlineWS", "解析消息失败: " + e.getMessage()); } } @Override public void onFailure(WebSocket webSocket, Throwable t, okhttp3.Response response) { Log.e("OnlineWS", "在线人数WebSocket连接失败: " + t.getMessage()); } @Override public void onClosed(WebSocket webSocket, int code, String reason) { Log.d("OnlineWS", "在线人数WebSocket关闭: " + reason); } }); } // 2. 在线人数心跳 private Runnable onlineHeartbeatRunnable; private void startOnlineHeartbeat() { stopOnlineHeartbeat(); onlineHeartbeatRunnable = new Runnable() { @Override public void run() { if (onlineWebSocket != null) { try { JSONObject ping = new JSONObject(); ping.put("type", "ping"); onlineWebSocket.send(ping.toString()); Log.d("OnlineWS", "发送在线人数心跳"); } catch (JSONException e) { Log.e("OnlineWS", "发送心跳失败: " + e.getMessage()); } handler.postDelayed(onlineHeartbeatRunnable, 25000); // 25秒心跳 } } }; handler.postDelayed(onlineHeartbeatRunnable, 25000); } private void stopOnlineHeartbeat() { if (onlineHeartbeatRunnable != null) { handler.removeCallbacks(onlineHeartbeatRunnable); onlineHeartbeatRunnable = null; } } // 3. 断开在线人数WebSocket private void disconnectOnlineWebSocket() { stopOnlineHeartbeat(); if (onlineWebSocket != null) { onlineWebSocket.close(1000, "Activity destroyed"); onlineWebSocket = null; } } ``` **调用位置**: - `onStart()`: 调用`connectOnlineWebSocket()` - `onStop()`: 调用`disconnectOnlineWebSocket()` --- ### 问题3: WebSocket URL硬编码 🟡 低优先级 **影响**: 切换环境时需要修改代码 **当前代码**: `RoomDetailActivity.java` 第87行 ```java private static final String WS_BASE_URL = "ws://192.168.1.164:8081/ws/live/chat/"; ``` **解决方案**: 使用ApiConfig统一管理 ```java // 在 ApiConfig.java 中添加 public static String getWebSocketBaseUrl() { return BASE_URL.replace("http://", "ws://") .replace("https://", "wss://"); } // 在 RoomDetailActivity.java 中使用 private String getWsChatUrl() { return ApiConfig.getWebSocketBaseUrl() + "/ws/live/chat/"; } private String getWsOnlineUrl() { return ApiConfig.getWebSocketBaseUrl() + "/ws/live/"; } ``` --- ### 问题4: 缺少HTTP接口降级方案 🟡 低优先级 **影响**: WebSocket失败时无法发送弹幕 **解决方案**: 在WebSocket发送失败时使用HTTP接口 ```java private void sendChatViaWebSocket(String content) { if (webSocket == null || !isWebSocketConnected) { // WebSocket未连接,使用HTTP接口发送 sendChatViaHttp(content); return; } try { JSONObject json = new JSONObject(); json.put("type", "chat"); json.put("content", content); json.put("nickname", AuthStore.getNickname(this)); json.put("userId", AuthStore.getUserId(this)); boolean sent = webSocket.send(json.toString()); if (!sent) { // 发送失败,使用HTTP接口 sendChatViaHttp(content); } } catch (JSONException e) { Log.e("WebSocket", "发送消息失败: " + e.getMessage()); // 失败时使用HTTP接口 sendChatViaHttp(content); } } private void sendChatViaHttp(String content) { Map body = new HashMap<>(); body.put("message", content); body.put("visitorId", AuthStore.getUserId(this)); body.put("nickname", AuthStore.getNickname(this)); ApiClient.getService(this).sendRoomMessage(roomId, body) .enqueue(new Callback>() { @Override public void onResponse(Call> call, Response> response) { if (response.isSuccessful() && response.body() != null && response.body().isOk()) { // 本地显示发送的消息 addChatMessage(new ChatMessage("我", content)); } } @Override public void onFailure(Call> call, Throwable t) { Toast.makeText(RoomDetailActivity.this, "发送失败,请检查网络", Toast.LENGTH_SHORT).show(); } }); } ``` --- ## 📋 修复优先级 | 优先级 | 问题 | 预计工作量 | 影响范围 | |-------|------|-----------|---------| | 🔴 高 | 加载历史弹幕 | 30分钟 | 用户体验 | | ⚠️ 中 | 在线人数WebSocket | 1-2小时 | 功能完整性 | | 🟡 低 | WebSocket URL配置 | 15分钟 | 代码质量 | | 🟡 低 | HTTP降级方案 | 30分钟 | 稳定性 | --- ## ✅ 修复步骤建议 ### 第一步: 加载历史弹幕(30分钟) 1. 在`RoomDetailActivity`中添加`loadHistoryMessages()`方法 2. 在`onStart()`中调用,在`connectWebSocket()`之前 3. 测试验证历史消息正常显示 ### 第二步: 实现在线人数WebSocket(1-2小时) 1. 添加在线人数WebSocket连接方法 2. 实现心跳保活机制 3. 处理在线人数更新消息 4. 在`onStart()`和`onStop()`中管理连接 5. 测试验证在线人数实时更新 ### 第三步: 优化WebSocket URL配置(15分钟) 1. 在`ApiConfig`中添加WebSocket URL方法 2. 修改`RoomDetailActivity`使用动态URL 3. 测试不同环境切换 ### 第四步: 添加HTTP降级方案(30分钟) 1. 实现`sendChatViaHttp()`方法 2. 在WebSocket失败时自动降级 3. 测试降级场景 --- ## 📊 对接完成度评估 | 功能 | 完成度 | 说明 | |------|-------|------| | WebSocket弹幕实时推送 | 100% | ✅ 完全实现 | | 发送弹幕消息 | 90% | ✅ WebSocket实现,缺少HTTP降级 | | 获取历史弹幕 | 50% | ⚠️ 接口已定义,未调用 | | 在线人数统计 | 0% | ❌ 完全未实现 | | **总体完成度** | **60%** | ⚠️ 核心功能已实现,需要完善 | --- ## 🎯 总结 ### 已完成 ✅ 1. ✅ WebSocket弹幕实时推送(完整实现) 2. ✅ 弹幕发送功能(WebSocket方式) 3. ✅ 心跳保活机制 4. ✅ 自动重连机制 5. ✅ 接口定义完整 ### 待完成 ⚠️ 1. ⚠️ 加载历史弹幕(高优先级) 2. ⚠️ 在线人数WebSocket(中优先级) 3. ⚠️ HTTP接口降级方案(低优先级) 4. ⚠️ WebSocket URL配置优化(低优先级) ### 建议 1. **优先修复历史弹幕加载**,这对用户体验影响最大 2. **实现在线人数WebSocket**,完善功能完整性 3. **添加HTTP降级方案**,提高系统稳定性 4. **统一WebSocket URL管理**,提升代码质量 --- **报告生成时间**: 2024-12-29 **分析人员**: Kiro AI Assistant