屏幕录制:调用系统录屏能力录制桌面内容(92)
在鸿蒙HarmonyOS应用开发中调用系统录屏能力主要依赖于Media Kit中的AVScreenCaptureRecorder模块。该模块支持 ArkTS 和 Native (C/C) 两种开发语言能够完成从全屏录制、窗口级录制到获取原始音视频码流等多种复杂场景。一、 ArkTS 基础录屏初始化配置与文件写入使用 ArkTS 进行录屏时核心流程包括创建AVScreenCaptureRecorder实例、配置音视频参数如指定文件描述符fd、以及控制录屏的开始与停止。核心代码示例import media from ohos.multimedia.media; import fs from ohos.file.fs; import { common } from kit.AbilityKit; private avScreenCaptureRecorder: media.AVScreenCaptureRecorder | undefined undefined; async function startScreenRecord(context: common.UIAbilityContext) { // 1. 创建录屏实例 this.avScreenCaptureRecorder await media.createAVScreenCaptureRecorder(); // 2. 准备录制文件并配置参数 let pathDir context.filesDir; let filesUri pathDir /Screen_ new Date().getTime() .mp4; let curFile fs.openSync(filesUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); let avCaptureConfig: media.AVScreenCaptureRecordConfig { fd: curFile.fd, // 必须传入具有写权限的文件描述符 // frameWidth: 720, // 可选自定义视频宽度 // frameHeight: 1280 // 可选自定义视频高度 }; // 3. 初始化并开始录制 await this.avScreenCaptureRecorder.init(avCaptureConfig); await this.avScreenCaptureRecorder.startRecording(); } async function stopScreenRecord() { // 4. 停止录制并释放资源 await this.avScreenCaptureRecorder?.stopRecording(); await this.avScreenCaptureRecorder?.release(); }二、 高阶控制Picker 模式与麦克风权限在 HarmonyOS 6.1.0 及以上版本中系统增强了录屏的隐私保护与多屏适配能力。开发者可以通过setPickerMode调起系统级的选择器Picker让用户自主选择录制全屏、特定应用或特定窗口。同时若需录入麦克风声音必须动态申请权限。核心代码示例import { abilityAccessCtrl } from kit.AbilityKit; // 1. 设置 Picker 显示模式例如仅显示窗口选择 if (this.avScreenCaptureRecorder) { await this.avScreenCaptureRecorder.setPickerMode(media.PickerMode.WINDOW_ONLY); // 录屏过程中可动态更新录制源 await this.avScreenCaptureRecorder.presentPicker(); } // 2. 申请麦克风权限录屏带解说必备 async function requestMicPermission() { const atManager abilityAccessCtrl.createAtManager(); try { let result await atManager.requestPermissionsFromUser(getContext(), [ohos.permission.MICROPHONE]); if (result.authResults[0] 0) { console.info(麦克风权限授权成功); } } catch (err) { console.error(申请麦克风权限失败:, err); } }三、 Native 层进阶获取原始音视频码流对于直播推流、远程桌面共享等需要实时处理视频帧的场景可以使用 C/C 调用AVScreenCapture的 NDK 接口。该方式不直接生成 MP4 文件而是通过回调将原始的音视频 Buffer 抛给业务层处理。核心代码示例C#include multimedia/player_framework/native_avscreen_capture.h // 1. 创建并配置录屏实例 OH_AVScreenCapture* capture OH_AVScreenCapture_Create(); OH_AVScreenCaptureConfig config { .captureMode OH_CAPTURE_HOME_SCREEN, .dataType OH_ORIGINAL_STREAM, // 指定获取原始码流 // ...配置音视频采集参数 }; OH_AVScreenCapture_Init(capture, config); // 2. 设置数据回调接收原始 Buffer void OnBufferAvailable(OH_AVScreenCapture *capture, OH_AVBuffer *buffer, OH_AVScreenCaptureBufferType bufferType, int64_t timestamp, void *userData) { // 在此处获取音视频原始码流数据用于推流或实时渲染 } OH_AVScreenCapture_SetDataCallback(capture, OnBufferAvailable, nullptr); // 3. 开始与停止采集 OH_AVScreenCapture_StartScreenCapture(capture); OH_AVScreenCapture_StopScreenCapture(capture); // 4. 释放资源 OH_AVScreenCapture_Release(capture);麦克风权限与长时任务如果配置了采集麦克风音频数据除了必须在module.json5中声明ohos.permission.MICROPHONE权限外还必须在后台运行时申请长时任务ohos.permission.KEEP_BACKGROUND_RUNNING防止录屏被系统挂起。状态机严格校验AVScreenCapture具有严格的状态机机制。在调用Start、Stop等方法前务必通过on(stateChange)监听当前状态在错误的状态下执行操作会导致录屏异常中断。通话中断保护在录屏过程中如果发生系统通话或来电录屏会被系统强制自动停止并上报OH_SCREEN_CAPTURE_STATE_STOPPED_BY_CALL状态开发者需在回调中做好业务状态的恢复与提示。隐私合规提示使用窗口级或应用级录屏时系统 Picker 会向用户展示“隐私保护”警告。开发者应确保录屏功能仅在用户明确授权和知情的情况下开启避免后台静默录制敏感信息。四、 视觉进阶精细化控制图像填充模式FillMode在录屏时捕获源的宽高比往往与目标输出分辨率不一致例如手机全屏录制输出为 1080p。鸿蒙提供了OH_AVScreenCapture_CaptureStrategy策略对象允许开发者灵活配置画面的填充模式避免自行处理裁剪或黑边。核心代码示例C// 1. 创建录屏实例与策略对象 OH_AVScreenCapture* capture OH_AVScreenCapture_Create(); OH_AVScreenCapture_CaptureStrategy* strategy OH_AVScreenCapture_CreateCaptureStrategy(); // 2. 设置填充模式 // OH_FILL_MODE_CROP: 裁剪边缘以填满画面适合游戏、沉浸式视频 // OH_FILL_MODE_FIT: 保持比例留黑边适合代码教学、文档演示 OH_AVScreenCapture_StrategyForFillMode(strategy, OH_FILL_MODE_FIT); // 3. 将策略关联到录屏实例必须在 Init 之前执行 OH_AVScreenCapture_SetCaptureStrategy(capture, strategy); OH_AVScreenCapture_Init(capture, config); // 4. 资源释放录屏结束后先释放策略再释放实例 OH_AVScreenCapture_DestroyCaptureStrategy(strategy); OH_AVScreenCapture_Release(capture);五、 PC端特化后台保活与隐私弹窗静默在鸿蒙 PC/2in1 设备上录屏应用常面临屏幕熄灭导致录制中断或频繁弹出系统隐私警告影响体验的问题。通过申请特定的系统级权限可实现无感录制与后台保活。配置与代码示例// module.json5 权限声明 requestPermissions: [ { name: ohos.permission.TIMEOUT_SCREENOFF_DISABLE_LOCK }, // 息屏不锁屏保活 { name: ohos.permission.CUSTOM_SCREEN_RECORDING } // 禁用系统隐私警告弹窗 ]注配置CUSTOM_SCREEN_RECORDING后应用录屏时将不再弹出“正在录制屏幕”的系统级隐私警告适用于企业内网会议或受信任的监控场景。六、 跨平台架构Flutter 鸿蒙录屏能力的桥接对于使用 Flutter 构建的鸿蒙应用Dart 层无法直接调用AVScreenCaptureRecorder。必须通过自定义插件Plugin结合 Platform Channel 机制在 ArkTS 层完成文件创建、权限申请和录屏控制再将状态回传给 Dart 层。核心代码示例ArkTS 侧// 处理来自 Flutter (Dart) 的 MethodChannel 调用 private onMethodCall(call: MethodCall): void { switch (call.method) { case startRecord: // 调用鸿蒙原生 API 启动录屏 this.startScreenRecord(getContext(this) as common.UIAbilityContext); this.channel.invokeMethodSuccess(call.callbackId, true); break; case stopRecord: this.stopScreenRecord(); this.channel.invokeMethodSuccess(call.callbackId, true); break; default: this.channel.invokeMethodError(call.callbackId, NOT_IMPLEMENTED, Method not implemented); } }七、 稳定性保障系统级异常中断的优雅降级录屏过程中极易受到系统级事件的干扰如来电、用户账号切换、麦克风被抢占。开发者必须完善状态机监听做好业务状态的恢复与用户提示。核心代码示例ArkTSthis.screenCapture.on(stateChange, async (infoType: media.AVScreenCaptureStateCode) { switch (infoType) { case media.AVScreenCaptureStateCode.SCREENCAPTURE_STATE_STOPPED_BY_CALL: // 录屏因通话中断自动释放资源并提示用户 await this.screenCapture?.release(); this.showUserToast(录屏已因系统通话自动暂停); break; case media.AVScreenCaptureStateCode.SCREENCAPTURE_STATE_MIC_UNAVAILABLE: // 麦克风被其他应用抢占仅停止音频采集视频继续或暂停 console.warn(麦克风不可用请检查其他音频应用); break; case media.AVScreenCaptureStateCode.SCREENCAPTURE_STATE_STOPPED_BY_USER_SWITCHES: // 用户切换账号强制停止并清理沙箱临时文件 await this.screenCapture?.release(); this.cleanTempRecordFiles(); break; } });策略先行原则在使用 Native C API 时CaptureStrategy如填充模式、Picker 弹窗策略必须在OH_AVScreenCapture_Init之前通过SetCaptureStrategy挂载。录屏引擎启动后将不再接受策略变更。沙箱路径与文件权限录屏生成的 MP4 文件必须存放在应用沙箱目录如context.filesDir下且文件打开模式必须包含fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE。直接传入外部存储路径会导致init报 401 参数错误。隐私合规红线虽然系统提供了禁用隐私弹窗的权限但在面向 C 端消费者的应用中强烈建议保留系统的 Picker 弹窗和录屏胶囊。静默录屏极易触发应用市场的安全合规审核拦截。性能开销控制录屏是极其消耗 CPU/GPU 和 I/O 的操作。在 ArkTS 层避免在录屏期间进行高频的 UI 刷新或复杂的 JSON 序列化建议将视频帧的后处理如加水印、裁剪交由 Native 层或独立的 Worker 线程处理。1、 策略先行原则Native C API 的严格时序控制在使用 C/C 进行录屏开发时CaptureStrategy必须在Init之前完成挂载。以下代码展示了如何正确地将“填充模式”和“Picker 弹窗策略”封装并绑定到录屏实例中。核心代码示例C#include multimedia/player_framework/native_avscreen_capture.h int32_t ConfigureCaptureStrategy(OH_AVScreenCapture *capture) { if (capture NULL) return -1; // 1. 创建策略对象 OH_AVScreenCapture_CaptureStrategy *strategy OH_AVScreenCapture_CreateCaptureStrategy(); if (strategy NULL) return -1; // 2. 设置填充模式例如保持比例留黑边适合文档演示 OH_AVScreenCapture_StrategyForFillMode(strategy, OH_SCREEN_CAPTURE_FILLMODE_LETTERBOX); // 3. 设置 Picker 弹窗策略true: 录屏启动时弹出系统选择器 OH_AVScreenCapture_StrategyForPickerPopUp(strategy, true); // 4. 将策略挂载到录屏实例必须在 Init 之前执行 OH_AVSCREEN_CAPTURE_ErrCode ret OH_AVScreenCapture_SetCaptureStrategy(capture, strategy); // 注意策略对象在 Set 之后其生命周期由 capture 管理无需手动释放 return ret; }2、 沙箱路径与文件权限规避 401 参数错误录屏初始化时如果文件路径越界或权限不足系统会直接抛出 401 错误。必须严格使用应用沙箱路径并使用正确的OpenMode组合。核心代码示例ArkTSimport { common } from kit.AbilityKit; import { fileIo as fs } from kit.CoreFileKit; import media from ohos.multimedia.media; async function initScreenCapture(context: common.UIAbilityContext) { // 1. 严格使用应用沙箱目录 (context.filesDir) let sandboxPath: string context.filesDir /Screen_ new Date().getTime() .mp4; // 2. 创建文件并赋予 读写 创建 权限 let curFile fs.openSync(sandboxPath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 3. 构建配置对象fd 为必填项其他参数可选 let avCaptureConfig: media.AVScreenCaptureRecordConfig { fd: curFile.fd, // 若需自定义输出分辨率可在此指定 // frameWidth: 1920, // frameHeight: 1080 }; let recorder await media.createAVScreenCaptureRecorder(); await recorder.init(avCaptureConfig); // 此时不会再报 401 错误 }3、 隐私合规红线动态控制 Picker 与弹窗为了兼顾合规与用户体验建议在代码中将 Picker 弹窗策略与业务场景解耦通过动态配置策略对象来控制是否弹出系统级选择器。核心代码示例C// 场景A面向C端用户必须弹出 Picker 让用户知情并选择录制目标 void enablePrivacyCompliance(OH_AVScreenCapture *capture) { OH_AVScreenCapture_CaptureStrategy *strategy OH_AVScreenCapture_CreateCaptureStrategy(); OH_AVScreenCapture_StrategyForPickerPopUp(strategy, true); // 显式开启弹窗 OH_AVScreenCapture_SetCaptureStrategy(capture, strategy); } // 场景B企业内部受信任设备需提前申请 CUSTOM_SCREEN_RECORDING 权限 void disablePickerForEnterprise(OH_AVScreenCapture *capture) { OH_AVScreenCapture_CaptureStrategy *strategy OH_AVScreenCapture_CreateCaptureStrategy(); OH_AVScreenCapture_StrategyForPickerPopUp(strategy, false); // 静默启动 OH_AVScreenCapture_SetCaptureStrategy(capture, strategy); }4、 性能开销控制Worker 线程隔离与后处理录屏期间主线程的 CPU 和 I/O 资源极其紧张。视频帧的后处理如加水印、裁剪、JSON 序列化必须剥离到独立的 Worker 线程中执行。核心代码示例ArkTS// 1. 主线程仅负责录屏控制和轻量级状态更新 Entry Component struct ScreenRecordPage { private worker: worker.ThreadWorker | null null; aboutToAppear() { // 2. 初始化 Worker 线程专门处理耗时的视频帧后处理 this.worker new worker.ThreadWorker(workers/VideoPostProcess.ets); // 监听 Worker 处理完成后的结果仅更新 UI 状态 this.worker.onmessage (e: MessageEvents) { if (e.data.type watermark_added) { // 安全地更新 UI不会导致录屏掉帧 this.updateUIStatus(水印添加成功); } }; } // 3. 录屏结束后的异步后处理 async onRecordingStopped(filePath: string) { // 将耗时操作抛给 Worker绝不阻塞主线程 this.worker?.postMessage({ action: add_watermark, videoPath: filePath }); } }// workers/VideoPostProcess.ets (Worker 线程代码) import { worker, MessageEvents } from kit.ArkTS; const workerPort worker.workerPort; workerPort.onmessage async (e: MessageEvents) { if (e.data.action add_watermark) { // 在独立线程中执行耗时的视频帧处理/JSON序列化 // await processVideoFrames(e.data.videoPath); // 处理完成后通知主线程 workerPort.postMessage({ type: watermark_added }); } };