本项目是一个基于 WebRTC 和 Android 无障碍服务(AccessibilityService)实现的 Android 设备局域网远程控制和屏幕共享应用。
项目背景与说明: 本项目的业务需求是在一个纯内网(或局域网)环境中,实现一台 Android 设备对另一台同在局域网中的 Android 设备的远程控制。由于纯内网的限制,传统的依赖公网信令服务器和中转服务器的方案不可行。本项目采用 NSD(mDNS)实现局域网设备发现,并通过纯局域网环境下的直连 Socket 交换 WebRTC 信令及控制指令。
⚠️ 注意:当前该项目仅作为功能可行性调研(Proof of Concept)的示例。其重点在于跑通局域网直连、屏幕流传输和手势无障碍控制的流程,因此未进行严谨的架构设计与异常处理,代码质量仅限调研演示级别,不可直接用于生产环境。
- 局域网发现:使用 Android NsdManager(mDNS)在局域网内自动发现并配对设备。
- 屏幕共享:基于 WebRTC 和 Android MediaProjection 实时、低延迟地传输受控端屏幕画面。
- 远程控制:控制端可以实时同步触摸事件(支持多点触控)以及全局操作(返回、主页、最近任务)到受控端。
- 手势模拟:受控端通过 AccessibilityService 接收坐标并执行手势模拟,实现无 Root 控制。
- 受控端 (Slave):
- 开启无障碍服务,准备接收手势和全局按键指令。
- 开启屏幕录制服务(Foreground Service),通过
MediaProjection捕获屏幕画面。 - 注册局域网 NSD 服务,并开启 Socket Server 等待控制端连接。
- 控制端 (Master):
- 搜索局域网中的受控端设备。
- 连接受控端的 Socket 服务。
- 接收 WebRTC 视频流并渲染。
- 捕获用户的屏幕触摸与按键操作,并通过 Socket 发送给受控端。
本项目的数据交互主要分为 发现阶段、信令与控制连接建立、WebRTC 音视频协商、远程控制指令流转四个部分。所有的信令(WebRTC SDP/ICE)和控制指令(触摸、按键)都复用同一个 TCP Socket 连接。
- 受控端:通过
NsdManager注册一个服务类型为_control._tcp.,端口为40000的服务,服务名通常为设备型号。 - 控制端:通过
NsdManager扫描_control._tcp.类型的服务,发现受控端设备后,解析出其局域网 IP 地址和端口号(40000)。
- 受控端:在
ScreenCaptureService中启动ServerSocket监听40000端口。 - 控制端:在
ScreenCaptureActivity中创建Socket连接受控端的 IP 和40000端口。 - 双方建立连接后,获取
DataInputStream和DataOutputStream,开始基于一套自定义的整数类型协议(定义于ext.kt)进行通信。协议类型包括:101 (ACTION_EVENT): 全局按键操作(返回、主屏幕等)102 (TOUCH_EVENT): 屏幕触摸事件201 (ICE_CANDIDATE): WebRTC ICE 候选者202 (SESSION_DESCRIPTION): WebRTC SDP 会话描述203 (CONFIGURATION_CHANGED): 屏幕配置(分辨率/比例)改变
- 受控端初始化:受控端获取
MediaProjection权限后,通过 WebRTC 的ScreenCapturerAndroid采集屏幕画面,作为本地视频轨添加到PeerConnection。 - 创建 Offer:受控端主动创建 WebRTC Offer SDP,并通过 TCP Socket (
SESSION_DESCRIPTION) 发送给控制端。 - 控制端响应 Answer:控制端收到 Offer SDP 后,设置为远端描述,随后创建 Answer SDP,再通过 TCP Socket (
SESSION_DESCRIPTION) 发送回受控端。 - 交换 ICE:双方的
PeerConnection收集到网络候选者(ICE Candidate)时,通过 TCP Socket (ICE_CANDIDATE) 发送给对方,对方接收后加入PeerConnection,完成 P2P 通道的穿透和建立。 - 画面渲染:控制端收到受控端的远端视频轨后,在
SurfaceViewRenderer上实时渲染。
- 触摸事件:
- 控制端用户在
SurfaceViewRenderer上的触摸动作会触发onTouchEvent。 - 控制端提取动作类型(ACTION_DOWN, ACTION_MOVE 等)、坐标(X, Y)、渲染器宽高、压力值等数据,打包成
TOUCH_EVENT通过 TCP Socket 发送。 - 受控端收到
TOUCH_EVENT后,将坐标从“控制端渲染器尺寸”等比例映射还原到“受控端实际屏幕尺寸”。 - 受控端的
Controller将坐标转换为MotionEvent,并传递给GestureControlAccessibilityService,使用GestureDescription构建笔画,在受控端真实屏幕上模拟点击或滑动。
- 控制端用户在
- 全局按键事件:
- 控制端点击“返回”、“主页”或“多任务”按钮时,发送对应的
ACTION_EVENT(如GLOBAL_ACTION_BACK) 给受控端。 - 受控端收到后,调用
GestureControlAccessibilityService的performGlobalAction方法,系统层级执行相应的全局导航操作。
- 控制端点击“返回”、“主页”或“多任务”按钮时,发送对应的
- 屏幕状态同步:
- 受控端屏幕发生旋转等配置改变时,通过
BroadcastReceiver监听,发送CONFIGURATION_CHANGED(包含最新宽高) 给控制端。 - 控制端收到后,动态调整
SurfaceViewRenderer的比例,确保画面不被拉伸变形。
- 受控端屏幕发生旋转等配置改变时,通过
- 界面 UI:Jetpack Compose, Material3
- WebRTC:
io.getstream:stream-webrtc-android - 依赖注入:
io.insert-koin:koin-android - 工具库:
com.blankj:utilcodex