Flutter 鸿蒙插件适配实战:用 haptic_kit 2.2.0 接入触感反馈与振动控制
适配仓库: 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 |
| 当前适配分支 HEAD | b6554f75bbd94b30ab5d34cc55d270570dfe8bd5 |
| 仓库默认 HEAD | main 的 602b6c596b9364e59343ed1aa378e4eb085d2b4a,不含 OHOS 适配 |
| 新增 OHOS 能力 | 语义触感、单次振动、波形、预设、自定义 pattern、取消和能力查询 |
| 自动化证据 | 63 项 Dart 测试在 a0b7f07 通过;最终提交另有 7 项 ArkTS 竞态回归 |
| 构建与真机 | 最终提交静态检查和 HAP 构建通过,签名 HAP 可启动 |
二、本次实测环境
| 项目 | 实际版本 |
|---|---|
| Flutter OH | 3.41.10-ohos-1.0.1 |
| Dart | 3.11.5 |
| DevEco Studio | 26.0.0 Release |
| HarmonyOS SDK | API 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.impact、haptic.notification、haptic.selection、haptic.prepare、vibration.oneShot、vibration.waveform、vibration.predefined、vibration.cancel、pattern.play 和 capabilities.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.md、pubspec.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
更多推荐



所有评论(0)