HarmonyOS鸿蒙Next中Flutter框架多设备开发指导-人脸识别场景

HarmonyOS鸿蒙Next中Flutter框架多设备开发指导-人脸识别场景

1.1 场景概述

在移动应用开发中,不同设备的屏幕形态各异,例如刘海屏、全面屏、折叠屏等,系统状态栏、导航栏、软键盘等元素亦会占据屏幕空间。人脸检测类界面通常需要在页面上持续展示检测状态、启动/停止控制与结果反馈,并在页面返回时安全释放检测流程;若事件监听与状态同步不完整,容易出现检测状态残留、UI 误报或返回后仍在检测的问题。本文将详细介绍本示例中原生人脸模块调用、事件回调状态联动、深浅色与检测态视觉反馈的适配方法,以及实现原理与具体场景案例。本文对应工程内人脸识别示例页。

1.1.1 使用场景

用户在人脸识别页中需要完成“开始检测—查看结果—停止检测/返回”闭环;页面应清晰反馈“未扫描到人脸 / 检测到人脸 / 检测失败”等状态。人脸识别适配验证(检测流程与状态界面协同自适应),指的是页面可在不同设备窗口下保持核心控件可见,并通过状态文案、圆形检测区颜色与按钮形态同步反映检测过程。下列表格展示不同横向断点下的逻辑与布局。

横向断点 sm md lg xl
展示逻辑 固定检测页结构:顶部返回 + 标题 + 中央圆形检测区 + 状态文案 + 开始/停止按钮 固定检测页结构:顶部返回 + 标题 + 中央圆形检测区 + 状态文案 + 开始/停止按钮 固定检测页结构:顶部返回 + 标题 + 中央圆形检测区 + 状态文案 + 开始/停止按钮 固定检测页结构:顶部返回 + 标题 + 中央圆形检测区 + 状态文案 + 开始/停止按钮
展示布局

1.1.2 常见问题

人脸识别类界面若未统筹,容易出现以下问题:

  • 启动检测后未监听原生事件,页面状态与实际检测结果不同步
  • 返回页面时未停止检测,导致资源未释放或状态残留
  • 检测成功/失败文案与视觉状态未联动,用户难以判断当前状态
  • 深浅色切换未适配,状态文本对比度不足

1.1.3 多设备适配

  • 适配点 1:启动时调用 FaceDetectionModule.startFaceDetection(),并通过 DeviceEventEmitter 监听 onFaceDetected 更新 faceDetected 与 detectionStatus。

图 1-0手机竖屏下人脸识别主界面。

图 1-0a手机端点击开始识别后的界面。

图 1-1md 档人脸识别界面。

图 1-2lg 档人脸识别界面。

  • 适配点 2:检测区域通过 faceDetected 切换样式:未检测时灰色圈(faceCircleInactive),检测到人脸时绿色圈(faceCircleActive);状态文本颜色同步切换。

图 2-0手机端识别成功后的状态反馈。

图 2-1PC 下提示“将设备旋转为竖屏”场景。

图 2-2PC 下设备检测失败场景。

  • 适配点 3:返回按钮 goBack 在 isDetecting 为真时先调用 stopFaceDetection(),再执行 navigation.goBack(),避免检测流程遗留。

1.2 开发指导

1.2.1 Flutter开发

1.2.1.1 关键能力

Flutter 人脸识别功能通过 MethodChannel 桥接 Flutter 端与 HarmonyOS 原生端,核心依赖 @kit.VisionKit 提供的 interactiveLiveness 活体检测 API。整体通信架构包含以下核心能力:

1.2.1.1.1 MethodChannel 通信通道

Flutter 端通过 MethodChannel 与原生端建立桥接,通道名为 com.facerecognition.ohos/faceRecognition。Flutter 端调用 invokeMethod(‘startDetection’, …) 发起人脸检测请求,原生端在 onMethodCall 中接收并分发处理。

static const MethodChannel _channel =
  MethodChannel('com.facerecognition.ohos/faceRecognition');

static Future<FaceRecognitionResult> startDetection({
  String isSilentMode = 'INTERACTIVE_MODE',
  int actionsNum = 0,
}) async {
  final result = await _channel.invokeMethod('startDetection', {
    'isSilentMode': isSilentMode,
    'actionsNum': actionsNum,
  });
  return FaceRecognitionResult.fromMap(result);
}
1.2.1.1.2 原生插件注册(FlutterPlugin)

