CameraAwesome 2.5.0:解决下拉通知栏/应用后台时录制中断及暂停恢复导致视频损坏的问题
CameraAwesome 2.5.0:解决下拉通知栏/应用后台时录制中断及暂停恢复导致视频损坏的问题
我之前用CameraAwesome做录制应用时,也碰到过几乎一模一样的问题——下拉通知栏就断录,改了暂停恢复后视频又莫名损坏。结合你的代码和日志,我来一步步拆解问题和解决方案:
先揪出你代码里的明显小坑
看你修改后的生命周期代码,AppLifecycleState.paused的case后面没加break!这会导致逻辑穿透:执行完stopRecording()后直接跳到detached的break,和你之前的暂停逻辑冲突,这是视频损坏的潜在诱因之一。
另外,你同步调用了pauseRecording/resumeRecording这些方法,但CameraAwesome的这些操作其实是异步的——如果不等它们把缓冲区的帧写完就切换应用状态,直接会导致帧丢失,最后视频自然缺了一大段内容。
针对“下拉通知栏不中断录制”的正确生命周期处理
首先得搞清楚Android的状态触发逻辑:
- 下拉通知栏/弹出系统弹窗时,触发的是
AppLifecycleState.inactive(应用临时失焦,但还在前台) - 按Home键退到后台时,触发的是
AppLifecycleState.paused(应用完全进入后台,Android 10+会强制限制相机权限)
所以我们要对两个状态做差异化处理:inactive时暂停录制,回到应用后恢复;paused时必须停止录制(否则系统会强制收回相机资源,反而更容易导致视频损坏)。
这里给你修正后的异步版生命周期代码:
@override Future<void> didChangeAppLifecycleState(AppLifecycleState state) async { final mediaCapture = _cameraContext.mediaCaptureController.value; final isRecording = mediaCapture != null && mediaCapture.isRecording; switch (state) { case AppLifecycleState.resumed: // 仅当之前处于暂停状态的录制任务,才执行恢复操作 if (isRecording && mediaCapture.isPaused) { await _cameraContext.state.when( onVideoRecordingMode: (mode) => mode.resumeRecording(mediaCapture), ); } break; case AppLifecycleState.inactive: // 下拉通知栏触发此状态,此时暂停录制(需确保正在录制且未暂停) if (isRecording && !mediaCapture.isPaused) { await _cameraContext.state.when( onVideoRecordingMode: (mode) => mode.pauseRecording(mediaCapture), ); } break; case AppLifecycleState.paused: // 应用完全退到后台,必须停止录制(Android后台相机权限限制) if (isRecording) { await _cameraContext.state.when( onVideoRecordingMode: (mode) => mode.stopRecording(), ); } break; case AppLifecycleState.detached: case AppLifecycleState.hidden: // 应用被销毁/隐藏,强制停止录制 if (isRecording) { await _cameraContext.state.when( onVideoRecordingMode: (mode) => mode.stopRecording(), ); } break; } super.didChangeAppLifecycleState(state); }
这段代码的核心改进:
- 给生命周期方法加上
async/await,确保媒体操作完全执行完再切换状态,避免帧丢失 - 修复了case穿透的问题(每个状态分支都加了break)
- 增加了录制状态校验(
isRecording/isPaused),避免错误调用暂停/恢复方法,比如在未录制时触发恢复操作
解读你看到的错误日志
你日志里的关键信息其实已经点明了问题:
W/GraphicBufferSource: onFrameAvailable: EOS is sent, ignoring frame:编码器收到了「流结束」信号,导致后续的帧直接被丢弃,这就是视频缺30/60秒内容的直接原因I/MPEG4Writer: The mp4 file will not be streamable:这个其实不影响播放,只是说明视频的moov原子在文件末尾,不能流式播放,不是视频损坏的根本原因
出现EOS信号的原因,就是你之前同步调用暂停/恢复,编码器还在处理帧的时候就被强制切换状态,误以为录制已经结束,所以发送了流结束信号。用await等待操作完成就能解决这个问题。
关于“后台持续录制”的替代方案
如果你的需求是应用退到后台后还能继续录制,那仅靠暂停恢复是行不通的——Android 10+明确禁止后台应用访问相机。这时候需要:
- 用Android前台服务承载相机录制逻辑,申请
android.permission.FOREGROUND_SERVICE_CAMERA(Android 12+)权限 - 把CameraAwesome的相机控制逻辑移到前台服务中,确保服务在前台运行(必须显示一个持续的通知)
- 严格管理前台服务的生命周期,避免内存泄漏
不过这个方案比较复杂,需要修改CameraAwesome的底层适配逻辑。如果只是想解决下拉通知栏的中断问题,前面的生命周期修正就完全足够了。
最后验证步骤
- 替换为修正后的代码,确保所有异步操作都加了
await - 测试下拉通知栏:此时录制应该暂停,回到应用后自动恢复
- 测试退到后台:录制会自动停止,生成完整的视频文件
- 检查日志,确认没有
EOS is sent的警告
内容来源于stack exchange




