
简介本资源是一套完整的Android手机远程监控应用源码面向具备Java/Kotlin基础的Android开发者尤其适合学习物联网终端开发、实时音视频传输与设备权限管理的中高级学习者。项目覆盖摄像头采集Camera2 API、网络通信HTTP/HTTPS或WebSocket、图像流编码可能集成FFmpeg、后台多线程处理及服务端交互等核心场景可快速搭建具备实时预览、远程控制与异常通知能力的监控原型。压缩包共66个文件含40个class字节码、14个java源文件承载核心逻辑如CamMonitor等、5个xml布局与配置文件以及apk安装包、dex可执行文件等整体仅133KB轻量易读目录结构聚焦于监控主模块便于逐层理解权限申请、Camera初始化、数据上传等关键流程。目前已有3442人学习下载是深入掌握Android多媒体网络协同开发的典型实践案例。1. 这不是“远程控制手机”而是构建一个可落地的 Android 端视频采集与推流节点很多人看到“Android 手机远程监控”第一反应是“能偷偷看别人手机”——这既误解了技术本质也混淆了合法边界。真实场景中它更常用于家庭老人看护、小型商铺无人值守、工业设备状态巡检等授权前提下的单向视频采集与回传。这个Android手机远程监控源码.zip提供的是一套完整可编译的 Android 工程核心价值不在于“隐蔽性”而在于如何在资源受限的移动设备上稳定完成摄像头采集 → 编码压缩 → 网络推流 → 服务端接收这一闭环。它跳过了 WebRTC 的复杂信令协商也不依赖云厂商 SDK而是基于 Camera2 MediaCodec RTMP 协议栈实现轻量级自主可控方案。适合已有 Java/Kotlin 基础、熟悉 Android 权限模型、但尚未实操过音视频管线的中级开发者对嵌入式或 IoT 方向工程师而言其 SurfaceTexture EGL 渲染路径、硬编码参数调优逻辑比纯 UI 应用更具参考价值。2. Camera2 MediaCodec 硬编码为什么不用 OpenCV 或 FFmpeg2.1 选型依据功耗、延迟与系统兼容性的三角平衡在 Android 8.0 设备上Camera2 API 是官方推荐的摄像头控制接口相比废弃的 Camera API它提供更精细的帧率控制、手动曝光/对焦调节、以及关键的Surface 输出支持——这是将原始 YUV 数据直接送入 MediaCodec 编码器的前提。而 MediaCodec 是 Android 原生硬编码框架调用高通/联发科/三星芯片内置的 DSP 模块相比 FFmpeg 软编码CPU 占用常超 70%或 OpenCV 的 Mat 处理链路功耗降低 40% 以上首帧延迟压至 300ms 内。本源码未集成 FFmpeg正是规避了 ndk 编译、so 文件体积膨胀15MB、以及 ARMv7/ARM64 架构适配等运维成本。实际测试中小米 Redmi Note 12骁龙 4 Gen 1开启 720p15fps 编码时CPU 温度稳定在 42℃电池续航下降速率与普通视频播放相当。2.2 Camera2 初始化关键步骤与权限校验// MainActivity.kt 中初始化逻辑节选 private fun initCamera() { val manager getSystemService(Context.CAMERA_SERVICE) as CameraManager try { // 获取默认后置摄像头 ID val cameraId manager.cameraIdList.firstOrNull { manager.getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) CameraCharacteristics.LENS_FACING_BACK } ?: throw RuntimeException(No back camera found) // 检查是否已获取 CAMERA 和 RECORD_AUDIO 权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ! PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO), REQUEST_CAMERA_PERMISSION) return } // 开启相机预览输出到 TextureView 的 Surface manager.openCamera(cameraId, object : CameraDevice.StateCallback() { override fun onOpened(camera: CameraDevice) { cameraDevice camera createCameraPreviewSession() } override fun onError(camera: CameraDevice, error: Int) { Log.e(CamMonitor, Camera open failed: $error) } }, null) } catch (e: CameraAccessException) { Log.e(CamMonitor, Camera access exception, e) } }注意RECORD_AUDIO权限不可省略——即使只传视频MediaCodec 编码 H.264 时若启用 B-Frames本源码默认开启需同步音频时间戳以维持 PTS/DTS 对齐否则服务端解码会出现花屏。Android 12 设备还需在AndroidManifest.xml中声明uses-permission android:nameandroid.permission.BODY_SENSORS /部分厂商摄像头驱动依赖此权限获取传感器数据。2.3 MediaCodec 编码器配置参数详解源码中H264Encoder.kt定义了硬编码器核心参数以下为关键字段说明参数取值示例作用说明KEY_BIT_RATE12000001.2Mbps直接决定码率上限过高导致网络拥塞过低引发马赛克。建议按目标分辨率设置480p→800kbps720p→1200kbps1080p→2500kbpsKEY_FRAME_RATE15实际帧率受 Camera2CONTROL_AE_TARGET_FPS_RANGE限制此处设为期望值编码器会动态插帧或丢帧KEY_I_FRAME_INTERVAL2关键帧间隔秒值越小 GOP 越短首屏加载快但码率升高。RTMP 场景建议 1~3 秒KEY_COLOR_FORMATMediaCodecInfo.CodecCapabilities.COLOR_FormatSurface强制使用 Surface 输入避免 ByteBuffer 拷贝开销KEY_PROFILEMediaCodecInfo.CodecProfileLevel.AVCProfileHigh高阶 Profile 支持 B-Frames 和 CABAC压缩率提升 20%但部分低端芯片不支持// 创建编码器实例Java 版Kotlin 同理 MediaFormat format MediaFormat.createVideoFormat(video/avc, width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate); format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); format.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel4); encoder MediaCodec.createEncoderByType(video/avc); encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);提示AVCLevel4对应 720p30fps若设备报CodecException可降级为AVCLevel32480p30fpsCOLOR_FormatSurface必须与 Camera2 的SurfaceTexture绑定否则dequeueInputBuffer返回 -1。3. RTMP 推流实现从 SrsFlvMuxer 到自定义协议栈3.1 为何选择 SrsFlvMuxer 而非 librtmp本源码采用 SrsFlvMuxer 的 Android 封装版srs-flv-android而非更常见的librtmp。根本原因在于FLV 封装比 RTMP 协议层更易调试且容错性强。当网络抖动导致 TCP 包乱序时librtmp常因send()阻塞直接崩溃而 SrsFlvMuxer 将音视频帧先写入内存缓冲区默认 2MB再通过 OkHttp 分块上传配合重试机制最大 3 次和断线自动重连间隔 1.5s。实测在地铁弱网环境下30 秒内断连恢复成功率 92%远高于原生 librtmp 的 63%。3.2 推流地址构造与鉴权参数注入源码中RtmpPublisher.kt的startPublish()方法要求传入完整 URL格式为rtmp://your-server-ip/live/{stream_key}?token{jwt_token}device_id{imei}其中stream_key为服务端约定的流名如cam_001不可含特殊字符token为 JWT 签名服务端验证exp过期时间、iat签发时间及device_id白名单device_id通过TelephonyManager.getImei()获取Android 10 需申请READ_PHONE_STATE权限或改用Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)。fun startPublish(rtmpUrl: String) { // 解析 URL 中的 query 参数 val uri Uri.parse(rtmpUrl) val token uri.getQueryParameter(token) ?: val deviceId uri.getQueryParameter(device_id) ?: // 构造带签名的推流地址服务端需校验 val signedUrl $rtmpUrlts${System.currentTimeMillis()}sig${generateSignature(token, deviceId)} muxer SrsFlvMuxer() muxer?.setRtmpUrl(signedUrl) muxer?.start() }注意generateSignature()函数使用 HMAC-SHA256 算法密钥由服务端统一下发禁止硬编码在客户端。Android 9 设备需在AndroidManifest.xml中添加android:usesCleartextTraffictrue若服务端未部署 HTTPS否则 OkHttp 默认拒绝 HTTP 请求。3.3 音视频时间戳同步策略RTMP 要求音视频 PTSPresentation Time Stamp严格单调递增且差值稳定。源码采用双时钟源校准法视频 PTS 以 Camera2CaptureResult.SENSOR_TIMESTAMP为基准减去预览启动时刻得到相对时间音频 PTS 以AudioRecord.getTimestamp()为基准通过AudioTimestamp.nanoTime与视频时间轴对齐若音视频差值 200ms主动丢弃音频帧避免缓冲区溢出。// AudioEncoder.java 中的时间戳修正逻辑 long audioPts (audioTimestamp.nanoTime - startTimeNs) / 1000; // 转为微秒 long videoPts (videoTimestamp - startVideoTime) / 1000; long diff Math.abs(audioPts - videoPts); if (diff 200000) { // 200ms // 丢弃该音频帧不送入 muxer return; } muxer.writeSampleData(audioTrackIndex, encodedBuffer, new MediaCodec.BufferInfo().apply { presentationTimeUs audioPts size encodedSize flags MediaCodec.BUFFER_FLAG_KEY_FRAME });4. 服务端接收与验证用 FFmpeg 搭建最小化验证环境4.1 本地快速验证无需部署 Nginx-RTMP开发者无需立即搭建专业流媒体服务器可用 FFmpeg 直接拉取并保存为 MP4 文件验证推流是否成功# 在 Mac/Linux 终端执行Windows 请下载 FFmpeg for Windows ffmpeg -i rtmp://localhost/live/cam_001 -c copy -f mp4 -y /tmp/test.mp4若命令卡在Input #0无响应说明手机端未启动推流检查 App 是否前台运行、权限是否授予防火墙拦截 RTMP 端口默认 1935需开放URL 中stream_key与服务端配置不一致。提示FFmpeg 日志中出现Invalid data found when processing input表示编码参数异常如COLOR_FormatSurface未正确绑定需回查 MediaCodec 配置。4.2 使用 OBS Studio 模拟服务端接收OBS 是最便捷的可视化验证工具安装 OBS Studio官网下载添加「媒体源」→ 选择「视频捕获设备」→ 设备选「SRS Live Stream」在「设置」→「推流」中URL 填rtmp://your-server-ip/live流密钥填cam_001启动 OBS 推流后在手机端启动 CamMonitorOBS 预览窗口即显示实时画面。此方式绕过服务端开发直接验证 Android 端推流质量。若 OBS 显示「连接失败」90% 概率为手机端网络未通如路由器禁用了 UPnP或手机连的是企业 Wi-Fi 限制了 RTMP 协议。4.3 关键日志定位表快速判断故障环节现象日志关键词Logcat 过滤可能原因解决方案启动后黑屏CameraDevice: Error 0Camera2 初始化失败检查AndroidManifest.xml是否声明uses-feature android:nameandroid.hardware.camera /推流无数据SrsFlvMuxer: send packet timeout网络不通或服务端未监听telnet your-server-ip 1935测试端口连通性画面卡顿MediaCodec: dequeueInputBuffer timeout编码器输入队列满降低分辨率或帧率检查MediaFormat.KEY_BIT_RATE是否过低音画不同步AudioEncoder: PTS drift detected时间戳校准失效确认AudioRecord采样率与MediaFormat.KEY_SAMPLE_RATE一致默认 44100Hz安装失败INSTALL_FAILED_CONFLICTING_PROVIDER与其他 App 的 FileProvider 冲突修改AndroidManifest.xml中android:authorities为唯一值如com.yourpackage.fileprovider5. 权限适配与 Android 12 行为变更应对技巧5.1 动态权限请求的兼容性补丁Android 11API 30起READ_EXTERNAL_STORAGE权限不再影响应用自身目录访问但本源码中日志文件写入getExternalFilesDir()仍需声明。Android 12API 31新增近似位置权限ACCESS_COARSE_LOCATION要求——即使不使用 GPS部分厂商摄像头驱动如 vivo、OPPO读取传感器数据时会触发此权限检查。解决方案是在AndroidManifest.xml中添加uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION /并在运行时请求仅针对 Android 12if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), REQUEST_LOCATION_PERMISSION) } }5.2 后台服务保活JobIntentService 替代 ForegroundServiceAndroid 9 对后台 Service 限制严格startForegroundService()必须在 5 秒内调用startForeground()否则抛出ForegroundServiceDidNotStartInTimeException。本源码采用JobIntentService替代传统 Service利用 JobScheduler 在系统空闲时执行推流任务既满足后台持续运行需求又规避 ANR 风险// 在 Application.onCreate() 中注册 val service ComponentName(this, RtmpJobService::class.java) JobIntentService.enqueueWork(this, service, 1001, intent)RtmpJobService继承JobIntentService其onHandleWork()方法中执行编码与推流逻辑系统保证在设备充电、空闲、网络可用时触发。5.3 调试模式下关闭硬件加速以定位渲染问题当遇到SurfaceTexture黑屏但日志无报错时可临时禁用硬件加速强制走软件渲染!-- AndroidManifest.xml 中 application 标签添加 -- android:hardwareAcceleratedfalse若此时画面正常则确认为 GPU 驱动兼容性问题常见于华为 EMUI 12、小米 HyperOS需在TextureView初始化时指定setOpaque(false)并禁用setZOrderOnTop(true)。本文还有配套的精品资源点击获取