跳到主要内容

录屏与投屏

问题

Android 如何实现录屏功能?MediaProjection API 怎么用?

答案

MediaProjection 录屏流程

实现步骤

class ScreenRecordService : Service() {
private var mediaProjection: MediaProjection? = null
private var mediaRecorder: MediaRecorder? = null
private var virtualDisplay: VirtualDisplay? = null

fun startRecording(resultCode: Int, data: Intent) {
// 1. 获取 MediaProjection
val projectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
mediaProjection = projectionManager.getMediaProjection(resultCode, data)

// 2. 配置 MediaRecorder
val outputFile = File(getExternalFilesDir(null), "record_${System.currentTimeMillis()}.mp4")
mediaRecorder = MediaRecorder(this).apply {
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setAudioSource(MediaRecorder.AudioSource.MIC)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setVideoSize(1080, 1920)
setVideoFrameRate(30)
setVideoEncodingBitRate(6_000_000)
setOutputFile(outputFile.absolutePath)
prepare()
}

// 3. 创建 VirtualDisplay,将屏幕镜像到 MediaRecorder 的 Surface
val metrics = resources.displayMetrics
virtualDisplay = mediaProjection?.createVirtualDisplay(
"ScreenRecord",
1080, 1920, metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaRecorder?.surface, // 关键:Surface 来自 MediaRecorder
null, null
)

// 4. 开始录制
mediaRecorder?.start()
}

fun stopRecording() {
mediaRecorder?.stop()
mediaRecorder?.release()
virtualDisplay?.release()
mediaProjection?.stop()
}
}
Android 10+ 限制

Android 10 起录屏必须在前台 ServiceforegroundServiceType="mediaProjection")中进行。Android 14 进一步要求每次录屏都必须重新获取用户授权。

截图(单帧捕获)

// 使用 ImageReader 捕获单帧
val imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2)

val virtualDisplay = mediaProjection.createVirtualDisplay(
"Screenshot", width, height, density,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
imageReader.surface, null, null
)

imageReader.setOnImageAvailableListener({ reader ->
val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener
// Image → Bitmap
val planes = image.planes
val buffer = planes[0].buffer
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
bitmap.copyPixelsFromBuffer(buffer)
image.close()
virtualDisplay.release()
}, handler)

常见面试问题

Q1: 为什么录屏需要前台 Service?

答案

录屏涉及用户隐私(屏幕内容可能包含敏感信息)。Android 10 起强制要求 MediaProjection 在前台 Service 中使用,确保用户能通过通知栏看到正在录屏。后台录屏被禁止,进入后台后 MediaProjection 会被自动停止。

Q2: 录屏如何同时录制系统音频?

答案

Android 10+ 支持通过 AudioPlaybackCapture API 录制其他应用播放的系统音频。需要在 MediaRecorder 中设置 setAudioSource(MediaRecorder.AudioSource.REMOTE_SUBMIX) 或使用 AudioRecord + AudioPlaybackCaptureConfiguration。但目标应用可以通过 setAllowedCapturePolicy(ALLOW_CAPTURE_BY_NONE) 拒绝被录制。

相关链接