适配仓库: https://atomgit.com/oh-flutter/haptic_kit

适配分支: feat/ohos_haptic_kit_2.2.0

一、最终效果与适配目标

按钮轻触、支付确认、滑块越过刻度、操作失败提醒,这些场景都适合用短促触感帮助用户确认操作。haptic_kit 2.2.0 不只封装一次振动,还提供 impact、notification、selection、单次振动、波形、系统预设效果、自定义 pattern、取消播放和能力查询。上层还有一组把动画和触感组合起来的 Flutter Widget。

上游已经实现 Android 和 iOS,Dart 层通过 dev.erykkruk/haptic_kit 方法通道下发统一指令,但鸿蒙端原先没有接收者。本次目标是保留这些公开 API,在 OHOS 侧对接 @kit.SensorServiceKit,同时处理高清触感设备和普通振动设备的差异。

在这里插入图片描述

图 1:haptic_kit 签名 HAP 在鸿蒙真机上启动后的触感演示页。

验证点实测结果证据
静态检查最终提交上 flutter analyze 无问题图 4
Dart 契约63 项测试在适配提交 a0b7f07 通过图 4
取消竞态最终提交的 7 项 ArkTS 回归通过图 3、图 4
HAP 构建、签名、安装和启动最终提交可构建,真机 Demo 可启动图 1、图 5、图 6

成果速览

项目内容
上游基线TAG v2.2.0,提交 602b6c596b9364e59343ed1aa378e4eb085d2b4a,MIT
适配分支feat/ohos_haptic_kit_2.2.0
适配 TAG尚未发布
最终受测提交b6554f75bbd94b30ab5d34cc55d270570dfe8bd5
当前适配分支 HEADb6554f75bbd94b30ab5d34cc55d270570dfe8bd5
仓库默认 HEADmain602b6c596b9364e59343ed1aa378e4eb085d2b4a,不含 OHOS 适配
新增 OHOS 能力语义触感、单次振动、波形、预设、自定义 pattern、取消和能力查询
自动化证据63 项 Dart 测试在 a0b7f07 通过;最终提交另有 7 项 ArkTS 竞态回归
构建与真机最终提交静态检查和 HAP 构建通过,签名 HAP 可启动

二、本次实测环境

项目实际版本
Flutter OH3.41.10-ohos-1.0.1
Dart3.11.5
DevEco Studio26.0.0 Release
HarmonyOS SDKAPI 26,示例兼容 API 18
测试设备CHZ-AL00,HarmonyOS 7.0.0.105(SP10C00E105R2P4);物理振感待验收
目标库haptic_kit 2.2.0

环境安装直接参考 Flutter OH 环境搭建指南。截至 2026 年 9 月 12 日,版本号最大的 Flutter OH 标签是预览版 3.44.9+ohos-0.0.1-canary1,最新正式稳定标签仍是 3.41.10-ohos-1.0.1。本文保留真实参与构建和设备启动的稳定版,不把未完成同等验证的预览版写成实测环境。

三、代码仓库与适配分支

适配前,我核对了待适配、适配中、已适配清单和目标组织同名仓库。上游基线是标签 v2.2.0、提交 602b6c596b9364e59343ed1aa378e4eb085d2b4a。AtomGit 仓库保留了这段历史,适配分支由该提交创建。

git clone https://atomgit.com/oh-flutter/haptic_kit.git
cd haptic_kit
git switch feat/ohos_haptic_kit_2.2.0
git branch --show-current

如果从基线复现分支和 OHOS 骨架,可在干净工作区执行:

git switch -c feat/ohos_haptic_kit_2.2.0 602b6c596b9364e59343ed1aa378e4eb085d2b4a
flutter create --template=plugin --platforms=ohos --no-pub .

第二条命令只生成工程结构。实际实现还包括 ohos/index.ets、HAR 配置、权限、插件类、示例 OHOS 工程和测试。图 2 汇总了实际 AtomGit origin、适配分支和 HEAD,可核对仓库来源与当前分支状态。

四、先读清楚原有通道

