鸿蒙版Flutter库torch_light手电筒功能深度适配

鸿蒙版Flutter库torch_light手电筒功能深度适配:跨平台开发者的光明之路

本项目作者:kirk/坚果

适配仓库地址

作者仓库:https://github.com/svprdga/torch_light#

在数字化浪潮的推动下,跨平台开发框架如 Flutter 凭借其高效、便捷的特性,成为了开发者们的宠儿。而鸿蒙系统的崛起,更是为跨平台开发注入了新的活力。为了助力开发者在鸿蒙生态中快速实现 torch_light来处理设备手电筒的插件功能,本文将深入浅出地为大家解析如何适配 torch_light 三方库至鸿蒙平台。

一、适配鸿蒙版 torch_light 三方库

(一)版本选择与仓库简介

我们先去 pub 上查看最新版本,我们选择以 0.0.10版本为基础进行适配。torch_light 是一个简单的 Flutter 插件来处理设备手电筒的插件,其 GitHub 仓库为https://github.com/svprdga/torch_light#,我们的目标是将这个插件适配到鸿蒙平台。

(二)引入背景与使用场景

在 OpenHarmony 北向生态的发展过程中,许多已经适配了 Flutter 的厂商在接入 OpenHarmony 时,都希望能够继续使用 torch_light 来实现手电筒功能。因此,我们提供了这个适配方案,采用插件化的适配器模式,帮助生态伙伴快速实现产品化。

本方案适用于已经支持 Flutter 框架的设备在移植到 OpenHarmony 系统过程中,作为一个备选方案。

(三)使用文档与插件库使用

适配 OpenHarmony 平台的详细使用指导可以参考:Flutter使用指导文档

在项目中使用该插件库时,只需在 pubspec.yaml 文件的 dependencies 中新增如下配置:

yaml 复制代码
dependencies:
  torch_light:
    git:
      url: "[email protected]:nutpi/flutter_torch_light.git"
      path: ""

然后在项目根目录运行 flutter pub get,即可完成依赖添加

接下来是具体的适配过程。

二、适配过程详解

(一)准备工作

确保已经配置好了 Flutter 开发环境,具体可参考 Flutter 配置指南。同时,从 官方插件库 下载待适配的三方插件。本指导书, 以适配 torch_light 为例

(二)插件目录结构

下载并解压插件后,我们会看到以下目录结构:

  • lib :对接 Dart 端代码的入口,由此文件接收到参数后,通过 channel 将数据发送到原生端。
  • android :安卓端代码实现目录。
  • ios :iOS 原生端实现目录。
  • example :一个依赖于该插件的 Flutter 应用程序,用于说明如何使用它。
  • README.md :介绍包的文件。
  • CHANGELOG.md :记录每个版本中的更改。
  • LICENSE :包含软件包许可条款的文件。

(三)创建插件的鸿蒙模块

在插件目录下,打开 Terminal,执行以下命令来创建一个鸿蒙平台的 Flutter 模块:

复制代码
flutter create . --org com.svprdga.torchlight --template=plugin --platforms=ohos

步骤:

  1. 用vscode/trae打开刚刚下载好的插件。

  2. 打开Terminal,cd到插件目录下。

  3. 执行命令flutter create . --template=plugin --platforms=ohos 创建一个ohos平台的flutter模块。

第一个问题,修改sdk的版本,适配旧版本。

我们做好修改就好。

(四)在根目录下添加鸿蒙平台配置

在项目根目录的 pubspec.yaml 文件中,添加鸿蒙平台的相关配置:

yaml 复制代码
name: torch_light
description: A Flutter plugin to check if the device has a torch / flashlight, and to turn it on and off.
version: 1.1.0
homepage: https://davidserrano.io/
repository: https://github.com/svprdga/torch_light

environment:
  sdk: ">=2.17.5 <4.0.0"
  flutter: ">=2.3.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  lint: 2.3.0

flutter:
  plugin:
    platforms:
      android:
        package: com.svprdga.torchlight
        pluginClass: TorchLightPlugin
      ios:
        pluginClass: TorchLightPlugin
      ohos:
        package: com.svprdga.torchlight
        pluginClass: TorchLightPlugin

(五)编写鸿蒙插件的原生 ArkTS模块

1. 创建鸿蒙插件模块

使用 DevEco Studio 打开鸿蒙项目。

2. 修改相关配置文件

