HarmonyOS 6学习:相机黑屏“七宗罪”——从日志盲猜到代码修复的精准排雷指南
在HarmonyOS 6应用开发中,自定义相机页面“一片漆黑”是最令人头疼的高频问题。你明明按照文档调用了 createPreviewOutput和 session.start(),但预览界面就是没有任何画面,Hilog日志里却只有一句模糊的 failed to get surface或 Operation not allowed。
这通常不是硬件故障,而是开发者在权限、时序、生命周期这三个关键环节踩了坑。本文将结合HarmonyOS 6的最新Camera Kit API,为你梳理一套从“日志关键词”到“代码修复”的完整排雷流程。
一、现场:黑屏背后的“七宗罪”与日志指纹
当相机页面黑屏时,第一步是查看Hilog日志。不同的错误日志对应着完全不同的代码缺陷。
|
黑屏场景(罪因) |
典型日志关键词 |
代码缺陷本质 |
|---|---|---|
|
1. 权限未授权 |
|
未声明或未申请 |
|
2. 设备被占用 |
|
相机被其他应用(如系统相机)独占 |
|
3. Surface未就绪 |
|
|
|
4. 配置时序错乱 |
|
|
|
5. 流不可用 |
|
添加了不支持的 |
|
6. 折叠屏未切换 |
(无特定日志) |
折叠状态变化后未重新绑定摄像头 |
|
7. 后台未释放 |
|
页面返回后未在 |
日志示例(Surface缺失):
// ❌ 典型错误:XComponent未创建就初始化相机
{CreatePreviewOutput():357} failed to get surface
<surface_utils.cpp:48-GetSurface>: Cannot find surface, uniqueId: 0
二、诊断:根据日志关键词锁定“病灶”
1. 如果是“Permission denied”或“errorReason: 2”
排查重点:权限声明与动态申请。
-
检查
module.json5:确认已声明ohos.permission.CAMERA权限。 -
检查动态申请逻辑:在
onPageShow中调用requestPermissionsFromUser,并处理用户拒绝后的引导逻辑。 -
日志线索:若日志出现
state: 2, errorReason: 2,通常意味着权限根本未声明。
2. 如果是“failed to get surface”
排查重点:XComponent 生命周期与相机初始化的时序。
这是HarmonyOS 6开发中最常见的坑。绝对不能在 onPageShow中直接初始化相机,因为此时 XComponent可能还未创建完成,导致 getXComponentSurfaceId()返回空值。
错误代码示例:
// ❌ 错误示例:onPageShow中直接初始化(XComponent可能未加载)
onPageShow() {
let surfaceId = this.mXComponentController.getXComponentSurfaceId(); // 可能为undefined
this.initCamera(surfaceId); // 导致createPreviewOutput失败
}
修复方案:必须在 XComponent的 onLoad回调中初始化相机。
// ✅ 正确示例:等待XComponent加载完成
@State surfaceId: string = '';
XComponent({ id: 'cameraPreview', type: 'surface', controller: this.mXComponentController })
.onLoad(() => {
// 此时Surface已创建,获取ID并初始化
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
this.initCamera(this.surfaceId);
})
3. 如果是“Operation not allowed”或“Session not config”
排查重点:相机操作必须包裹在配置会话中。
HarmonyOS 6的相机操作是严格的“事务性”流程,添加/移除输入输出流必须在 beginConfig()和 commitConfig()之间进行,且必须在 commitConfig()之后才能调用 start()。
正确时序代码:
// ✅ 必须遵循的时序
async initCamera() {
// ... 创建cameraInput, previewOutput ...
// 1. 开始配置
this.session.beginConfig();
// 2. 添加流(必须在配置区间内)
this.session.addInput(this.cameraInput);
this.session.addOutput(this.previewOutput);
// 3. 提交配置
await this.session.commitConfig();
// 4. 提交后才能启动
await this.session.start();
}
注意:任何在 beginConfig之外直接调用 addInput或 commitConfig之前调用 start的行为都会触发 7400102或 7400103错误码。
三、修复:高频黑屏场景的“代码手术”
场景1:权限导致的“静默黑屏”
现象:无崩溃日志,但页面黑屏,拍照按钮点击闪退。
修复:在初始化前增加权限校验。
import { abilityAccessCtrl } from '@kit.AbilityAccessCtrlKit';
async checkCameraPermission(): Promise<boolean> {
let atManager = abilityAccessCtrl.createAtManager();
let permissions: Array<string> = ['ohos.permission.CAMERA'];
let grantStatus = await atManager.checkAccessToken(permissions);
return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
async initCamera() {
if (!await this.checkCameraPermission()) {
// 跳转设置或弹窗提示
return;
}
// ... 继续初始化
}
场景2:折叠屏切换后的“黑屏”
现象:折叠屏设备展开/折叠后,相机预览黑屏。
修复:监听 display变化,重新初始化相机。
import { display } from '@kit.ArkUI';
// 监听屏幕变化
display.on('change', () => {
this.releaseCamera(); // 先释放旧资源
setTimeout(() => {
this.initCamera(); // 重新初始化(需等待布局稳定)
}, 300);
});
场景3:页面返回后“黑屏”
现象:从B页面返回A页面,A页面的相机无法恢复。
修复:在 onPageHide中释放,在 onPageShow中重建。
onPageShow() {
if (this.surfaceId) {
this.initCamera(this.surfaceId);
}
}
onPageHide() {
this.releaseCamera(); // 必须释放,否则返回时可能报“设备被占用”
}
四、总结:相机黑屏排查 SOP
-
查日志:搜索
Permission denied、failed to get surface、Operation not allowed关键词。 -
验权限:确认
module.json5已声明且用户已授权。 -
看时序:确认相机初始化在
XComponent.onLoad中,且操作流严格遵循beginConfig->addInput/Output->commitConfig->start。 -
保释放:在
onPageHide或aboutToDisappear中调用release(),防止资源泄漏。
核心法则:在HarmonyOS 6中,相机是稀缺资源,“谁申请,谁释放”是铁律。任何对时序和生命周期的忽视,都会直接导致预览黑屏。
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任。
更多推荐


所有评论(0)