鸿蒙Camera Kit深度解析与开发环境搭建

25 阅读5分钟

鸿蒙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的基础架构、开发环境配置、权限管理和相机初始化流程。通过完整的代码示例和最佳实践,为后续的预览、拍照、录像等高级功能打下了坚实基础。

关键要点总结:

  1. Camera Kit采用分层架构,提供统一的相机访问接口
  2. 完善的权限管理是相机应用开发的前提
  3. CameraManager是相机功能的入口,负责设备管理和状态监控
  4. 合理的错误处理和资源管理是稳定性的保障