
1. Android屏幕录制功能实现方案解析在移动应用开发中屏幕录制功能正变得越来越重要。无论是游戏直播、教学演示还是用户行为分析都需要可靠的屏幕录制能力。Android平台从5.0API 21开始提供了完整的屏幕录制API支持通过MediaProjection和MediaRecorder这两个核心类开发者可以用不到200行代码实现高质量的屏幕录制功能。我曾在多个商业项目中实现过屏幕录制模块发现这套API虽然强大但存在不少隐藏的坑。本文将分享如何用最精简的代码结构仅两个类实现稳定可靠的屏幕录制功能同时会详细解释每个参数设置的原理和实际项目中的优化经验。2. 核心组件与工作原理2.1 MediaProjection机制解析MediaProjection是Android屏幕录制的核心组件它本质上是一个令牌(token)代表用户授权应用捕获屏幕内容的权限。当应用请求屏幕录制时系统会弹出权限确认对话框用户同意后才会返回有效的MediaProjection实例。这个设计有三大优势明确的用户授权流程符合隐私保护要求令牌式管理避免后台偷偷录制支持随时撤销权限通过通知栏实际开发中需要注意MediaProjection实例必须在用户交互的上下文中获取如Activity获取的token是一次性使用的每次录制都需要重新申请应用退到后台时录制会自动停止Android 102.2 VirtualDisplay的作用VirtualDisplay是将屏幕内容映射到Surface的虚拟显示器。它负责指定录制的分辨率建议使用屏幕原生分辨率设置DPI保持与设备一致连接SurfaceMediaRecorder提供的关键参数设置经验// 最佳实践参数设置 virtualDisplay mediaProjection.createVirtualDisplay( ScreenRecorder, // 显示名称 width, // 横向分辨率 height, // 纵向分辨率 displayMetrics.densityDpi, // DPI DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, // 自动镜像 surface, // MediaRecorder提供的Surface null, // 回调 null // Handler );2.3 MediaRecorder配置要点MediaRecorder负责将Surface接收到的帧数据编码为视频文件。推荐配置流程设置视频源CAMERA或SURFACE配置输出格式MP4最通用设置视频编码器H.264兼容性最好调整视频参数关键比特率1080p建议8-12Mbps帧率25/30fps最自然I帧间隔1-2秒最佳设置输出文件路径实测参数示例mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mediaRecorder.setVideoEncodingBitRate(8 * 1000 * 1000); // 8Mbps mediaRecorder.setVideoFrameRate(30); mediaRecorder.setVideoSize(width, height); mediaRecorder.setOutputFile(outputFile.getAbsolutePath());3. 完整实现方案3.1 权限申请与初始化首先需要在AndroidManifest.xml中添加必要权限uses-permission android:nameandroid.permission.RECORD_AUDIO / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE /然后创建MediaProjectionManagermediaProjectionManager (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);启动权限申请startActivityForResult( mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_CAPTURE );在onActivityResult中处理授权结果Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode REQUEST_CODE_SCREEN_CAPTURE) { if (resultCode RESULT_OK) { mediaProjection mediaProjectionManager.getMediaProjection(resultCode, data); startRecording(); } } }3.2 录制控制类实现核心录制控制器代码结构public class ScreenRecorder { private MediaProjection mediaProjection; private MediaRecorder mediaRecorder; private VirtualDisplay virtualDisplay; public void start(MediaProjection projection, File outputFile) { this.mediaProjection projection; // 1. 初始化MediaRecorder initRecorder(outputFile); // 2. 创建VirtualDisplay createVirtualDisplay(); // 3. 开始录制 mediaRecorder.start(); } public void stop() { // 逆序释放资源 if (mediaRecorder ! null) { try { mediaRecorder.stop(); mediaRecorder.reset(); } catch (IllegalStateException e) { // 处理异常情况 } } if (virtualDisplay ! null) { virtualDisplay.release(); } if (mediaProjection ! null) { mediaProjection.stop(); } } // 其他辅助方法... }3.3 分辨率适配方案不同设备屏幕比例各异最佳实践是获取实际屏幕分辨率保持原始宽高比根据设备性能调整代码实现DisplayMetrics metrics getResources().getDisplayMetrics(); int width metrics.widthPixels; int height metrics.heightPixels; // 4K设备需要降分辨率处理 if (width 1920 || height 1080) { float ratio (float) height / width; width 1920; height (int) (1920 * ratio); }4. 实战问题与解决方案4.1 常见崩溃场景处理权限丢失问题场景用户从通知栏撤销权限处理监听MediaProjection回调mediaProjection.registerCallback(new MediaProjection.Callback() { Override public void onStop() { // 立即停止录制并清理资源 stopRecording(); } }, null);文件写入失败检查存储权限使用getExternalFilesDir()避免MANAGE_EXTERNAL_STORAGE权限创建文件前检查可用空间编码器不支持备用编码器方案// 检测H.264可用性 if (MediaRecorder.getVideoEncoderCapabilities( MediaRecorder.VideoEncoder.H264).length 0) { // 使用H264 } else { // 回退到H263或MPEG4 }4.2 性能优化技巧SurfaceTexture缓冲优化// 在创建VirtualDisplay前设置 surfaceTexture.setDefaultBufferSize(width, height);音频录制优化单独音频线程使用AudioRecord代替MediaRecorder内置录音动态调整采样率44.1kHz → 22.05kHz内存管理// 在Application中设置 android:largeHeaptrue4.3 特殊场景处理刘海屏适配if (Build.VERSION.SDK_INT Build.VERSION_CODES.P) { WindowManager.LayoutParams params getWindow().getAttributes(); params.layoutInDisplayCutoutMode WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; getWindow().setAttributes(params); }多显示器支持DisplayManager dm (DisplayManager) getSystemService(DISPLAY_SERVICE); Display[] displays dm.getDisplays(); // 选择要录制的display低电量和发热控制PowerManager powerManager (PowerManager) getSystemService(POWER_SERVICE); if (!powerManager.isPowerSaveMode()) { // 正常录制 } else { // 降低分辨率和帧率 }5. 高级功能扩展5.1 实时预览实现通过TextureView实现录制预览// 在布局中添加TextureView TextureView android:idid/preview_view android:layout_widthmatch_parent android:layout_heightmatch_parent / // 代码中设置SurfaceTexture监听 textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // 创建用于预览的Surface previewSurface new Surface(surface); // 将此Surface也添加到VirtualDisplay } // 其他回调方法... });5.2 动态分辨率切换录制过程中动态调整分辨率// 先停止当前VirtualDisplay virtualDisplay.release(); // 创建新配置的VirtualDisplay virtualDisplay mediaProjection.createVirtualDisplay( ScreenRecorder, newWidth, newHeight, newDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null ); // 需要同时调整MediaRecorder配置 mediaRecorder.setVideoSize(newWidth, newHeight);5.3 视频后处理方案视频压缩// 使用MediaCodec进行离线压缩 MediaFormat format MediaFormat.createVideoFormat( video/avc, width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, newBitrate); // 其他参数设置...添加水印使用OpenGL在录制时实时叠加或使用FFmpeg后期处理关键帧提取MediaExtractor extractor new MediaExtractor(); extractor.setDataSource(videoPath); // 解析视频帧数据...6. 测试与调试技巧6.1 ADB调试命令常用ADB命令# 强制授予权限开发时使用 adb shell pm grant package_name android.permission.RECORD_AUDIO adb shell pm grant package_name android.permission.WRITE_EXTERNAL_STORAGE # 查看MediaCodec信息 adb shell dumpsys media.codec # 监控CPU/内存使用 adb shell top -n 1 | grep package_name6.2 性能分析工具Android Profiler监控CPU使用率重点关注MediaCodec线程内存泄漏检查特别是Surface相关对象Systracepython systrace.py --time10 -o trace.html sched gfx viewGPU渲染分析开发者选项中的GPU渲染模式分析6.3 兼容性测试方案必备测试场景不同Android版本重点测试8.0、10.0、12.0各种屏幕比例16:9、18:9、19.5:9等低端设备内存2GB的机型长时间录制1小时以上稳定性测试7. 替代方案对比7.1 第三方库方案MediaProjection FFmpeg优点更灵活的编码控制缺点集成复杂度高OpenGL屏幕捕获优点高性能支持特效缺点实现难度大Root方案优点无需用户确认缺点需要root权限违反Google政策7.2 方案选型建议根据项目需求选择普通应用本文的MediaProjection方案专业录屏MediaProjection MediaCodec游戏直播OpenGL方案我在电商App中采用基础方案而在游戏直播App中使用OpenGL方案两者在性能和效果上有明显差异。对于90%的应用场景标准的双类实现已经足够。