Flutter/OpenHarmony 三方库适配实战:tuya_home_flutter_plugin家庭通道

一、项目信息

项目内容
仓库名称tuya_home_flutter_plugin
Dart 包名tuya_home_sdk_flutter
AtomGit 仓库地址https://atomgit.com/oh-flutter/tuya_home_flutter_plugin
上游适配版本0.0.1
OHOS 适配版本0.0.1-ohos.1
方法通道tuya_home_sdk_flutter
事件通道DPS、设备发现、Wi-Fi 发现各一条
OHOS 原生入口TuyaHomeSdkFlutterPlugin
示例包名com.example.tuya_home_sdk_flutter_example
HAP 产物example/build/ohos/hap/entry-default-unsigned.hap
当前状态本地已完成分析、测试、构建和模拟器启动验证,目标仓库已创建

任务名称使用 tuya_home_flutter_plugin_ohos,但 pubspec.yaml 的包名
必须保持上游真实名称 tuya_home_sdk_flutter。改包名会破坏所有 import 和
依赖解析,因此只在仓库命名层区分。

目标 AtomGit 仓库已创建,适配代码将提交到 main 分支。

二、为什么不能直接“把方法都返回 true”

上游 Dart 层覆盖了大量家庭业务:

账号      注册、登录、验证码、密码重置、用户资料
家庭      创建、更新、删除、查询、Token
房间      创建、更新、删除、查询
设备      查询、删除、重命名、DPS 下发
配网      BLE+Wi-Fi、Wi-Fi、有线、子设备
成员      添加、查询、删除、修改
邀请      加入、取消、接受/拒绝、查询、修改
事件      设备 DPS、设备发现、Wi-Fi 设备发现

这些方法背后依赖涂鸦账号服务、家庭服务、配网协议和设备事件服务。当前
OpenHarmony 没有可验证的对应原生 SDK。如果 OHOS 插件把所有方法都返回
true,调用方会认为家庭和设备已经创建,随后却拿不到任何真实数据,错误
会扩散到数据库、UI 和业务状态机。

本次选择的边界是:

  1. 完整保留 Dart API 和通道名,方便未来接入 SDK。
  2. OHOS 实现平台版本和适配版本查询。
  3. 其他方法返回 tuya_home_unsupported。
  4. 三个 EventChannel 主动返回 unsupported,不伪造事件。

三、上游通道契约

Dart 单例固定使用一条方法通道:

class TuyaHomeSdkFlutter {
  final methodChannel =
      const MethodChannel('tuya_home_sdk_flutter');

  static TuyaHomeSdkFlutter get instance {
    return _singleton ??= TuyaHomeSdkFlutter._();
  }

另外还有三条事件通道:

final _deviceEvent = const EventChannel(
  'tuya_home_sdk_flutter_device_dps_event',
);

final _deviceDiscoveryEvent = const EventChannel(
  'tuya_home_sdk_flutter_device_discovery_event',
);

final EventChannel _wifiEvent = const EventChannel(
  'tuya_home_sdk_flutter_wifi_discovery_event',
);

这意味着 OHOS 适配至少要注册四条通道。只注册 MethodChannel 时,账号和
家庭方法会得到错误,但三个流可能表现为“永远没有数据”,业务很难区分
“无设备”和“原生流没有实现”。

四、让 Flutter OHOS 发现插件

根 pubspec.yaml:

name: tuya_home_sdk_flutter
version: 0.0.1-ohos.1

flutter:
  plugin:
    platforms:
      android:
        package: com.example.tuya_home_sdk_flutter
        pluginClass: TuyaHomeSdkFlutterPlugin
      ios:
        pluginClass: TuyaHomeSdkFlutterPlugin
      ohos:
        pluginClass: TuyaHomeSdkFlutterPlugin

OHOS HAR 的 hvigorfile.ts:

import { harTasks } from '@ohos/hvigor-ohos-plugin';

export default {
  system: harTasks,
  plugins: [],
};

index.ets:

import TuyaHomeSdkFlutterPlugin
  from './src/main/ets/components/plugin/TuyaHomeSdkFlutterPlugin';

export default TuyaHomeSdkFlutterPlugin;

oh-package.json5 将模块类型约束为 HAR:

{
  "module": {
    "name": "tuya_home_sdk_flutter",
    "type": "har",
    "deviceTypes": ["default", "tablet"]
  }
}

五、ArkTS 注册一条方法通道和三条事件通道

插件实现 FlutterPlugin、MethodCallHandler 和 StreamHandler:

export default class TuyaHomeSdkFlutterPlugin
  implements FlutterPlugin, MethodCallHandler, StreamHandler {
  private methodChannel: MethodChannel | null = null;
  private deviceDpsChannel: EventChannel | null = null;
  private discoveryChannel: EventChannel | null = null;
  private wifiChannel: EventChannel | null = null;

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.methodChannel = new MethodChannel(
      binding.getBinaryMessenger(),
      'tuya_home_sdk_flutter',
    );
  }

实际实现中 MethodChannel 和 EventChannel 分别创建。注册完成后,方法调用
入口只开放两个已验证分支:

onMethodCall(call: MethodCall, result: MethodResult): void {
  switch (call.method) {
    case 'getPlatformVersion':
      result.success('OHOS');
      return;
    case 'getSDKVersion':
      result.success(
        'tuya_home_sdk_flutter OHOS adapter 0.0.1-ohos.1',
      );
      return;
    default:
      result.error(
        'tuya_home_unsupported',
        `${call.method}: Tuya Home SDK is not available on OpenHarmony.`,
        null,
      );
      return;
  }
}

事件监听主动报错:

onListen(args: Any, events: EventSink): void {
  events.error(
    'tuya_home_unsupported',
    'Tuya Home SDK is not available on OpenHarmony.',
    null,
  );
}

引擎销毁时必须卸载三个流处理器:

onDetachedFromEngine(binding: FlutterPluginBinding): void {
  this.removeStreamHandlers();
  this.methodChannel?.setMethodCallHandler(null);
  this.methodChannel = null;
  this.deviceDpsChannel = null;
  this.discoveryChannel = null;
  this.wifiChannel = null;
}

如果不清理,Flutter Engine 重建后可能继续持有旧 handler,导致回调进入
已经销毁的 Dart isolate。

六、平台版本接口与业务单例

上游模板只在 platform interface 中实现 getPlatformVersion,但示例页面
直接使用 TuyaHomeSdkFlutter(),该构造函数并不存在。本次增加单例访问:

class TuyaHomeSdkFlutter {
  static TuyaHomeSdkFlutter? _singleton;