ohos 目录内的 oh-package.json5 文件中添加 libs/flutter.har 依赖,并创建 .gitignore 文件,添加以下内容以忽略 libs 目录:

json 复制代码
/node_modules
/oh_modules
/local.properties
/.preview
/.idea
/build
/libs
*.har
/.cxx
/.test
/BuildProfile.ets
/oh-package-lock.json5

oh-package.json5 文件内容如下:

json 复制代码
{
  "name": "torch_light",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "index.ets",
  "author": "",
  "license": "Apache-2.0",
  "dependencies": {
    "@ohos/flutter_ohos": "file:./har/flutter.har"
  }
}

ohos 目录下创建 index.ets 文件,导出配置:

js 复制代码
import TorchLightPlugin from './src/main/ets/components/plugin/TorchLightPlugin';
export default TorchLightPlugin;
3. 编写 ETS 代码

文件结构和代码逻辑可以参考安卓或 iOS 的实现,鸿蒙的 API 文档可以参考 :https://gitcode.com/openharmony-sig/flutter_packages/tree/master/packages/path_provider/path_provider_android

ohos的api可以参考:https://gitcode.com/openharmony/docs

以下是 TorchLightPlugin.ets 文件的代码示例:

js 复制代码
  private channel: MethodChannel | null = null;
  private nativeEventIsTorchAvailable: string = "torch_available";
  private errorIsTorchAvailable: string = "torch_available_error";

  private nativeEventEnableTorch: string = "enable_torch";
  private errorEnableTorchExistentUser: string = "enable_torch_error_existent_user";
  private errorEnableTorch: string = "enable_torch_error";
  private errorEnableTorchNotAvailable: string = "enable_torch_not_available";

  private nativeEventDisableTorch: string = "disable_torch";
  private errorDisableTorchExistentUser: string = "disable_torch_error_existent_user";
  private errorDisableTorch: string = "disable_torch_error";
  private errorDisableTorchNotAvailable: string = "disable_torch_not_available";

这里我主要参考的是

三、手电筒使用

手电筒模式的使用是通过操作手机启用手电筒功能,使设备的手电筒功能持续保持常亮状态。

在使用相机应用并操作手电筒功能时,存在以下几种情况说明:

  • 当使用后置摄像头并设置闪光灯模式FlashMode关闭时,手电筒功能无法启用。
  • 当使用前置摄像头时,手电筒可以正常启用并保持常亮状态。
  • 从前置摄像头切换至后置摄像头时,如果手电筒原本处于开启状态,它将会被自动关闭。

详情请参考Camera API参考

开发步骤

导入camera接口,接口中提供了相机相关的属性和方法,导入方法如下。

typescript 复制代码
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';

通过CameraManager类中的isTorchSupported方法,检测当前设备是否支持手电筒功能。

typescript 复制代码
function isTorchSupported(cameraManager: camera.CameraManager) : boolean {
    let torchSupport: boolean = false;
    try {
        torchSupport = cameraManager.isTorchSupported();
    } catch (error) {
        let err = error as BusinessError;
        console.error('Failed to torch. errorCode = ' + err.code);
    }
    console.info('Returned with the torch support status:' + torchSupport);
    return torchSupport;
}

通过CameraManager类中的isTorchModeSupported方法,检测是否支持指定的手电筒模式TorchMode

typescript 复制代码
function isTorchModeSupported(cameraManager: camera.CameraManager, torchMode: camera.TorchMode) : boolean {
    let isTorchModeSupport: boolean = false;
    try {
        isTorchModeSupport = cameraManager.isTorchModeSupported(torchMode);
    } catch (error) {
        let err = error as BusinessError;
        console.error('Failed to set the torch mode. errorCode = ' + err.code);
    }
    return isTorchModeSupport;
}

通过CameraManager类中的setTorchMode方法,设置当前设备的手电筒模式。以及通过CameraManager类中的getTorchMode方法,获取当前设备的手电筒模式。

在使用getTorchMode方法前,需要先注册监听手电筒的状态变化,请参考状态监听

typescript 复制代码
function setTorchModeSupported(cameraManager: camera.CameraManager, torchMode: camera.TorchMode) : void {
    cameraManager.setTorchMode(torchMode);
    let isTorchMode = cameraManager.getTorchMode();
    console.info(`Returned with the torch mode supportd mode: ${isTorchMode}`);
}

状态监听

