鸿蒙Camera Kit深度解析与开发环境搭建
1. Camera Kit概述与核心架构
1.1 Camera Kit的定位与价值
鸿蒙Camera Kit是HarmonyOS系统中负责相机功能的核心套件,它为开发者提供了一套完整、高效的相机应用开发解决方案。作为多媒体子系统的重要组成部分,Camera Kit不仅仅是一个简单的API集合,而是一个完整的相机框架体系。
Camera Kit的核心价值体现在:
- 统一的相机访问接口:屏蔽底层硬件差异,提供一致的开发体验
- 高性能图像处理:优化的图像处理流水线,保证拍摄质量和性能
- 多场景适配:支持普通拍照、录像、美颜、AR等多种场景
- 安全权限管理:完善的权限控制机制,保护用户隐私
1.2 核心架构解析
Camera Kit采用分层架构设计,从上到下分为:
text
应用层 → 框架层 → 服务层 → HDI层 → 驱动层
各层职责详解:
- 应用层:开发者编写的相机应用,通过ArkTS调用Camera Kit API
- 框架层:提供CameraManager、Session、Input/Output等核心类
- 服务层:相机服务管理,负责权限验证、资源调度
- HDI层:硬件设备接口,抽象不同厂商的相机硬件
- 驱动层:具体的相机硬件驱动
1.3 核心组件关系
Camera Kit的核心组件遵循明确的协作关系:
typescript
CameraManager → CameraInput → Session → Outputs (Preview/Photo/Video)
这种设计确保了数据流的清晰性和可维护性,每个组件职责单一,便于扩展和维护。
2. 开发环境配置
2.1 环境要求与工具准备
系统要求:
- DevEco Studio 4.0 Release 或更高版本
- HarmonyOS SDK API 9+
- 真机设备或模拟器(推荐使用真机测试相机功能)
项目配置:
在module.json5中配置相机相关权限和能力:
json
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_permission_reason",
"usedScene": {
"abilities": ["MainAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:microphone_permission_reason",
"usedScene": {
"abilities": ["MainAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.MEDIA_LOCATION",
"reason": "$string:media_location_reason",
"usedScene": {
"abilities": ["MainAbility"],
"when": "inuse"
}
}
],
"abilities": [
{
"name": "MainAbility",
"srcEntry": "./ets/mainability/MainAbility.ts",
"description": "$string:mainability_description",
"icon": "$media:icon",
"label": "$string:mainability_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:white",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
}
]
}
}
2.2 依赖配置
在package.json中确保包含相机相关依赖:
json
{
"dependencies": {
"@kit.CameraKit": "^1.0.0",
"@kit.MediaLibraryKit": "^1.0.0",
"@kit.AbilityKit": "^1.0.0",
"@kit.ImageKit": "^1.0.0"
}
}
3. 权限管理深度解析
3.1 相机权限分类与使用场景
必需权限:
typescript
// 基础相机权限 - 必须申请
const CAMERA_PERMISSION = 'ohos.permission.CAMERA';
// 录音权限 - 录像时需要
const MICROPHONE_PERMISSION = 'ohos.permission.MICROPHONE';
// 地理位置权限 - 需要记录照片位置时使用
const MEDIA_LOCATION_PERMISSION = 'ohos.permission.MEDIA_LOCATION';
3.2 动态权限申请实现
创建完整的权限管理类:
typescript
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
class CameraPermissionManager {
private context: common.BaseContext;
private atManager: abilityAccessCtrl.AtManager;
constructor(context: common.BaseContext) {
this.context = context;
this.atManager = abilityAccessCtrl.createAtManager();
}
// 检查权限状态
async checkPermissions(permissions: Array<Permissions>): Promise<Array<boolean>> {
try {
const results: Array<boolean> = [];
for (const permission of permissions) {
const result = await this.atManager.checkAccessToken(this.context, permission);
results.push(result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED);
}
return results;
} catch (error) {
console.error(`Check permissions failed: ${(error as BusinessError).message}`);
return permissions.map(() => false);
}
}
// 请求权限
async requestPermissions(permissions: Array<Permissions>): Promise<Array<boolean>> {
try {
const requestResult = await this.atManager.requestPermissionsFromUser(
this.context,
permissions
);
const grantResults: Array<boolean> = [];
for (let i = 0; i < permissions.length; i++) {
const granted = requestResult.authResults[i] === 0;
grantResults.push(granted);
if (!granted) {
console.warn(`Permission ${permissions[i]} denied by user`);
}
}
return grantResults;
} catch (error) {
console.error(`Request permissions failed: ${(error as BusinessError).message}`);
return permissions.map(() => false);
}
}
// 完整的权限验证流程
async ensureCameraPermissions(): Promise<boolean> {
const requiredPermissions: Array<Permissions> = [
'ohos.permission.CAMERA'
];
// 先检查权限状态
const checkResults = await this.checkPermissions(requiredPermissions);
const allGranted = checkResults.every(result => result);
if (allGranted) {
return true;
}
// 请求未授权的权限
const requestResults = await this.requestPermissions(requiredPermissions);
return requestResults.every(result => result);
}
}
// 使用示例
export { CameraPermissionManager };
4. 相机管理器深度探索
4.1 CameraManager的创建与初始化
CameraManager是相机功能的入口点,负责管理所有相机设备和会话:
typescript
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
class AdvancedCameraManager {
private cameraManager: camera.CameraManager | null = null;
private context: common.BaseContext;
constructor(context: common.BaseContext) {
this.context = context;
}
// 初始化CameraManager
async initialize(): Promise<boolean> {
try {
this.cameraManager = camera.getCameraManager(this.context);
if (!this.cameraManager) {
console.error('Failed to get CameraManager instance');
return false;
}
// 设置相机状态监听
this.setupCameraStatusListener();
// 设置折叠状态监听(针对折叠设备)
this.setupFoldStatusListener();
console.info('CameraManager initialized successfully');
return true;
} catch (error) {
console.error(`CameraManager initialization failed: ${(error as BusinessError).message}`);
return false;
}
}
// 相机状态监听
private setupCameraStatusListener(): void {
if (!this.cameraManager) return;
this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
if (err) {
console.error(`Camera status error: ${err.code}, ${err.message}`);
return;
}
this.handleCameraStatusChange(cameraStatusInfo);
});
}
// 处理相机状态变化
private handleCameraStatusChange(cameraStatusInfo: camera.CameraStatusInfo): void {
const { camera: cameraDevice, status } = cameraStatusInfo;
console.info(`Camera ${cameraDevice.cameraId} status changed to: ${status}`);
switch (status) {
case camera.CameraStatus.CAMERA_STATUS_APPEAR:
this.onCameraAppear(cameraDevice);
break;
case camera.CameraStatus.CAMERA_STATUS_DISAPPEAR:
this.onCameraDisappear(cameraDevice);
break;
case camera.CameraStatus.CAMERA_STATUS_AVAILABLE:
this.onCameraAvailable(cameraDevice);
break;
case camera.CameraStatus.CAMERA_STATUS_UNAVAILABLE:
this.onCameraUnavailable(cameraDevice);
break;
}
}
private onCameraAppear(cameraDevice: camera.CameraDevice): void {
console.info(`New camera appeared: ${cameraDevice.cameraId}`);
// 处理新相机设备出现,如更新UI等
}
private onCameraDisappear(cameraDevice: camera.CameraDevice): void {
console.info(`Camera disappeared: ${cameraDevice.cameraId}`);
// 处理相机设备移除
}
private onCameraAvailable(cameraDevice: camera.CameraDevice): void {
console.info(`Camera available: ${cameraDevice.cameraId}`);
// 相机可用,可以打开
}
private onCameraUnavailable(cameraDevice: camera.CameraDevice): void {
console.info(`Camera unavailable: ${cameraDevice.cameraId}`);
// 相机被占用,不可用
}
// 折叠状态监听(针对折叠设备)
private setupFoldStatusListener(): void {
if (!this.cameraManager) return;
this.cameraManager.on('foldStatusChange', (err: BusinessError, foldStatusInfo: camera.FoldStatusInfo) => {
if (err) {
console.error(`Fold status error: ${err.code}, ${err.message}`);
return;
}
this.handleFoldStatusChange(foldStatusInfo);
});
}
private handleFoldStatusChange(foldStatusInfo: camera.FoldStatusInfo): void {
console.info(`Fold status changed to: ${foldStatusInfo.foldStatus}`);
console.info(`Supported cameras in new state: ${foldStatusInfo.supportedCameras.length}`);
// 处理折叠状态变化,可能需要切换相机
this.adaptToFoldStatus(foldStatusInfo);
}
private adaptToFoldStatus(foldStatusInfo: camera.FoldStatusInfo): void {
// 根据折叠状态调整相机选择
// 实际实现中可能需要重启相机会话
}
}
4.2 相机设备枚举与选择策略
实现智能的相机设备选择逻辑:
typescript
class CameraDeviceSelector {
private cameraManager: camera.CameraManager;
constructor(cameraManager: camera.CameraManager) {
this.cameraManager = cameraManager;
}
// 获取所有支持的相机设备
getSupportedCameras(): Array<camera.CameraDevice> {
try {
return this.cameraManager.getSupportedCameras();
} catch (error) {
console.error(`Get supported cameras failed: ${(error as BusinessError).message}`);
return [];
}
}
// 根据位置筛选相机
filterCamerasByPosition(
cameras: Array<camera.CameraDevice>,
position: camera.CameraPosition
): Array<camera.CameraDevice> {
return cameras.filter(camera => camera.cameraPosition === position);
}
// 根据类型筛选相机
filterCamerasByType(
cameras: Array<camera.CameraDevice>,
cameraType: camera.CameraType
): Array<camera.CameraDevice> {
return cameras.filter(camera => camera.cameraType === cameraType);
}
// 智能选择最佳相机
selectOptimalCamera(
preferredPosition: camera.CameraPosition = camera.CameraPosition.CAMERA_POSITION_BACK
): camera.CameraDevice | null {
const cameras = this.getSupportedCameras();
if (cameras.length === 0) {
console.error('No cameras available');
return null;
}
// 优先选择指定位置的相机
const positionCameras = this.filterCamerasByPosition(cameras, preferredPosition);
if (positionCameras.length > 0) {
// 在同位置相机中选择广角镜头(通常质量更好)
const wideAngle = positionCameras.find(camera =>
camera.cameraType === camera.CameraType.CAMERA_TYPE_WIDE_ANGLE
);
return wideAngle || positionCameras[0];
}
// 回退到第一个可用相机
console.warn(`No camera found at position ${preferredPosition}, using first available`);
return cameras[0];
}
// 获取相机详细信息
logCameraDetails(cameras: Array<camera.CameraDevice>): void {
cameras.forEach((cameraDevice, index) => {
console.info(`Camera ${index}:`);
console.info(` ID: ${cameraDevice.cameraId}`);
console.info(` Position: ${cameraDevice.cameraPosition}`);
console.info(` Type: ${cameraDevice.cameraType}`);
console.info(` Connection: ${cameraDevice.connectionType}`);
});
}
}
5. 相机输入流深度配置
5.1 CameraInput的创建与管理
CameraInput代表相机的输入流,是相机数据流的起点:
typescript
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
class AdvancedCameraInput {
private cameraInput: camera.CameraInput | null = null;
private currentCamera: camera.CameraDevice | null = null;
// 创建并打开相机输入
async createAndOpenCameraInput(
cameraDevice: camera.CameraDevice,
cameraManager: camera.CameraManager
): Promise<boolean> {
try {
// 创建相机输入
this.cameraInput = cameraManager.createCameraInput(cameraDevice);
this.currentCamera = cameraDevice;
// 设置错误监听
this.setupErrorListener();
// 打开相机
await this.cameraInput.open();
console.info(`Camera input opened successfully for device: ${cameraDevice.cameraId}`);
return true;
} catch (error) {
console.error(`Failed to create camera input: ${(error as BusinessError).message}`);
return false;
}
}
// 设置错误监听
private setupErrorListener(): void {
if (!this.cameraInput || !this.currentCamera) return;
this.cameraInput.on('error', this.currentCamera, (error: BusinessError) => {
console.error(`Camera input error: code=${error.code}, message=${error.message}`);
this.handleCameraError(error);
});
}
// 处理相机错误
private handleCameraError(error: BusinessError): void {
switch (error.code) {
case 5400101:
console.error('Camera device not found or permission denied');
break;
case 5400102:
console.error('Camera device already in use');
break;
case 5400103:
console.error('Camera device configuration failed');
break;
default:
console.error(`Unknown camera error: ${error.code}`);
}
}
// 关闭相机输入
async closeCameraInput(): Promise<void> {
if (this.cameraInput) {
try {
await this.cameraInput.close();
this.cameraInput = null;
this.currentCamera = null;
console.info('Camera input closed successfully');
} catch (error) {
console.error(`Failed to close camera input: ${(error as BusinessError).message}`);
}
}
}
// 获取支持的场景模式
getSupportedSceneModes(
cameraDevice: camera.CameraDevice,
cameraManager: camera.CameraManager
): Array<camera.SceneMode> {
try {
return cameraManager.getSupportedSceneModes(cameraDevice);
} catch (error) {
console.error(`Get supported scene modes failed: ${(error as BusinessError).message}`);
return [];
}
}
// 检查是否支持特定场景模式
isSceneModeSupported(
cameraDevice: camera.CameraDevice,
cameraManager: camera.CameraManager,
sceneMode: camera.SceneMode
): boolean {
const supportedModes = this.getSupportedSceneModes(cameraDevice, cameraManager);
return supportedModes.includes(sceneMode);
}
}
5.2 相机输出能力分析
深度分析相机的输出能力,为后续配置做准备:
typescript
class CameraCapabilityAnalyzer {
private cameraManager: camera.CameraManager;
constructor(cameraManager: camera.CameraManager) {
this.cameraManager = cameraManager;
}
// 获取相机输出能力
async getCameraOutputCapability(
cameraDevice: camera.CameraDevice,
sceneMode: camera.SceneMode
): Promise<camera.CameraOutputCapability | null> {
try {
const capability = this.cameraManager.getSupportedOutputCapability(cameraDevice, sceneMode);
if (!capability) {
console.error('Failed to get camera output capability');
return null;
}
this.logCapabilityDetails(capability, cameraDevice.cameraId);
return capability;
} catch (error) {
console.error(`Get camera output capability failed: ${(error as BusinessError).message}`);
return null;
}
}
// 记录能力详情
private logCapabilityDetails(capability: camera.CameraOutputCapability, cameraId: string): void {
console.info(`Camera ${cameraId} capability details:`);
// 预览配置
if (capability.previewProfiles && capability.previewProfiles.length > 0) {
console.info(` Preview profiles: ${capability.previewProfiles.length}`);
capability.previewProfiles.forEach((profile, index) => {
console.info(` [${index}] ${profile.size.width}x${profile.size.height}, format: ${profile.format}`);
});
}
// 拍照配置
if (capability.photoProfiles && capability.photoProfiles.length > 0) {
console.info(` Photo profiles: ${capability.photoProfiles.length}`);
capability.photoProfiles.forEach((profile, index) => {
console.info(` [${index}] ${profile.size.width}x${profile.size.height}, format: ${profile.format}`);
});
}
// 视频配置
if (capability.videoProfiles && capability.videoProfiles.length > 0) {
console.info(` Video profiles: ${capability.videoProfiles.length}`);
capability.videoProfiles.forEach((profile, index) => {
console.info(` [${index}] ${profile.size.width}x${profile.size.height}, format: ${profile.format}`);
});
}
// 支持的元数据类型
if (capability.supportedMetadataObjectTypes) {
console.info(` Supported metadata types: ${capability.supportedMetadataObjectTypes.length}`);
}
}
// 选择最佳预览配置
selectOptimalPreviewProfile(
capability: camera.CameraOutputCapability,
targetWidth: number,
targetHeight: number
): camera.Profile | null {
if (!capability.previewProfiles || capability.previewProfiles.length === 0) {
return null;
}
const targetRatio = targetWidth / targetHeight;
let bestProfile: camera.Profile | null = null;
let minRatioDiff = Number.MAX_VALUE;
for (const profile of capability.previewProfiles) {
const profileRatio = profile.size.width / profile.size.height;
const ratioDiff = Math.abs(profileRatio - targetRatio);
// 优先选择比例最接近的配置
if (ratioDiff < minRatioDiff) {
minRatioDiff = ratioDiff;
bestProfile = profile;
}
}
return bestProfile;
}
}
6. 完整示例:相机初始化框架
整合以上所有组件,创建一个完整的相机初始化框架:
typescript
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
class CameraInitializationFramework {
private context: common.BaseContext;
private permissionManager: CameraPermissionManager;
private cameraManager: AdvancedCameraManager;
private deviceSelector: CameraDeviceSelector;
private capabilityAnalyzer: CameraCapabilityAnalyzer;
private cameraInput: AdvancedCameraInput;
private isInitialized: boolean = false;
private currentCamera: camera.CameraDevice | null = null;
private currentCapability: camera.CameraOutputCapability | null = null;
constructor(context: common.BaseContext) {
this.context = context;
this.permissionManager = new CameraPermissionManager(context);
this.cameraManager = new AdvancedCameraManager(context);
// 注意:这里需要先初始化cameraManager后才能创建其他依赖
this.deviceSelector = new CameraDeviceSelector(this.cameraManager.cameraManager!);
this.capabilityAnalyzer = new CameraCapabilityAnalyzer(this.cameraManager.cameraManager!);
this.cameraInput = new AdvancedCameraInput();
}
// 完整的相机初始化流程
async initializeCamera(): Promise<boolean> {
try {
// 1. 检查权限
const hasPermission = await this.permissionManager.ensureCameraPermissions();
if (!hasPermission) {
console.error('Camera permissions denied');
return false;
}
// 2. 初始化CameraManager
const managerInitialized = await this.cameraManager.initialize();
if (!managerInitialized) {
console.error('CameraManager initialization failed');
return false;
}
// 3. 选择相机设备
this.currentCamera = this.deviceSelector.selectOptimalCamera();
if (!this.currentCamera) {
console.error('No suitable camera found');
return false;
}
// 4. 获取输出能力
this.currentCapability = await this.capabilityAnalyzer.getCameraOutputCapability(
this.currentCamera,
camera.SceneMode.NORMAL_PHOTO
);
if (!this.currentCapability) {
console.error('Failed to get camera capability');
return false;
}
// 5. 创建并打开相机输入
const inputCreated = await this.cameraInput.createAndOpenCameraInput(
this.currentCamera,
this.cameraManager.cameraManager!
);
if (!inputCreated) {
console.error('Failed to create camera input');
return false;
}
this.isInitialized = true;
console.info('Camera initialization completed successfully');
return true;
} catch (error) {
console.error(`Camera initialization failed: ${(error as BusinessError).message}`);
this.cleanup();
return false;
}
}
// 清理资源
async cleanup(): Promise<void> {
await this.cameraInput.closeCameraInput();
this.isInitialized = false;
this.currentCamera = null;
this.currentCapability = null;
}
// 获取当前状态
getStatus(): {
isInitialized: boolean;
camera: camera.CameraDevice | null;
capability: camera.CameraOutputCapability | null;
} {
return {
isInitialized: this.isInitialized,
camera: this.currentCamera,
capability: this.currentCapability
};
}
}
// 使用示例
export { CameraInitializationFramework };
7. 最佳实践与注意事项
7.1 错误处理策略
typescript
class CameraErrorHandler {
static handleCameraError(error: BusinessError, context: string): void {
console.error(`Camera error in ${context}: code=${error.code}, message=${error.message}`);
// 根据错误码提供用户友好的提示
const userMessage = this.getUserFriendlyMessage(error.code);
// 在实际应用中,这里可以显示Toast或对话框
console.info(`User message: ${userMessage}`);
}
private static getUserFriendlyMessage(errorCode: number): string {
switch (errorCode) {
case 5400101:
return '相机设备未找到或权限被拒绝';
case 5400102:
return '相机设备正在被其他应用使用';
case 5400103:
return '相机配置失败,请重启应用';
case 5400104:
return '相机服务不可用';
default:
return '相机发生未知错误';
}
}
}
7.2 资源管理最佳实践
typescript
class CameraResourceManager {
private resources: Array<{ release: () => Promise<void> }> = [];
// 注册需要管理的资源
registerResource(resource: { release: () => Promise<void> }): void {
this.resources.push(resource);
}
// 释放所有资源
async releaseAllResources(): Promise<void> {
const releasePromises = this.resources.map(async resource => {
try {
await resource.release();
} catch (error) {
console.error(`Resource release failed: ${(error as BusinessError).message}`);
}
});
await Promise.all(releasePromises);
this.resources = [];
}
// 自动资源管理(使用RAII模式)
async withCameraResources<T>(
operation: () => Promise<T>
): Promise<T> {
try {
return await operation();
} finally {
await this.releaseAllResources();
}
}
}
总结
本篇深入探讨了鸿蒙Camera Kit的基础架构、开发环境配置、权限管理和相机初始化流程。通过完整的代码示例和最佳实践,为后续的预览、拍照、录像等高级功能打下了坚实基础。
关键要点总结:
- Camera Kit采用分层架构,提供统一的相机访问接口
- 完善的权限管理是相机应用开发的前提
- CameraManager是相机功能的入口,负责设备管理和状态监控
- 合理的错误处理和资源管理是稳定性的保障