16 KiB
16 KiB
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<List<ChatMessageResponse>>
后端实现位置: LiveRoomController.java 第105-116行
@GetMapping("/public/rooms/{roomId}/messages")
public CommonResult<List<ChatMessageResponse>> getMessages(
@PathVariable Integer roomId,
@RequestParam(defaultValue = "50") Integer limit) {
if (roomId == null) return CommonResult.failed("参数错误");
List<LiveChat> messages = liveChatService.getRoomMessages(roomId, limit);
List<ChatMessageResponse> result = messages.stream()
.map(ChatMessageResponse::from)
.collect(Collectors.toList());
return CommonResult.success(result);
}
Android端实现
接口定义: ApiService.java 第67-71行
@GET("api/front/live/public/rooms/{roomId}/messages")
Call<ApiResponse<List<ChatMessageResponse>>> getRoomMessages(
@Path("roomId") String roomId,
@Query("limit") int limit);
问题:
- ✅ ApiService中已定义接口
- ❌ RoomDetailActivity中未调用此接口
- ❌ 进入直播间时没有加载历史弹幕
- ⚠️ 目前使用模拟数据生成弹幕(
startChatSimulation()方法)
TODO标记: RoomDetailActivity.java 第514行
// TODO: 接入后端接口 - 初始化时获取历史弹幕消息
// 接口路径: GET /api/rooms/{roomId}/messages
2. 发送弹幕消息接口 ⚠️
后端接口
POST /api/front/live/public/rooms/{roomId}/messages
参数:
- roomId: 房间ID(路径参数)
- message: 消息内容(请求体)
- visitorId: 访客ID(请求体,可选)
- nickname: 昵称(请求体,可选)
返回: ApiResponse<ChatMessageResponse>
后端实现位置: LiveRoomController.java 第118-143行
@PostMapping("/public/rooms/{roomId}/messages")
public CommonResult<ChatMessageResponse> sendMessage(
@PathVariable Integer roomId,
@RequestBody Map<String, String> body) {
String content = body.get("message");
String visitorId = body.get("visitorId");
String nickname = body.get("nickname");
// ... 保存消息逻辑
}
Android端实现
接口定义: ApiService.java 第73-76行
@POST("api/front/live/public/rooms/{roomId}/messages")
Call<ApiResponse<ChatMessageResponse>> sendRoomMessage(
@Path("roomId") String roomId,
@Body Map<String, String> 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
后端接口:
// 获取在线人数
GET /api/live/online/count/{roomId}
// 手动广播人数
POST /api/live/online/broadcast/{roomId}
Android端实现
状态: ❌ 未实现
问题:
- ❌ 没有连接在线人数WebSocket
- ❌ 没有发送心跳保活
- ❌ 没有接收在线人数更新
- ⚠️ 目前使用模拟数据显示观看人数
TODO标记: RoomDetailActivity.java 第656行
// TODO: 接入后端接口 - 获取实时观看人数
// 接口路径: GET /api/rooms/{roomId}/viewers/count
// 建议使用WebSocket实时推送观看人数变化,或每10-15秒轮询一次
🔧 需要修复的问题
问题1: 未加载历史弹幕 🔴 高优先级
影响: 用户进入直播间时看不到之前的弹幕消息
解决方案:
// 在 RoomDetailActivity.onCreate() 或 onStart() 中添加
private void loadHistoryMessages() {
if (TextUtils.isEmpty(roomId)) return;
ApiClient.getService(this).getRoomMessages(roomId, 50)
.enqueue(new Callback<ApiResponse<List<ChatMessageResponse>>>() {
@Override
public void onResponse(Call<ApiResponse<List<ChatMessageResponse>>> call,
Response<ApiResponse<List<ChatMessageResponse>>> response) {
if (response.isSuccessful() && response.body() != null
&& response.body().isOk()) {
List<ChatMessageResponse> messages = response.body().getData();
if (messages != null) {
for (ChatMessageResponse msg : messages) {
addChatMessage(new ChatMessage(
msg.getNickname(),
msg.getContent()
));
}
}
}
}
@Override
public void onFailure(Call<ApiResponse<List<ChatMessageResponse>>> call,
Throwable t) {
Log.e("RoomDetail", "加载历史弹幕失败: " + t.getMessage());
}
});
}
调用位置: 在connectWebSocket()之前调用,确保先显示历史消息
问题2: 未实现在线人数WebSocket ⚠️ 中优先级
影响: 无法实时显示观看人数变化
解决方案:
// 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行
private static final String WS_BASE_URL = "ws://192.168.1.164:8081/ws/live/chat/";
解决方案: 使用ApiConfig统一管理
// 在 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接口
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<String, String> 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<ApiResponse<ChatMessageResponse>>() {
@Override
public void onResponse(Call<ApiResponse<ChatMessageResponse>> call,
Response<ApiResponse<ChatMessageResponse>> response) {
if (response.isSuccessful() && response.body() != null
&& response.body().isOk()) {
// 本地显示发送的消息
addChatMessage(new ChatMessage("我", content));
}
}
@Override
public void onFailure(Call<ApiResponse<ChatMessageResponse>> call,
Throwable t) {
Toast.makeText(RoomDetailActivity.this,
"发送失败,请检查网络", Toast.LENGTH_SHORT).show();
}
});
}
📋 修复优先级
| 优先级 | 问题 | 预计工作量 | 影响范围 |
|---|---|---|---|
| 🔴 高 | 加载历史弹幕 | 30分钟 | 用户体验 |
| ⚠️ 中 | 在线人数WebSocket | 1-2小时 | 功能完整性 |
| 🟡 低 | WebSocket URL配置 | 15分钟 | 代码质量 |
| 🟡 低 | HTTP降级方案 | 30分钟 | 稳定性 |
✅ 修复步骤建议
第一步: 加载历史弹幕(30分钟)
- 在
RoomDetailActivity中添加loadHistoryMessages()方法 - 在
onStart()中调用,在connectWebSocket()之前 - 测试验证历史消息正常显示
第二步: 实现在线人数WebSocket(1-2小时)
- 添加在线人数WebSocket连接方法
- 实现心跳保活机制
- 处理在线人数更新消息
- 在
onStart()和onStop()中管理连接 - 测试验证在线人数实时更新
第三步: 优化WebSocket URL配置(15分钟)
- 在
ApiConfig中添加WebSocket URL方法 - 修改
RoomDetailActivity使用动态URL - 测试不同环境切换
第四步: 添加HTTP降级方案(30分钟)
- 实现
sendChatViaHttp()方法 - 在WebSocket失败时自动降级
- 测试降级场景
📊 对接完成度评估
| 功能 | 完成度 | 说明 |
|---|---|---|
| WebSocket弹幕实时推送 | 100% | ✅ 完全实现 |
| 发送弹幕消息 | 90% | ✅ WebSocket实现,缺少HTTP降级 |
| 获取历史弹幕 | 50% | ⚠️ 接口已定义,未调用 |
| 在线人数统计 | 0% | ❌ 完全未实现 |
| 总体完成度 | 60% | ⚠️ 核心功能已实现,需要完善 |
🎯 总结
已完成 ✅
- ✅ WebSocket弹幕实时推送(完整实现)
- ✅ 弹幕发送功能(WebSocket方式)
- ✅ 心跳保活机制
- ✅ 自动重连机制
- ✅ 接口定义完整
待完成 ⚠️
- ⚠️ 加载历史弹幕(高优先级)
- ⚠️ 在线人数WebSocket(中优先级)
- ⚠️ HTTP接口降级方案(低优先级)
- ⚠️ WebSocket URL配置优化(低优先级)
建议
- 优先修复历史弹幕加载,这对用户体验影响最大
- 实现在线人数WebSocket,完善功能完整性
- 添加HTTP降级方案,提高系统稳定性
- 统一WebSocket URL管理,提升代码质量
报告生成时间: 2024-12-29
分析人员: Kiro AI Assistant