在相机应用开发过程中,可以随时监听手电筒状态,包括手电筒打开、手电筒关闭、手电筒不可用、手电筒恢复可用。手电筒状态发生变化,可通过回调函数获取手电筒模式的变化。

通过注册torchStatusChange事件,通过回调返回监听结果,callback返回TorchStatusInfo参数,参数的具体内容可参考相机管理器回调接口实例TorchStatusInfo

typescript 复制代码
function onTorchStatusChange(cameraManager: camera.CameraManager): void {
    cameraManager.on('torchStatusChange', (err: BusinessError, torchStatusInfo: camera.TorchStatusInfo) => {
        if (err !== undefined && err.code !== 0) {
            console.error(`Callback Error, errorCode: ${err.code}`);
            return;
        }
        console.info(`onTorchStatusChange, isTorchAvailable: ${torchStatusInfo.isTorchAvailable}, isTorchActive: ${torchStatusInfo.
            isTorchActive}, level: ${torchStatusInfo.torchLevel}`);
    });
}

完整的代码

typescript 复制代码
import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult,
} from '@ohos/flutter_ohos';
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';

/** TorchLightPlugin **/
export default class TorchLightPlugin implements FlutterPlugin, MethodCallHandler {
  private channel: MethodChannel | null = null;
  private channelName = "com.svprdga.torchlight/main";
  private NATIVE_EVENT_TORCH_AVAILABLE = "torch_available";

  private NATIVE_EVENT_ENABLE_TORCH = "enable_torch";
  private NATIVE_EVENT_DISABLE_TORCH = "disable_torch";

  private cameraManager: camera.CameraManager | undefined = undefined;
  constructor() {
  }

  getUniqueClassName(): string {
    return "TorchLightPlugin"
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(binding.getBinaryMessenger(), this.channelName);
    this.channel.setMethodCallHandler(this)
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    if (this.channel != null) {
      this.channel.setMethodCallHandler(null)
    }
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    this.cameraManager=camera.getCameraManager(getContext());
    switch (call.method) {
      case this.NATIVE_EVENT_TORCH_AVAILABLE : this.isTorchAvailable(result);      break;
      case this.NATIVE_EVENT_ENABLE_TORCH :  this.enableTorch(result);      break;
      case this.NATIVE_EVENT_DISABLE_TORCH :  this.disableTorch(result);      break;
    }
  }
  //检查设备是否有可用的手电筒
  isTorchAvailable(result: MethodResult){
    if(this.cameraManager!==null){
      registerTorchStatusChange(this.cameraManager!)
    }
    result.success(this.cameraManager!==null?isTorchSupported(this.cameraManager!):false);
  }


  //启用手电筒
  enableTorch(result: MethodResult){
    if(this.cameraManager!==null){
      if(isTorchSupported(this.cameraManager!)&&isTorchModeSupported(this.cameraManager!,camera.TorchMode.ON)){
        setTorchMode(this.cameraManager!,camera.TorchMode.ON)
      }
    }
    result.success(null)
  }
  //禁用手电筒
  disableTorch(result: MethodResult){
    if(this.cameraManager!==null){
      if(isTorchSupported(this.cameraManager!)&&isTorchModeSupported(this.cameraManager!,camera.TorchMode.ON)){
        setTorchMode(this.cameraManager!,camera.TorchMode.OFF)
        unregisterTorchStatusChange(this.cameraManager!)
      }
    }
    result.success(null)
  }

}
///检测是否支持手电筒
function isTorchSupported(cameraManager: camera.CameraManager) : boolean {
  let torchSupport: boolean = false;
  try {
    torchSupport = cameraManager.isTorchSupported();
  } catch (error) {
    let err = error as BusinessError;
    console.error('Failed to torch. errorCode = ' + err.code);
  }
  console.info('Returned with the torch support status:' + torchSupport);
  return torchSupport;
}
///检测是否支持指定的手电筒模式TorchMode
function isTorchModeSupported(cameraManager: camera.CameraManager, torchMode: camera.TorchMode) : boolean {
  let isTorchModeSupport: boolean = false;
  try {
    isTorchModeSupport = cameraManager.isTorchModeSupported(torchMode);
  } catch (error) {
    let err = error as BusinessError;
    console.error('Failed to set the torch mode. errorCode = ' + err.code);
  }
  return isTorchModeSupport;
}
//返回设备当前手电筒模式
function getTorchMode(cameraManager: camera.CameraManager): camera.TorchMode | undefined {
  let torchMode: camera.TorchMode | undefined = undefined;
  torchMode = cameraManager.getTorchMode();
  return torchMode;
}

