Android屏幕录制技术:MediaProjection与MediaRecorder实战
1. Android录屏技术背景与核心组件解析在移动应用开发中屏幕录制功能的需求日益增长无论是游戏直播、操作演示还是远程协助场景都离不开这项基础能力。Android平台从5.0Lollipop开始通过MediaProjection API提供了系统级的录屏支持配合MediaRecorder实现了高效的屏幕捕获与编码流水线。MediaProjection作为录屏功能的核心本质上是一个令牌(token)系统。当用户授权应用进行屏幕捕获后系统会返回一个MediaProjection实例这个实例包含了进行屏幕捕获所需的所有权限和上下文信息。其工作流程可以类比为电影院放映机——MediaProjection是放映机本身而VirtualDisplay则是投射到墙上的光影。MediaRecorder则是Android多媒体框架中的瑞士军刀负责将原始视频数据编码压缩为可存储的格式。它支持H.264、H.265等主流编码格式能够直接接收来自VirtualDisplay的表面(Surface)数据流。这种设计使得屏幕内容可以不经过应用层直接进入编码管道大幅提升了录制效率。2. 实现方案设计与权限配置2.1 基础工程配置在AndroidManifest.xml中需要声明以下关键权限uses-permission android:nameandroid.permission.FOREGROUND_SERVICE/ uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE/ uses-permission android:nameandroid.permission.RECORD_AUDIO/ !-- 如需录制音频 --对于Android 10设备必须在manifest中添加屏幕捕获服务声明service android:name.ScreenRecordService android:foregroundServiceTypemediaProjection/2.2 权限获取流程屏幕录制需要用户显式授权这个流程必须通过Activity触发private fun requestScreenCapture() { val mediaProjectionManager getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager startActivityForResult( mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_CAPTURE ) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode REQUEST_CODE_SCREEN_CAPTURE resultCode RESULT_OK) { data?.let { startRecordingService(it) } } }重要提示用户授权是一次性的每次应用重启后都需要重新获取。实际开发中应该缓存授权结果避免频繁弹窗影响用户体验。3. 核心实现代码解析3.1 MediaRecorder配置创建适配当前设备的最佳录制参数private fun setupMediaRecorder(): MediaRecorder { return MediaRecorder().apply { setVideoSource(MediaRecorder.VideoSource.SURFACE) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) // 自适应视频参数配置 val displayMetrics resources.displayMetrics val bitrate displayMetrics.widthPixels * displayMetrics.heightPixels * 5 // 基础比特率计算 setVideoEncoder(MediaRecorder.VideoEncoder.H264) setVideoEncodingProfileLevel( MediaCodecInfo.CodecProfileLevel.AVCProfileHigh, MediaCodecInfo.CodecProfileLevel.AVCLevel42 ) setVideoSize(displayMetrics.widthPixels, displayMetrics.heightPixels) setVideoFrameRate(30) setVideoEncodingBitRate(bitrate) // 输出文件配置 val outputDir getExternalFilesDir(Environment.DIRECTORY_MOVIES) ?: filesDir setOutputFile(File(outputDir, record_${System.currentTimeMillis()}.mp4).absolutePath) } }3.2 VirtualDisplay创建将屏幕内容投射到MediaRecorder的Surfaceprivate fun createVirtualDisplay( mediaProjection: MediaProjection, recorder: MediaRecorder ): VirtualDisplay { val metrics resources.displayMetrics return mediaProjection.createVirtualDisplay( ScreenCapture, metrics.widthPixels, metrics.heightPixels, metrics.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, recorder.surface, null, null ) }3.3 服务端完整实现Foreground Service的实现要点class ScreenRecordService : Service() { private lateinit var mediaProjection: MediaProjection private lateinit var mediaRecorder: MediaRecorder private lateinit var virtualDisplay: VirtualDisplay override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { startForeground( NOTIFICATION_ID, createNotification().build() ) mediaProjection (getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager) .getMediaProjection(Activity.RESULT_OK, intent!!) mediaRecorder setupMediaRecorder().apply { prepare() } virtualDisplay createVirtualDisplay(mediaProjection, mediaRecorder) mediaRecorder.start() return START_NOT_STICKY } private fun stopRecording() { try { mediaRecorder.stop() } catch (e: IllegalStateException) { Log.e(TAG, Stop failed: ${e.message}) } finally { cleanupResources() } } private fun cleanupResources() { virtualDisplay.release() mediaProjection.stop() mediaRecorder.release() stopForeground(true) stopSelf() } }4. 高级优化技巧4.1 性能调优参数根据不同设备配置动态调整参数fun getOptimalFrameRate(caps: MediaCodecInfo.CodecCapabilities): Int { return caps.videoCapabilities.supportedFrameRates .filter { it 60 } // 限制最大帧率 .maxOrNull() ?: 30 } fun getOptimalBitrate(width: Int, height: Int): Int { return when { width * height 1920 * 1080 - 8000000 // 1080p width * height 1280 * 720 - 4000000 // 720p else - 2000000 // 低分辨率 } }4.2 音频同步录制实现音视频同步录制private fun setupMediaRecorderWithAudio(): MediaRecorder { return setupMediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setAudioChannels(2) setAudioSamplingRate(44100) setAudioEncodingBitRate(128000) } }4.3 动态分辨率适配根据设备性能自动降级fun getAdjustedResolution(originalWidth: Int, originalHeight: Int): PairInt, Int { return when { Runtime.getRuntime().availableProcessors() 4 - originalWidth / 2 to originalHeight / 2 getTotalMemory() 2 * 1024 - (originalWidth * 0.75).toInt() to (originalHeight * 0.75).toInt() else - originalWidth to originalHeight } }5. 常见问题排查指南5.1 权限问题排查表现象可能原因解决方案立即崩溃未声明FOREGROUND_SERVICE权限添加权限声明黑屏录制未正确获取MediaProjection检查onActivityResult处理文件为空存储权限未授予动态请求WRITE_EXTERNAL_STORAGE5.2 编码问题处理视频花屏问题检查H264 profile/level配置是否超出设备支持范围尝试降低帧率或分辨率添加关键帧间隔配置mediaRecorder.setVideoEncodingIFrameInterval(2) // 每2秒一个关键帧音频不同步问题确保音频采样率设置为44100Hz检查时间戳处理mediaRecorder.setCaptureRate(30.0) // 明确设置捕获速率5.3 设备兼容性问题特殊机型适配fun checkDeviceSpecificIssues() { when (Build.MANUFACTURER.lowercase()) { xiaomi - { // 小米设备需要额外设置 mediaRecorder.setVideoEncodingProfileLevel( MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline, MediaCodecInfo.CodecProfileLevel.AVCLevel3 ) } huawei - { // 华为设备需要限制比特率 mediaRecorder.setVideoEncodingBitRate(bitrate / 2) } } }6. 前沿技术扩展6.1 低延迟直播推流通过MediaCodec直接获取原始数据mediaProjection.createVirtualDisplay( ScreenCapture, width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, surface, // 自定义Surface连接到MediaCodec null, null )6.2 动态内容分析实时处理屏幕内容val imageReader ImageReader.newInstance( width, height, PixelFormat.RGBA_8888, 2 ).apply { setOnImageAvailableListener({ reader - val image reader.acquireLatestImage() // 处理图像数据 image.close() }, handler) } mediaProjection.createVirtualDisplay( Analysis, width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, imageReader.surface, null, null )6.3 多源合成录制结合摄像头画面val textureView TextureView(context).apply { setSurfaceTextureListener(object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(st: SurfaceTexture, w: Int, h: Int) { val surface Surface(st) // 将摄像头画面绘制到此surface } }) } // 在MediaRecorder配置中添加摄像头源 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE) mediaRecorder.setInputSurface(textureView.surfaceTexture)在实际项目中我发现正确处理MediaProjection的生命周期至关重要。特别是在Android 12及以上版本中当用户切换应用或锁屏时系统会主动停止MediaProjection此时需要妥善处理中断事件并给用户适当的反馈。一个实用的技巧是在注册MediaProjection.Callback时保存关键状态以便在意外中断后能够恢复录制。

相关新闻

micro-github:3分钟实现GitHub登录集成的终极微服务方案

micro-github:3分钟实现GitHub登录集成的终极微服务方案

micro-github:3分钟实现GitHub登录集成的终极微服务方案 【免费下载链接】micro-github A tiny microservice that makes adding authentication with GitHub to your application easy. 项目地址: https://gitcode.com/gh_mirrors/mi/micro-github micro-gi…

2026/7/18 9:11:28阅读更多 →
Vibram与Agility Robotics合作:为双足机器人打造智能鞋底,重塑足地交互

Vibram与Agility Robotics合作:为双足机器人打造智能鞋底,重塑足地交互

1. 项目概述:当顶级鞋底科技遇见双足机器人如果你关注过户外徒步或者越野跑,大概率听说过“Vibram”这个牌子——那个黄色八角形的Logo,几乎就是高性能橡胶鞋底的代名词。从登山靴到城市通勤鞋,Vibram的黄金大底以其卓越的抓地力、…

2026/7/18 9:11:28阅读更多 →
e2core多语言支持:JavaScript、TypeScript、Go、Rust插件开发对比

e2core多语言支持:JavaScript、TypeScript、Go、Rust插件开发对比

e2core多语言支持:JavaScript、TypeScript、Go、Rust插件开发对比 【免费下载链接】e2core Server for sandboxed third-party plugins, powered by WebAssembly 项目地址: https://gitcode.com/gh_mirrors/e2/e2core e2core(Suborbital E2 Core&…

2026/7/18 9:11:28阅读更多 →
TI 14xx MCU AWR模块核心寄存器实战解析:从时钟监控到安全启动

TI 14xx MCU AWR模块核心寄存器实战解析:从时钟监控到安全启动

1. 项目概述与核心价值在嵌入式系统开发,尤其是汽车电子和工业控制这类对可靠性要求极高的领域,MCU的稳定运行绝非偶然,而是由一系列底层硬件机制精心保障的结果。其中,电源、复位和时钟管理(通常简称为PRCM或AWR模块&…

2026/7/18 10:17:03阅读更多 →
venv-selector.nvim缓存机制详解:提升Python环境切换速度的终极指南

venv-selector.nvim缓存机制详解:提升Python环境切换速度的终极指南

venv-selector.nvim缓存机制详解:提升Python环境切换速度的终极指南 【免费下载链接】venv-selector.nvim Allows selection of python virtual environment from within neovim 项目地址: https://gitcode.com/gh_mirrors/ve/venv-selector.nvim venv-selec…

2026/7/18 10:17:03阅读更多 →
CANN/asc-devkit Inputs方法API文档

CANN/asc-devkit Inputs方法API文档

Inputs 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcode.com/can…

2026/7/18 10:17:03阅读更多 →
amphp/http-client错误处理最佳实践:避免常见的10个陷阱

amphp/http-client错误处理最佳实践:避免常见的10个陷阱

amphp/http-client错误处理最佳实践:避免常见的10个陷阱 【免费下载链接】http-client An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses. 项目地址: https://gitcode.com/gh_mirrors/h…

2026/7/18 10:17:03阅读更多 →
微信小游戏Unity适配终极指南:快速移植你的游戏到微信平台 [特殊字符]

微信小游戏Unity适配终极指南:快速移植你的游戏到微信平台 [特殊字符]

微信小游戏Unity适配终极指南:快速移植你的游戏到微信平台 🚀 【免费下载链接】minigame-unity-webgl-transform 微信小游戏Unity引擎适配器文档。 项目地址: https://gitcode.com/GitHub_Trending/mi/minigame-unity-webgl-transform 微信小游戏…

2026/7/18 10:17:03阅读更多 →
MoneyPrinterTurbo完整指南:3分钟打造AI短视频的终极工具

MoneyPrinterTurbo完整指南:3分钟打造AI短视频的终极工具

MoneyPrinterTurbo完整指南:3分钟打造AI短视频的终极工具 【免费下载链接】MoneyPrinterTurbo 利用AI大模型,一键生成高清短视频 Generate short videos with one click using AI LLM. 项目地址: https://gitcode.com/GitHub_Trending/mo/MoneyPrinter…

2026/7/18 10:12:02阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/17 10:42:55阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/18 8:49:08阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/17 13:22:23阅读更多 →
从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

更多请点击: https://kaifayun.com 第一章:从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则 在Claude驱动的产品需求文档(PRD)生成实践中,原始业务意图往往以自然语言片…

2026/7/18 0:00:14阅读更多 →
Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

更多请点击: https://codechina.net 第一章:Cursor配置生成失效?3大隐藏陷阱4行修复代码,资深工程师连夜整理的紧急补救清单 Cursor 配置生成突然失效,是近期高频报障场景。表面看是 cursor.config.json 未更新或 LSP…

2026/7/18 0:00:14阅读更多 →
某智驾大牛创业

某智驾大牛创业

作者:钟声编辑:Mark出品:红色星际头图:智能驾驶图片据悉,国内某头部智驾公司端到端模型技术大牛Z投身创业,并且已经拿到融资。Z不仅是该头部公司内部最年轻的对标阿里P10级别技术负责⼈,更是业内…

2026/7/18 0:00:14阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/17 22:48:46阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/17 13:22:38阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/17 17:26:50阅读更多 →