  static TuyaHomeSdkFlutter get instance {
    return _singleton ??= TuyaHomeSdkFlutter._();
  }

  Future<String?> getPlatformVersion() {
    return TuyaHomeSdkFlutterPlatform.instance
        .getPlatformVersion();
  }

示例改为:

final _tuyaHomeSdkFlutterPlugin =
    TuyaHomeSdkFlutter.instance;

final String platformVersion =
    await _tuyaHomeSdkFlutterPlugin.getPlatformVersion() ??
    'Unknown platform version';

这条修复让 OHOS 注册结果真正显示在示例页面,而不是停留在模板的
Unknown。

七、同步修复上游 Dart 问题

适配时处理了几个与 OHOS 运行相关的问题:

1. 房间匹配错误

// 修改前
if (room == roomId) {
  return room;
}

// 修改后
if (room.id == roomId) {
  return room;
}

原写法比较的是模型对象和整数 ID,条件永远不可靠。

2. 无效的空值合并

// 移除无意义的 ?? null
schemaModel.toJson();

3. 清理不必要 import

多个模型文件删除未使用 import,避免 flutter analyze 产生噪声。

4. 示例构造函数修复

将不存在的 TuyaHomeSdkFlutter() 改为
TuyaHomeSdkFlutter.instance。

这些修复不等于实现了涂鸦业务,但它们保证插件注册、版本查询和示例页面
是真实可运行的。

八、业务 API 的 OHOS 行为

API 分组上游示例OHOS 当前行为
getPlatformVersion查询平台成功返回 OHOS
initSdk初始化涂鸦 SDKtuya_home_unsupported
注册、登录、验证码账号服务tuya_home_unsupported
家庭、房间、成员、邀请家庭服务tuya_home_unsupported
设备查询、删除、重命名设备服务tuya_home_unsupported
配网四类接口配网协议tuya_home_unsupported
DPS 下发设备控制tuya_home_unsupported
三个事件流原生事件Stream 错误返回 unsupported

业务端可以统一处理:

Future<T> runTuyaAction<T>(
  Future<T> Function() action,
) async {
  try {
    return await action();
  } on PlatformException catch (error) {
    if (error.code == 'tuya_home_unsupported') {
      throw UnsupportedError(
        '当前 OpenHarmony 版本尚未接入 Tuya Home SDK',
      );
    }
    rethrow;
  }
}

这样既能保留上游调用,也不会把“未实现”误判为“业务返回 false”。

九、示例页面与真实截图

示例通过平台版本调用验证插件注册:


Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      appBar: AppBar(title: const Text('Plugin example app')),
      body: Center(
        child: Text('Running on: $_platformVersion\n'),
      ),
    ),
  );
}