原生端实现 FlutterPlugin 接口,在 onAttachedToEngine 中注册 MethodChannel 并绑定 MethodCallHandler,负责接收和响应 Flutter 端的方法调用。

onAttachedToEngine(binding: FlutterPluginBinding): void {
  this.channel = new MethodChannel(
    binding.getBinaryMessenger(),
    'com.facerecognition.ohos/faceRecognition',
    StandardMethodCodec.INSTANCE
  );
  this.channel.setMethodCallHandler(this);
}
1.2.1.1.3 相机权限申请

调用活体检测前,通过 abilityAccessCtrl.createAtManager().requestPermissionsFromUser() 动态申请 ohos.permission.CAMERA 权限,权限通过后才启动检测流程。

const atManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, ['ohos.permission.CAMERA'])
  .then((res) => {
    // 检查 authResults 判断是否授权
  });
1.2.1.1.4 活体检测调用(interactiveLiveness)

通过 @kit.VisionKit 的 interactiveLiveness.startLivenessDetection() 启动活体检测界面,检测完成后调用 getInteractiveLivenessResult() 获取结果并回传 Flutter 端。

const routerOptions: interactiveLiveness.InteractiveLivenessConfig = {
  isSilentMode: isSilentMode, // 交互模式 / 静默模式
  routeMode: 'push', // push 模式避免替换 Flutter 页面
  actionsNum: actionsNum // 动作数量
};

interactiveLiveness.startLivenessDetection(routerOptions).then(() => {
  interactiveLiveness.getInteractiveLivenessResult().then((data) => {
    resultMap.set('success', true);
    resultMap.set('livenessType', data.livenessType);
    result.success(resultMap);
  });
});
1.2.1.1.5 结果数据模型

Flutter 端定义 FaceRecognitionResult 数据类,统一封装检测结果(成功/失败、活体类型、错误码、错误信息),通过 fromMap 工厂方法从原生端返回的 Map 中解析。

1.2.1.2 指导案例

1.2.1.2.1 原生侧插件开发

步骤1:创建 FaceRecognitionPlugin

在 entryability 下创建 FaceRecognitionPlugin.ets,实现 FlutterPlugin 和 MethodCallHandler 接口:

import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/...';
import MethodChannel, { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/...';
import { interactiveLiveness } from '[@kit](/user/kit).VisionKit';

export class FaceRecognitionPlugin implements FlutterPlugin, MethodCallHandler {
  private channel: MethodChannel | null = null;
  private static uiAbilityContext: common.UIAbilityContext | null = null;

  // 由 EntryAbility 调用,传入上下文
  public static setUIAbilityContext(context: common.UIAbilityContext): void {
    FaceRecognitionPlugin.uiAbilityContext = context;
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(binding.getBinaryMessenger(),
      'com.facerecognition.ohos/faceRecognition', StandardMethodCodec.INSTANCE);
    this.channel.setMethodCallHandler(this);
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    if (call.method === 'startDetection') {
      this.handleStartDetection(call, result);
    } else {
      result.notImplemented();
    }
  }
}

步骤2:在 EntryAbility 中注册插件

在 EntryAbility.ets 的 configureFlutterEngine 中设置上下文并注册插件:

export default class EntryAbility extends FlutterAbility {
  configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine);
    FaceRecognitionPlugin.setUIAbilityContext(this.context);
    this.addPlugin(new FaceRecognitionPlugin());
  }
}

步骤3:实现权限申请 + 活体检测逻辑

在 handleStartDetection 方法中依次完成:

  1. 校验 UIAbilityContext 是否已设置
  2. 调用 requestPermissionsFromUser 申请相机权限
  3. 构建 InteractiveLivenessConfig 配置(检测模式、路由模式、动作数)
  4. 调用 startLivenessDetection() 启动检测
  5. 调用 getInteractiveLivenessResult() 获取结果
  6. 通过 result.success(resultMap) 将结果回传 Flutter 端

关键点:routeMode 须设为 ‘push’,避免活体检测页面替换 Flutter 页面导致白屏。

1.2.1.2.2 Flutter 端通信层开发

步骤1:定义结果数据类

在 face_recognition_channel.dart 中定义 FaceRecognitionResult:

