鸿蒙相机开发入门篇(官方实践版)
--- 从系统能力声明到可运行的拍照预览应用
一、前言
很多刚接触鸿蒙开发的同学,在尝试使用相机时会遇到两个常见问题:
- 为什么明明引入了相机模块,却提示"系统能力缺失"?
- 为什么写了相机逻辑,却看不到预览画面?
这篇文章将带你从 0 到 1 完成一个能"预览 + 拍照"的相机应用,完全基于 HarmonyOS NEXT 官方最佳实践,并结合 UI 层和交互讲解。
二、基础准备
1. 必要权限与系统能力声明
鸿蒙系统使用 SystemCapability(系统能力标识) 来声明模块功能。
在相机开发中,你必须在 module.json5
文件中声明以下内容:
json
{
"module": {
"name": "entry",
"requestPermissions": [
{ "name": "ohos.permission.CAMERA" },
{ "name": "ohos.permission.MICROPHONE" },
{ "name": "ohos.permission.WRITE_MEDIA" }
],
"systemCapabilities": [
"SystemCapability.Multimedia.Camera.Core",
"SystemCapability.Multimedia.Camera.Basic",
"SystemCapability.Multimedia.Camera.Metadata"
]
}
}
⚠️ 注意:
鸿蒙要求编译时声明能力,否则构建期就会报错,这点和 Android 运行时动态声明完全不同。
三、创建相机基础结构
在鸿蒙中,Camera 模块的核心接口位于 @ohos.multimedia.camera
。
下面我们先构建一个基础拍照页面:
kotlin
// pages/CameraPage.ets
import camera from '@ohos.multimedia.camera';
import media from '@ohos.multimedia.media';
import fileio from '@ohos.fileio';
@Entry
@Component
struct CameraPage {
controller: camera.CameraManager = camera.getCameraManager(globalThis.context);
previewOutput?: camera.PreviewOutput;
photoOutput?: camera.PhotoOutput;
cameraInput?: camera.CameraInput;
build() {
Column() {
// 预览区域
if (this.previewOutput) {
// 使用 SurfaceId 渲染相机画面
XComponent({ id: 'cameraView', type: XComponentType.SURFACE })
.onLoad((context) => {
this.startPreview(context);
})
.width('100%')
.height('80%')
}
// 拍照按钮
Button('拍照')
.onClick(() => this.takePhoto())
.width('50%')
.height(50)
.backgroundColor('#007DFF')
.fontColor('#fff')
.borderRadius(25)
}
}
async startPreview(context) {
const cameras = this.controller.getSupportedCameras();
this.cameraInput = this.controller.createCameraInput(cameras[0]);
this.previewOutput = this.controller.createPreviewOutput(context);
this.photoOutput = this.controller.createPhotoOutput();
const session = this.controller.createSession(camera.SessionType.SESSION_TYPE_NORMAL);
await session.beginConfig();
session.addInput(this.cameraInput);
session.addOutput(this.previewOutput);
session.addOutput(this.photoOutput);
await session.commitConfig();
session.start();
await this.cameraInput.open();
this.previewOutput.start();
}
async takePhoto() {
if (!this.photoOutput) return;
const photoPath = `/data/storage/el2/base/photos/${Date.now()}.jpg`;
await this.photoOutput.capture(photoPath);
prompt.showToast({ message: '拍照成功!', duration: 1500 });
}
}
四、代码讲解
模块 | 说明 |
---|---|
CameraManager |
管理相机设备(前置/后置等) |
CameraInput |
表示相机输入(光学传感器) |
PreviewOutput |
负责输出实时预览帧(绑定 UI Surface) |
PhotoOutput |
负责拍照输出(生成 JPEG 文件) |
Session |
管理相机的输入输出会话,必须配置后才能启动 |
五、UI 层与交互优化
为了让拍照体验更自然,可以加入一个简洁的取景框样式与快门动效:
kotlin
// 快门动画效果
@State shutterEffect: boolean = false
Button('拍照')
.onClick(() => {
this.shutterEffect = true
setTimeout(() => (this.shutterEffect = false), 150)
this.takePhoto()
})
.scale({ x: this.shutterEffect ? 0.9 : 1.0 })
.animation({ duration: 150, curve: Curve.EaseInOut })