Dart 层把所有原生调用集中在一个通道中。播放类调用会先检查应用级开关,取消和能力查询即使关闭触感也会继续下发,因为“停止正在播放的效果”和“读取设备能力”不属于新播放。

await Haptics.impact(HapticImpactStyle.medium);
await Vibration.vibrate(duration: const Duration(milliseconds: 300));
await Vibration.playPredefined(PredefinedEffect.doubleClick);
await Vibration.cancel();

final capabilities = await HapticCapabilities.query();

OHOS 端必须接住 haptic.impacthaptic.notificationhaptic.selectionhaptic.preparevibration.oneShotvibration.waveformvibration.predefinedvibration.cancelpattern.playcapabilities.query。方法名或参数键只要有一个不一致,Dart API 就会在运行期失败。

五、补全 OHOS 原生实现

先在 pubspec.yaml 注册插件入口,并在 HAR 的 module.json5 声明 ohos.permission.VIBRATE

flutter:
  plugin:
    platforms:
      ohos:
        pluginClass: HapticKitPlugin

核心分发位于 HapticKitPlugin.ets。语义触感会映射到鸿蒙预设效果;单次振动可以传时长和幅度;波形及自定义 pattern 在支持高清触感时使用 VibratorPatternBuilder,否则按时间轴调度普通振动。

case 'vibration.oneShot':
  await this.playOneShot(
    this.requireNumber(call, 'durationMs'),
    this.optionalNumber(call, 'amplitude'),
  );
  result.success(null);
  return;
case 'vibration.cancel':
  await this.cancelPlayback();
  result.success(null);
  return;

这里不能把所有设备都当成支持幅度控制。实现先查询 HD Haptics 能力,支持时构建带 intensity 的 pattern;不支持时退化为时长振动。连续事件超过 5000 毫秒还会拆段,避免超过系统单个 continuous event 的限制。

取消逻辑是这次最值得记录的细节。早期实现先等待预设能力查询,再启动振动。如果查询尚未返回时调用 cancel(),旧请求仍可能在查询结束后重新启动。修复提交 b6554f75bbd94b30ab5d34cc55d270570dfe8bd5 保存了播放代次,异步查询返回后再次比较:

this.beginPlayback();
const generation = this.playbackGeneration;
const supported = await this.isPresetSupported(effectId);
if (generation !== this.playbackGeneration) {
  return;
}

这样,取消、引擎解绑或新播放都会让旧代次失效,晚到的查询结果不能复活已经取消的触感。

在这里插入图片描述

图 2:AtomGit origin、适配分支和当前 HEAD 的实际 Git 核验结果。

在这里插入图片描述

图 3:能力查询期间的代次校验、预置效果与时长降级路径。

六、仓库交付文件

本分支保留 MIT LICENSE 和上游 Git 历史,补充了 README.OpenSource、OHOS 说明、CHANGELOG.mdpubspec.yaml 平台声明、ohos/ HAR、example/ohos/ 与取消竞态测试。完整实现提交是 a0b7f07ca510d9e29310ce411754fe9585e4e091,随后 b6554f7 只修正 ArkTS 取消竞态并补回归说明。

签名证书、口令、本机 SDK 路径、依赖缓存和构建产物均不应提交。宿主应用若没有自动合并 HAR 权限,还要在宿主清单中声明 ohos.permission.VIBRATE

七、测试与构建结果

flutter analyze
flutter test
npm install --prefix ohos --no-save --no-package-lock typescript@5.9.3
node --test ohos/test/haptic_kit_cancellation.test.cjs
cd example
flutter build hap --debug --no-codesign

适配提交 a0b7f07 对应的 63 项 Dart 测试通过。竞态修复后的生产 ArkTS 源码又通过 7 项取消回归,覆盖预设支持、不支持、查询失败、引擎解绑和取消后重新播放;b6554f7 的无签名 HAP 也构建成功。2026 年 9 月 11 日在最终 b6554f7 上复跑 flutter analyze,结果为 No issues found。修复后没有重新执行 63 项 Dart 测试,因此文章必须分开写清受测提交,不能合并成“70 项都在最终提交上跑过”。