class FaceRecognitionResult {
  final bool success;
  final int livenessType; // 0: 未检测, 1: 活体
  final int errorCode;
  final String errorMessage;

  factory FaceRecognitionResult.fromMap(Map<dynamic, dynamic> map) {
    return FaceRecognitionResult(
      success: map['success'] ?? false,
      livenessType: map['livenessType'] ?? 0,
      errorCode: map['errorCode'] ?? 0,
      errorMessage: map['errorMessage'] ?? '',
    );
  }
}

步骤2:封装 MethodChannel 调用

class FaceRecognitionChannel {
  static const MethodChannel _channel =
  MethodChannel('com.facerecognition.ohos/faceRecognition');

  static Future<FaceRecognitionResult> startDetection({
    String isSilentMode = 'INTERACTIVE_MODE',
    int actionsNum = 0,
  }) async {
    final result = await _channel.invokeMethod('startDetection', {
      'isSilentMode': isSilentMode,
      'actionsNum': actionsNum,
    });
    return FaceRecognitionResult.fromMap(result);
  }
}
1.2.1.2.3 Flutter 端 UI 页面开发

在 face_recognition_page.dart 中实现交互界面,核心逻辑:

  1. 状态管理:使用 _resultInfo(成功结果)、_failResult(失败结果)、_isDetecting(检测中状态)三个状态变量
  2. 调用检测:点击按钮后调用 FaceRecognitionChannel.startDetection(),根据返回结果更新 UI
  3. 响应式适配:通过 MediaQuery.of(context).size.width 获取屏幕宽度,根据断点(< 600 为小屏)调整间距等布局参数
  4. 检测中遮罩:检测进行时展示半透明遮罩 + 加载指示器,提示用户配合检测
Future<void> _startDetection() async {
  setState(() => _isDetecting = true);
  try {
    final result = await FaceRecognitionChannel.startDetection(
      isSilentMode: 'INTERACTIVE_MODE',
      actionsNum: 0,
    );
    setState(() {
      _isDetecting = false;
      if (result.success) {
        _resultInfo = result;
      } else {
        _failResult = {'code': result.errorCode, 'message': result.errorMessage};
      }
    });
  } catch (e) {
    setState(() {
      _isDetecting = false;
      _failResult = {'code': -1, 'message': e.toString()};
    });
  }
}

1.2.1.3 示例代码

人脸识别的Sample示例代码地址:example,开发者可以通过该地址查看完整的人脸识别示例代码,并根据自己的需求进行修改和扩展。


更多关于HarmonyOS鸿蒙Next中Flutter框架多设备开发指导-人脸识别场景的实战教程也可以访问 https://www.itying.com/category-92-b0.html

2 回复

在HarmonyOS Next中,使用Flutter进行多设备人脸识别开发,需通过Platform Channel调用鸿蒙原生人脸检测API(如使用端侧AI引擎)。多设备适配需处理相机预览尺寸、权限差异及不同屏幕分辨率。推荐使用Flutter插件封装原生能力,确保跨设备一致性。性能上需优化帧率和识别延迟,避免阻塞UI线程。

更多关于HarmonyOS鸿蒙Next中Flutter框架多设备开发指导-人脸识别场景的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在HarmonyOS Next的Flutter开发中,人脸识别场景的核心是多设备适配和状态协同。实现关键包括:

  • 通信桥接:通过MethodChannel(通道名com.facerecognition.ohos/faceRecognition)连接Flutter与原生,原生侧实现FlutterPluginMethodCallHandler,在onAttachedToEngine注册。
  • 权限与检测:原生端动态申请相机权限后,使用interactiveLiveness活体检测API,routeMode设为push避免覆盖Flutter页面。检测结果通过result.success回传。
  • 状态管理:Flutter端维护_isDetecting_resultInfo等状态变量,调用startDetection时更新UI,并展示检测中遮罩和结果反馈。
  • 适配方案:基于屏幕宽度断点(sm/md/lg/xl)调整布局,保持“返回+标题+圆形检测区+状态文案+按钮”的固定结构。
  • 资源释放:返回时若正在检测,先调用stopFaceDetectionnavigation.goBack,避免状态残留与资源泄漏。

这一设计解决了检测状态不同步、返回未停止检测等常见问题。

回到顶部