guoyu/log/屏幕流监控功能实现方案.md
2025-12-03 18:58:36 +08:00

368 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 屏幕流监控功能实现方案
## 一、功能概述
基于 UniApp 开发的安卓 App实现局域网内后台按需调取学习端屏幕画面的功能。
### 核心需求
1. **按需启动**:后台管理端点击特定学生账号后,触发该账号绑定的安卓 App 启动屏幕捕获
2. **实时传输**:将学习画面实时传输到后台
3. **资源节省**:不点击时 App 不进行任何捕获和传输操作
4. **局域网传输**:全程在局域网内传输,不依赖外网
5. **权限兼容**:适配安卓 10+ 版本,处理好屏幕捕获权限、后台保活
## 二、技术方案
### 2.1 架构设计
```
┌─────────────────┐ WebSocket ┌─────────────────┐
│ 学生端 App │ ◄─────────────────────────► │ 后台管理端 │
│ (UniApp) │ │ (RuoYi) │
│ │ │ │
│ - 屏幕捕获 │ │ - 指令控制 │
│ - WebSocket │ │ - 画面显示 │
│ - 按需启动 │ │ - 学生管理 │
└─────────────────┘ └─────────────────┘
```
### 2.2 技术选型
**前端UniApp**
- 屏幕捕获:使用 `plus.screen.capture` API安卓原生
- 通信协议WebSocket实时双向通信
- 图片编码Base64便于 WebSocket 传输)
- 后台保活:使用 `FOREGROUND_SERVICE` 权限
**后端RuoYi**
- WebSocket 服务器Spring WebSocket
- 控制接口RESTful API
- 画面转发WebSocket 消息转发
### 2.3 数据流程
1. **启动监控流程**
```
后台点击学生 → 调用控制接口 → 发送 WebSocket 指令 → 学生端接收指令 → 开始屏幕捕获 → 传输画面
```
2. **停止监控流程**
```
后台点击停止 → 调用控制接口 → 发送 WebSocket 指令 → 学生端接收指令 → 停止屏幕捕获
```
3. **画面传输流程**
```
学生端捕获屏幕 → Base64 编码 → WebSocket 发送 → 后台接收 → 解码显示
```
## 三、实现细节
### 3.1 学生端实现UniApp
#### 3.1.1 屏幕流捕获工具类 (`screenStream.js`)
**核心功能:**
- WebSocket 连接管理
- 接收后台指令(启动/停止)
- 屏幕捕获和传输
- 自动重连机制
- 后台保活
**关键代码:**
```javascript
// 连接 WebSocket
connect() {
const wsUrl = this.getWebSocketUrl()
this.ws = uni.connectSocket({
url: wsUrl,
header: {
'Authorization': `Bearer ${uni.getStorageSync('token') || ''}`
}
})
}
// 开始捕获
startCapture(interval = 500) {
this.isCapturing = true
this.captureTimer = setInterval(() => {
this.captureAndSend()
}, interval)
}
// 捕获并发送
async captureAndSend() {
const screenshotData = await this.captureScreen()
this.sendMessage({
type: 'screen_frame',
userId: this.userId,
data: screenshotData,
timestamp: Date.now()
})
}
```
#### 3.1.2 权限配置
`manifest.json` 中添加必要权限:
```json
{
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>"
]
}
}
```
#### 3.1.3 应用初始化
`App.vue` 中初始化屏幕流服务:
```javascript
onShow() {
const token = uni.getStorageSync('token')
if (token) {
this.initScreenStream()
}
}
```
### 3.2 后端实现RuoYi
#### 3.2.1 WebSocket 处理器 (`ScreenStreamWebSocketHandler.java`)
**核心功能:**
- 管理学生端连接
- 管理监控端连接
- 转发屏幕帧数据
- 发送控制指令
**关键代码:**
```java
@ServerEndpoint("/ws/screenStream/{userId}")
@Component
public class ScreenStreamWebSocketHandler {
// 学生端连接映射
private static ConcurrentHashMap<String, ScreenStreamWebSocketHandler> studentConnections;
// 监控端连接映射
private static ConcurrentHashMap<String, ScreenStreamWebSocketHandler> monitorConnections;
// 发送指令给学生端
public static void sendCommandToStudent(String studentUserId, String command, Integer interval) {
ScreenStreamWebSocketHandler handler = studentConnections.get(studentUserId);
if (handler != null) {
handler.sendMessage(JSON.toJSONString(cmd));
}
}
}
```
#### 3.2.2 控制接口 (`ScreenStreamController.java`)
**接口列表:**
- `POST /study/screenStream/start` - 启动屏幕流捕获
- `POST /study/screenStream/stop` - 停止屏幕流捕获
- `POST /study/screenStream/checkOnline` - 检查学生是否在线
- `POST /study/screenStream/onlineCount` - 获取在线学生数
#### 3.2.3 安全配置
`SecurityConfig.java` 中添加 WebSocket 路径免认证:
```java
.antMatchers("/ws/**").permitAll()
```
### 3.3 后台管理端实现
#### 3.3.1 屏幕流监控页面 (`screenStream/index.vue`)
**功能特性:**
- 学生列表展示(带在线状态)
- 点击学生开始/停止监控
- 实时显示屏幕画面
- WebSocket 接收画面数据
**关键代码:**
```javascript
// 连接 WebSocket 接收画面
connectWebSocket(studentId) {
const wsUrl = `ws://${host}/ws/screenStream/${studentId}`
this.ws = new WebSocket(wsUrl)
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data)
if (message.type === "screen_frame") {
this.currentScreenFrame = `data:image/jpeg;base64,${message.data}`
}
}
}
// 启动监控
async startMonitor() {
await startScreenStream(this.currentStudent.userId, 500)
this.currentStudent.isMonitoring = true
this.connectWebSocket(this.currentStudent.userId)
}
```
## 四、部署说明
### 4.1 前端部署
1. **配置服务器地址**
- 修改 `frontend-uniapp/src/utils/config.js` 中的 `SERVER_HOST`
- 确保 WebSocket 地址正确
2. **编译打包**
```bash
cd frontend-uniapp
npm run build:app
```
3. **权限说明**
- 安卓 10+ 需要用户手动授予屏幕捕获权限
- 首次启动时会请求相关权限
### 4.2 后端部署
1. **确保 WebSocket 支持**
- 检查 `pom.xml` 中已包含 `spring-boot-starter-websocket` 依赖
2. **配置安全策略**
- WebSocket 路径 `/ws/**` 已配置为免认证
- 实际认证在 WebSocket 处理器中处理
3. **启动服务**
```bash
cd RuoYi-Vue-redis
mvn clean install
java -jar ry-news-admin/target/ry-news-admin.jar
```
## 五、性能优化
### 5.1 传输优化
1. **图片质量调整**
- 默认质量 0.7(可调整)
- 根据网络情况动态调整
2. **捕获频率**
- 默认 500ms约 2 帧/秒)
- 可根据需求调整
3. **数据压缩**
- 使用 JPEG 格式(比 PNG 小)
- Base64 编码传输
### 5.2 资源管理
1. **按需启动**
- 只有后台点击时才启动捕获
- 不监控时完全停止,节省资源
2. **连接管理**
- 自动重连机制
- 连接断开时停止捕获
3. **后台保活**
- 使用前台服务权限
- 确保应用在后台时也能运行
## 六、注意事项
### 6.1 权限问题
1. **屏幕捕获权限**
- 安卓 10+ 需要 `MediaProjection` 权限
- 需要用户手动授权
2. **后台运行权限**
- 需要 `FOREGROUND_SERVICE` 权限
-`manifest.json` 中已配置
### 6.2 兼容性
1. **安卓版本**
- 最低支持Android 5.0 (API 21)
- 推荐Android 10+ (API 29+)
2. **网络要求**
- 必须在同一局域网内
- 确保防火墙允许 WebSocket 连接
### 6.3 安全性
1. **认证机制**
- WebSocket 连接时携带 Token
- 后端验证用户身份
2. **数据加密**
- 建议在生产环境使用 WSSWebSocket Secure
- 局域网环境可考虑使用 HTTP
## 七、测试建议
### 7.1 功能测试
1. **连接测试**
- 测试学生端 WebSocket 连接
- 测试后台管理端连接
2. **指令测试**
- 测试启动/停止指令
- 测试指令响应时间
3. **画面传输测试**
- 测试画面清晰度
- 测试传输延迟
- 测试多学生同时监控
### 7.2 性能测试
1. **资源占用**
- 监控 CPU 和内存占用
- 监控网络带宽占用
2. **稳定性测试**
- 长时间运行测试
- 网络中断恢复测试
## 八、后续优化方向
1. **WebRTC 方案**
- 如果 WebSocket 方案性能不足,可考虑 WebRTC
- 需要开发原生插件支持
2. **流媒体服务器**
- 使用 RTMP/RTSP 协议
- 需要部署流媒体服务器(如 SRS
3. **画面录制**
- 支持录制监控画面
- 保存为视频文件
4. **多画面监控**
- 支持同时监控多个学生
- 画面分屏显示
## 九、常见问题
### Q1: 屏幕捕获失败?
**A:** 检查是否授予屏幕捕获权限,安卓 10+ 需要用户手动授权。
### Q2: WebSocket 连接失败?
**A:** 检查网络连接、防火墙设置,确保在同一局域网内。
### Q3: 画面延迟高?
**A:** 可以调整捕获间隔(默认 500ms或降低图片质量。
### Q4: 应用后台时停止捕获?
**A:** 检查是否授予后台运行权限,确保 `FOREGROUND_SERVICE` 权限已配置。
### Q5: 多学生同时监控性能问题?
**A:** 可以限制同时监控的学生数量,或使用流媒体服务器方案。