模拟器真实截图:

在这里插入图片描述

图 1:OpenHarmony 模拟器上的 tuya_home_sdk_flutter 示例。首屏已完成
渲染,插件版本查询结果由 MethodChannel 返回。

截图只用于证明插件注册和 Dart 页面运行,不表示涂鸦家庭业务已经接通。

十、HAP 构建与自动化测试

核心命令:

flutter analyze
flutter test
cd example
flutter analyze
flutter test
flutter build hap --debug --no-codesign

结果:

检查项结果
根包 analyze通过,No issues found
根包测试通过
示例 analyze通过,No issues found
示例测试通过
HAP 构建通过
产物entry-default-unsigned.hap

模拟器安装:

hdc install -r \
  example/build/ohos/hap/entry-default-unsigned.hap
hdc shell aa start \
  -a EntryAbility \
  -b com.example.tuya_home_sdk_flutter_example

最终真实日志:

install bundle successfully.
start ability successfully.
20020081 4284 ... com.example.tuya_home_sdk_flutter_example
10-19 01:08:27.595 4284 4284 D ... Flutter:
FlutterNapi --> called onFirstFrame isPreload:0

进程 4284 完成首帧并稳定存活。

十一、LowMemoryKill 不是插件崩溃

验证过程中,多个 Flutter 示例同时驻留时,系统出现:

reason=LowMemoryKill
exit with signal:9

该事件的特点:

  • 没有新增该应用的 cppcrash 文件。
  • 日志由 memmgrservice 明确标记为 LowMemoryKill。
  • 4 GB 模拟器同时运行多个 Flutter 示例时更容易触发。

处理方式:

hdc shell aa force-stop com.example.jpush_example
hdc shell aa force-stop io.openinstall.openinstall_flutter_plugin_example
hdc shell reboot

重启模拟器后卸载旧包、单独安装 Tuya 示例,再启动并验证 onFirstFrame。
这个问题与 ArkTS 空指针、SIGSEGV 或插件异常不同,不能混为一类。

十二、接入真实 OHOS SDK 前的工程准备

未来接入涂鸦 SDK 时,应按以下顺序推进:

  1. 确认涂鸦提供 OpenHarmony Home SDK、版本、协议和包管理方式。
  2. 在 ohos/oh-package.json5 中固定真实 SDK 依赖。
  3. 先实现 initSDK,验证 appKey、appSecret 和错误码。
  4. 再实现登录与用户信息,确认账号区域和验证码服务。
  5. 实现家庭和房间查询,验证模型 JSON 转换。
  6. 实现设备查询和 DPS,验证真实设备。
  7. 实现配网与三个 EventChannel,验证蓝牙、Wi-Fi 权限和生命周期。
  8. 最后补真机截图、设备日志和失败用例。

不能先批量把 switch 分支改成 result.success(true),否则后续 SDK 接入
时无法区分旧假成功和真实服务结果。

十三、目录结构

tuya_home_flutter_plugin_ohos/
├── lib/
│   ├── tuya_home_sdk_flutter.dart
│   ├── tuya_home_sdk_flutter_method_channel.dart
│   ├── tuya_home_sdk_flutter_platform_interface.dart
│   └── src/
│       ├── models/
│       └── tuya_home_sdk_flutter.dart
├── ohos/
│   ├── build-profile.json5
│   ├── hvigorfile.ts
│   ├── index.ets
│   └── src/main/ets/components/plugin/
│       └── TuyaHomeSdkFlutterPlugin.ets
├── example/
│   ├── lib/main.dart
│   └── ohos/
├── test/tuya_home_sdk_flutter_test.dart
├── photos/tuya_home_ohos.jpeg
├── verification.md
├── CHANGELOG.md
└── README.md

十四、总结

这次适配把一个大体量 Dart SDK 拆成了清晰的工程事实:

完整 Dart API 和模型
          |
          v
一条 MethodChannel + 三条 EventChannel
          |
          v
OHOS 插件注册和生命周期
          |
          +--> 可验证:平台版本、适配版本
          +--> 暂不可验证:家庭业务和事件
          |
          v
analyze + test + HAP + 首帧 + 进程存活

适配完成的标准不是所有按钮都返回成功,而是工程可运行、通道可诊断、能力
边界真实、后续 SDK 接入路径明确。

仓库名称:tuya_home_flutter_plugin

仓库地址:https://atomgit.com/oh-flutter/tuya_home_flutter_plugin

欢迎加入 CPF-Flutter 社区,一起交流
Flutter 三方库 OpenHarmony 适配、家庭设备服务和 EventChannel 验证经验:
https://atomgit.com/CPF-Flutter

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