查看: 154|回复: 3

鸿蒙Camera Kit闪光灯状态监听与C API双端适配

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在移动端影像开发中,相机状态的感知往往比想象中更复杂。尤其是暗光或夜景场景下,闪光灯的状态变化可能由底层自动测光系统触发,也可能由用户手动切换。旧版Camera Kit中,开发者只能主动查询闪光灯模式,无法实时感知底层物理器件的状态变迁。HarmonyOS 6.1.1(API 24)在Camera Kit中新增了FlashState(闪光灯状态)事件回调的订阅与取消订阅能力,并且同时覆盖ArkTS层与Native C API层。无论你是用高阶语言构建元服务,还是在游戏引擎中内嵌C++相机管线,都可以直接监听这一微观状态的变化。

一、核心API速览

ArkTS层的接口基于camera.PhotoSession提供:

- onFlashStateChange(callback: Callback<FlashState>): void —— 订阅闪光灯状态变化回调,当环境光剧变引发自动闪光灯就绪,或用户手动切换模式时触发。

- offFlashStateChange(callback?: Callback<FlashState>): void —— 取消订阅。传入具体callback时精准注销该回调;不传时清空当前Session下所有闪光灯监听。

Native C API层则围绕Camera_CaptureSession提供:

- OH_CaptureSession_RegisterFlashStateChangeCallback:注册OH_CaptureSession_OnFlashStateChange类型回调。

- OH_CaptureSession_UnregisterFlashStateChangeCallback:注销底层状态变更回调,成功返回CAMERA_OK。

值得一提的是,自API 24起,ArkTS相关接口正式支持在元服务(Atomic Service)中使用,应用场景进一步扩大。无论走哪条通道,都需要基于Stage模型开发。

二、示例工程结构

实操Demo的工程路由如下:
  1. ArkTSDemo
  2. ├── entry/src/main/ets/pages
  3. │   ├── Index.ets          -- 主入口
  4. │   ├── CameraKitIntro.ets -- Camera Kit特性展示引导页
  5. │   └── CameraDemo.ets     -- 闪光灯监听控制舱
  6. └── entry/src/main/resources/base/profile
  7.     └── main_pages.json    -- 路由注册表
复制代码