Node 测试只 mock Flutter 通道和系统 vibrator 边界,不能证明手机真的产生了正确振感。

在这里插入图片描述

图 4:2026 年 9 月 11 日复跑的 Flutter 检查、63 项 Dart 测试与已保存的 ArkTS 回归统计。

在这里插入图片描述

图 5:已安装的签名 HAP 元数据、摘要和源码 HEAD。

八、Demo 通过固定提交引入

dependencies:
  haptic_kit:
    git:
      url: https://atomgit.com/oh-flutter/haptic_kit.git
      ref: b6554f75bbd94b30ab5d34cc55d270570dfe8bd5

执行 flutter pub get 后,应在 pubspec.lock 中确认 resolved-ref 等于上述完整 SHA。当前没有适配 TAG,业务依赖不应长期指向会移动的分支。

示例应至少提供轻、中、重 impact,一次振动、波形、预设效果、循环 pattern、能力查询和取消按钮。播放前先检查 HapticSettings.isAvailable,页面释放时调用 Vibration.cancel()。幅度和 sharpness 是设备能力,不应保证每台手机都能呈现完全相同的手感。

当前缺少最后一层物理验收。真机测试要逐项记录“是否有振感、相对强弱、时序、取消是否立即停止、重复波形是否会在取消后复活”,并在一台支持 HD Haptics 和一台仅支持普通振动的设备上分别验证。录屏无法记录振感,需保留 Demo 状态、系统能力查询和操作者签字记录,不能用构建成功替代。

在这里插入图片描述

图 6:真机启动与物理振感验收状态;截图不代替操作者的振感确认。

九、提交与远端状态

git status --short
git add pubspec.yaml ohos example README.md README.OpenSource CHANGELOG.md
git commit -m "feat(ohos): adapt haptic_kit 2.2.0 for HarmonyOS"
git push -u origin feat/ohos_haptic_kit_2.2.0

2026 年 9 月 12 日匿名核对时,远端适配分支 HEAD 为 b6554f75bbd94b30ab5d34cc55d270570dfe8bd5,而仓库默认 HEAD 仍是 main 的上游基线 602b6c596b9364e59343ed1aa378e4eb085d2b4a。因此查看源码时要进入适配分支,业务接入则直接锁定受测 SHA;只克隆默认分支会得到不含 OHOS 实现的代码。

十、FAQ

Q1:点击后没有振动,但方法没有报错

  • 现象: Dart 调用完成,设备没有明显反馈。
  • 原因: 应用级开关关闭、设备无振动器、权限未合并,或设备不支持请求的高清 pattern。
  • 解决方法: 检查 HapticSettings.enabled、能力查询和最终 HAP 权限;对非 HD 设备使用 fallback。
  • 验证结果: 自动化已覆盖能力分支;物理结果仍待真机补证。

Q2:调用 cancel 后又振了一下

  • 现象: 能力查询较慢时,取消后旧预设仍启动。
  • 原因: 异步查询返回前没有核对播放代次。
  • 解决方法: 使用 playbackGeneration 屏蔽已经取消或解绑的请求。
  • 验证结果: 最终 ArkTS 源码的 7 项竞态回归全部通过。

Q3:为什么 prepare() 在鸿蒙返回 false

  • 现象: 调用成功但返回 false
  • 原因: 这是 iOS 预热触感生成器的语义,OHOS 没有对应的必要操作。
  • 解决方法:false 视为无需预热,不视为振动不可用;能力应通过 HapticCapabilities.query() 判断。
  • 验证结果: 通道保持上游返回类型,没有伪造预热成功。

十一、总结

这次适配保留了 haptic_kit 2.2.0 的 Dart API,在 OHOS 端补齐语义触感、单次振动、波形、预设、自定义 pattern、取消和能力查询,并为普通设备提供时长 fallback。自动化、HAP 和匿名 AtomGit 读取已过关,取消竞态也有针对最终源码的回归证据;剩下的发布阻塞只有操作者的物理振感验收。

十二、参考链接

欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