function onTorchStatusChange(cameraManager: camera.CameraManager): void {
  cameraManager.on('torchStatusChange', (err: BusinessError, torchStatusInfo: camera.TorchStatusInfo) => {
    if (err !== undefined && err.code !== 0) {
      console.error(`Callback Error, errorCode: ${err.code}`);
      return;
    }
    console.info(`onTorchStatusChange, isTorchAvailable: ${torchStatusInfo.isTorchAvailable}, isTorchActive: ${torchStatusInfo.
    isTorchActive}, level: ${torchStatusInfo.torchLevel}`);
  });
}
///设置手电筒模式
function setTorchMode(cameraManager: camera.CameraManager, torchMode: camera.TorchMode): void {
  try {
    cameraManager.setTorchMode(torchMode);
  } catch (error) {
    // 失败返回错误码error.code并处理
    let err = error as BusinessError;
    console.error(`The setTorchMode call failed. error code: ${err.code}`);
  }
}
function callback(err: BusinessError, torchStatusInfo: camera.TorchStatusInfo): void {
  if (err !== undefined && err.code !== 0) {
    console.error(`Callback Error, errorCode: ${err.code}`);
    return;
  }

  console.info(`onTorchStatusChange, isTorchAvailable: ${torchStatusInfo.isTorchAvailable}, isTorchActive: ${torchStatusInfo.isTorchActive}, level: ${torchStatusInfo.torchLevel}`);
}

function registerTorchStatusChange(cameraManager: camera.CameraManager): void {
  cameraManager.on('torchStatusChange', callback);
}
function unregisterTorchStatusChange(cameraManager: camera.CameraManager): void {
  cameraManager.off('torchStatusChange');
}

四、编写 Example

1. 创建 Example 应用

在插件根目录下创建一个名为 example 的文件夹,用于存放示例应用。在 example 文件夹中,创建一个鸿蒙平台的 Flutter 应用,用于验证插件功能。

2. 签名与运行

使用 Deveco Studio 打开 example > ohos 目录,单击 File > Project Structure > Project > Signing Configs,勾选 Automatically generate signature,等待自动签名完成。然后运行以下命令:

复制代码
flutter pub get

 flutter build hap --debug

如果应用正常启动,说明插件适配成功。如果没有,欢迎大家联系坚果派一起支持。

五、总结

通过以上步骤,我们成功地将 torch_light 三方库适配到了鸿蒙平台。这个过程涉及到了解插件的基本信息、配置开发环境、创建鸿蒙模块、编写原生代码以及测试验证等多个环节。希望这篇博客能够帮助到需要进行 torch_light 鸿蒙适配的开发者们,让大家在鸿蒙生态的开发中更加得心应手。

六、参考

  • 如何使用Flutter与OpenHarmony通信 FlutterChannel\](https://gitcode.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/04_development/如何使用Flutter与OpenHarmony通信 FlutterChannel.md)

  • 开发package
  • 开发plugin
  • 开发FFI plugin\](https://gitcode.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/04_development/开发FFI plugin.md)

  • 适配仓库地址
  • 手电筒
相关推荐
梁下轻语的秋缘3 小时前
OpenHarmony:开源操作系统重塑产业数字化底座
华为·开源
Robot2513 小时前
「华为」持续加码人形机器人赛道!
大数据·人工智能·科技·华为·机器人·自动驾驶
特立独行的猫a4 小时前
HarmonyOS NEXT应用开发实战:玩鸿蒙App客户端开发
华为·harmonyos
爱吃鱼的锅包肉5 小时前
记录一下flutter项目自己封窗的弹窗
前端·javascript·flutter
Frank学习路上5 小时前
【Flutter】创建BMI计算器应用并添加依赖和打包
前端·javascript·flutter
特立独行的猫a8 小时前
鸿蒙HarmonyOS最新的组件间通信的装饰器与状态组件详解
华为·harmonyos
HarmonyOS_SDK10 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 —Live View Kit (3)
harmonyos
初遇你时动了情10 小时前
flutter长列表 ListView、GridView、SingleChildScrollView、CustomScrollView区别
前端·javascript·flutter
ONETHING_CLOUD_211 小时前
华为鸿蒙电脑发布,折叠屏怎么选?
经验分享·华为·电脑·harmonyos·数码