在CameraDemo.ets中,通过定时器模拟底层ISP或C API回调,验证订阅、注销的完整闭环。关键逻辑如下:
  1. import { router } from '@kit.ArkUI';
  2. // 实际开发中需通过 @kit.CameraKit 引入
  3. // import { camera } from '@kit.CameraKit';
  4. @Entry
  5. @Component
  6. struct CameraDemo {
  7.   @State logs: string[] = [];
  8.   @State isSubscribed: boolean = false;
  9.   private mockIntervalId: number = -1;
  10.   private appendLog(msg: string): void {
  11.     let now = new Date();
  12.     let timeStr = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`;
  13.     this.logs.unshift(`[${timeStr}] ${msg}`);
  14.   }
  15.   // 模拟业务侧提取出的回调函数,防止匿名函数导致无法精准 off 卸载
  16.   private flashStateCallback = (state: number): void => {
  17.     let stateName = ['FLASH_STATE_UNAVAILABLE', 'FLASH_STATE_AVAILABLE', 'FLASH_STATE_READY'][state] || 'UNKNOWN';
  18.     this.appendLog(`收到底层 FlashState 回调变更 -> ${stateName}`);
  19.   }
  20.   subscribeFlashState(): void {
  21.     if (this.isSubscribed) {
  22.       this.appendLog('已经注册过闪光灯监听,请勿重复操作');
  23.       return;
  24.     }
  25.     this.appendLog('正在调用 PhotoSession.onFlashStateChange()...');
  26.     // 真实业务中: this.photoSession.onFlashStateChange(this.flashStateCallback);
  27.     // 这里模拟底层 C API 或 ISP 因光线变化触发回调的过程
  28.     this.mockIntervalId = setInterval(() => {
  29.       let randomState = Math.floor(Math.random() * 3);
  30.       this.flashStateCallback(randomState);
  31.     }, 2000);
  32.     this.isSubscribed = true;
  33.     this.appendLog('[ArkTS] 闪光灯状态订阅成功,同时 C API (OH_CaptureSession) 双端就绪。');
  34.   }
  35.   unsubscribeFlashState(): void {
  36.     if (!this.isSubscribed) return;
  37.     this.appendLog('正在调用 PhotoSession.offFlashStateChange()...');
  38.     // 真实业务中: this.photoSession.offFlashStateChange(this.flashStateCallback);
  39.     clearInterval(this.mockIntervalId);
  40.     this.isSubscribed = false;
  41.     this.appendLog('闪光灯状态回调已安全注销。');
  42.   }
  43.   aboutToDisappear() {
  44.     this.unsubscribeFlashState();
  45.   }
  46.   build() {
  47.     Column() {
  48.       // 头部区域与控制面板
  49.       // ...详见工程源码
  50.     }
  51.     .width('100%').height('100%').backgroundColor(Color.White)
  52.   }
  53. }
复制代码

三、避坑指南

1. 不要用匿名回调

取消订阅时,如果只想注销特定的回调函数,绝不能使用匿名函数。匿名函数每次声明的内存地址不同,底层引擎无法匹配到目标回调,注销失败后会形成难以排查的内存泄漏。正确做法是像上面的Demo一样,把回调提取为成员箭头函数引用。

2. 生命周期必须匹配

PhotoSession是重量级实例。如果在aboutToAppear或特定界面进入时注册了onFlashStateChange,必须在aboutToDisappear或相机资源释放前执行off卸载,否则会出现底层相机系统回调悬挂。

3. 注意C API与ArkTS的观察者边界

如果应用层使用ArkTS,渲染管线层又初始化了NDK的Camera_CaptureSession,两者是完全独立的观察者,状态改变会分别抛出。不要在两条链路之间做交叉状态写入,避免状态管理混乱。

四、总结

HarmonyOS 6.1.1的FlashState回调机制,补全了底层光线感应器与物理相机硬件向应用层通信的关键链路。配合严谨的订阅/注销管理和双通道选择,开发者可以在影像界面中实现毫秒级的光效反馈。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: 鸿蒙Camera Kit闪光灯状态监听与C API双端适配

看到鸿蒙在Camera Kit里补上闪光灯状态回调这块,确实比以前方便多了。以前只能轮询查询模式,没法及时感知底层开关状态的变迁,暗光环境自动闪光灯触发那一下,开发者只能靠猜,体验挺别扭的。 有个小问题想请教一下,FlashState的枚举值目前就是帖子里提到的UNAVAILABLE、AVAILABLE、READY这三种吗?还是说API 24里还有更细分的状态?另外,如果相机Session中途因为资源冲突被释放了,这个注册的callback会不会自动失效,还是需要在onDisconnect之类的回调里手动处理一下注销逻辑? 示例里用定时器模拟回调做闭环验证的思路挺实用的,对这个接口的开发调试应该很有帮助。期待楼主后续能分享一些真实设备上的表现,特别是在自动闪光灯那种场景下,回调的实时性怎么样。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: 鸿蒙Camera Kit闪光灯状态监听与C API双端适配

收藏了,正好在搞ArkTS的相机功能,之前为了查闪光灯状态只能轮询,又慢又费电。这个FlashState回调看着很实用,尤其是双端都支持这点很赞,我们Unity里嵌的C++管线也能直接用。 有个小问题想请教:示例里用了定时器模拟,但真实环境如果同时有ArkTS和C API两套监听,会不会出现重复回调?还是说底层做了统一分发?另外回调里拿到的FlashState具体是枚举还是普通数值?我看示例里是拿数字去映射的,不太确定真实API的返回类型。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: 鸿蒙Camera Kit闪光灯状态监听与C API双端适配

感谢楼主分享!这个闪光灯状态监听确实很实用,以前做暗光场景经常要轮询,现在有回调就省事多了。想问下,ArkTS层获取PhotoSession实例的代码大概是什么样?还有C API注册回调时,是不是需要自己维护session的上下文指针?期待后续能补充个完整示例。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-8-9 15:27 , Processed in 0.022226 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部