新闻详情

新闻详情

首页 / 资讯中心 / 详情

Flutter for OpenHarmony 实战:三方库 pedometer 的鸿蒙化适配指南

发布时间:2026/9/27 5:08:42来源:尧图网络
Flutter for OpenHarmony 实战:三方库 pedometer 的鸿蒙化适配指南
pedometer4.2.0做两件事把自开机以来的累计步数推成流以及判断人在走还是已停下。它的 API 面很小——两个静态 getter连一个 MethodChannel 都没有——但它在鸿蒙上暴露了一个很典型的问题同一份 Dart 代码在其他平台上多跑了一段逻辑鸿蒙上那段不会跑。不去把它补回来界面就会一直停在行走中。环境准备本文只讲适配本身不重复环境搭建步骤。Flutter for OpenHarmony SDK、DevEco Studio、模拟器/真机的完整配置见官方指引https://atomgit.com/CPF-Flutter/flutter_samples/blob/master/docs/ohos/getting-started/flutter-oh-env-setup.md一、适配步骤1️⃣ 上游仓库同步到 AtomGit上游cph-cachet/flutter-plugins是一个含 17 个包的大 monorepopedometer只是其中之一。做法是在 AtomGit 的oh-flutter组织下新建空仓库pedometer完整克隆上游保留全部历史后再追加适配提交。gitclone https://github.com/cph-cachet/flutter-plugins.git pd_workcdpd_workgitrev-list--countHEAD# 1730上游历史一条不少实测提醒这个仓库体量偏大用https://ghproxy.net/克隆连续两次被掐断fetch-pack: unexpected disconnect/fatal: early EOF/invalid index-pack output。换https://gh-proxy.com/一次成功。遇到同类报错不要反复重试同一个代理。2️⃣ 本地克隆目标库cdpackages/pedometer flutter pub get包本身没有任何第三方依赖只有flutterSDK 和flutter_test解析很快。3️⃣ 创建分支并用框架命令补全鸿蒙目录gitcheckout-bfeat/ohos_pedometer_4.2.0cdpackages/pedometer# 插件本体 → HAR 骨架flutter create-tplugin--platformsohos--orgcom.example --project-name pedometer.# 示例工程 → app 骨架cdexample flutter create--platformsohos --project-name pedometer_example.-t plugin不能省不加会按app模板生成出来的是AppScope/entry/而不是插件要的index.etssrc/main/ets/components/plugin/PedometerPlugin.ets并且会把.metadata写成project_type: app之后再补-t plugin会直接报The requested template type plugin doesnt match the existing template type of app。生成的骨架上本次真正要动的只有一个文件packages/pedometer/ ├── ohos/ # ★ 新增HAR │ ├── index.ets # 只做导出一行 │ ├── oh-package.json5 │ ├── build-profile.json5 │ └── src/main/ │ ├── module.json5 │ └── ets/components/plugin/ │ └── PedometerPlugin.ets # ★ 全部 ArkTS 代码 ├── example/ohos/ # ★ 新增示例的鸿蒙工程 └── pubspec.yaml # 加 2 行 ohos 声明4️⃣ 适配详细过程flutter create会顺手灌进一批模板文件必须逐个清掉。这次多出 23 项例如lib/pedometer_method_channel.dart # 与 lib/ 下真实实现重名本库根本不用 MethodChannel lib/pedometer_platform_interface.dart test/pedometer_method_channel_test.dart ios/pedometer/Sources/pedometer/PrivacyInfo.xcprivacy example/integration_test/ example/ios/RunnerTests/ example/android/app/src/main/res/drawable-v21/ ...清理办法取git status --porcelain里的??项排除含ohos/的路径与.metadata它是 M 状态记录 ohos 平台要保留其余全删。原库的lib/、test/、各平台实现一个字节都没动。除了新写的PedometerPlugin.ets改动只有三处插件的pubspec.yaml加ohos: pluginClass: PedometerPlugin示例的module.json5加运动权限声明示例的main.dart里给permission_handler调用加一道平台判断原因见下。5️⃣ 补全适配仓库所需文件新增README.OpenHarmony_CN.md与README.OpenHarmony.md安装方式monorepo 必须带path、权限声明要求、三个关键点、已知限制、验证结果与复现命令。上游原有文档未做改动。6️⃣ 代码推送gitaddpackages/pedometer/ohos packages/pedometer/example/ohos\packages/pedometer/{pubspec.yaml,.metadata,README.OpenHarmony*.md}\packages/pedometer/example/{.metadata,lib/main.dart}gitcommit-mfeat: 新增OpenHarmony平台实现gitpush origin feat/ohos_pedometer_4.2.0gitpush origin HEAD:main# 上游克隆下来默认分支是 master要显式推成 maingittag-a4.2.0-ohos-1.0.0-beta.1-mpedometer 4.2.0 OpenHarmony 适配gitpush origin4.2.0-ohos-1.0.0-beta.1推送前必做清空example/ohos/build-profile.json5里的signingConfigs里面是明文密码。二、上游给了什么契约packages/pedometer/lib/pedometer.dart里只有两个 getter两条通道都是 EventChannelclassPedometer{staticconstEventChannel_stepDetectionChannelEventChannel(step_detection);staticconstEventChannel_stepCountChannelEventChannel(step_count);staticStreamPedestrianStatusgetpedestrianStatusStream_stepDetectionChannel.receiveBroadcastStream().map((event)PedestrianStatus._(event));staticStreamStepCountgetstepCountStream_stepCountChannel.receiveBroadcastStream().map((event)StepCount._(event));}Dart 侧通道事件值Android 原生stepCountStreamstep_countint累计步数Sensor.TYPE_STEP_COUNTERpedestrianStatusStreamstep_detectionint0stopped1walkingSensor.TYPE_STEP_DETECTOR两个 DTO 的解析都写得很紧这是必须留意的StepCount._(dynamice){_stepseasint;// 非整数直接抛类型错误}PedestrianStatus._(dynamict){int _typetasint;_status_STATUSES[_type]!;// _STATUSES 只有 {0: stopped, 1: walking}}as int意味着原生侧不能把步数当成double发_STATUSES[_type]!意味着状态只能是 0 或 1——传个2会因为!断言崩溃。还有一处藏在pedestrianStatusStream里的分支它是本次适配的核心staticStreamPedestrianStatusgetpedestrianStatusStream{StreamPedestrianStatusstream_stepDetectionChannel.receiveBroadcastStream().map((event)PedestrianStatus._(event));if(Platform.isAndroid)return_androidStream(stream);// ← 只有 Android 走这段returnstream;// ← 鸿蒙走这里原样透传}_androidStream是一个去抖器每收到一次步伐就发walking并起一个 2 秒定时器2 秒内没有新步伐就把状态切成stopped。也就是说 Android 原生只负责每步发一个事件walking/stopped 的判定是 Dart 侧做的。鸿蒙不在这条分支里 → 这段去抖逻辑不会执行 →原生侧必须自己实现。三、鸿蒙侧的 API 选型三个关键点关键点一walking/stopped 的去抖要在原生补回来ohos.sensor提供了两个对应的传感器SensorId.PEDOMETER_DETECTION 265 // 步伐检测回调带 scalar SensorId.PEDOMETER 266 // 计步回调带 steps两个都需要ohos.permission.ACTIVITY_MOTION。订阅方式和别的传感器一样sensor.on(sensor.SensorId.PEDOMETER_DETECTION,this.onStepDetected);sensor.on(sensor.SensorId.PEDOMETER,this.onStepCount);因为 Dart 侧在鸿蒙上不做去抖原生这边把收到步伐 → walking静默 2 秒 → stopped整套实现出来参数与上游 Android 完全对齐privatehandleStepDetected():void{this.emitStatus(STATUS_WALKING);this.clearStopTimer();this.stopTimersetTimeout(():void{this.stopTimer-1;this.emitStatus(STATUS_STOPPED);},STOP_TIMEOUT_MS);// 2000与上游 Timer(Duration(seconds: 2)) 一致}这一步不做界面上Pedestrian Status会永远停在 walking只要用户走过一次因为没有任何东西会把状态改回 stopped。这类平台分支导致逻辑缺一块的问题光看原生接口是发现不了的必须把 Dart 层读完。顺带说一下为什么不做状态去重Android 侧每条步伐都会推一个事件调用方按收到即走了一步来处理是合法用法鸿蒙侧保持同样语义只在状态真正切换时打日志。关键点二部分设备没有独立的步伐检测传感器SensorId.PEDOMETER_DETECTION在 Pura X View 模拟器上订阅会抛错PedometerPlugin -- PEDOMETER_DETECTION unavailable code401, fallback to PEDOMETER changes401 The parameter invalid—— 模拟器只模拟了计步传感器没有模拟步伐检测。直接把这个错误抛给 Dartstep_detection通道就彻底不可用了。所以加了一条降级路径检测传感器不可用时用计步值的变化来推导行走状态——steps变了就说明又走了一步接同样的 2 秒去抖privatehandleStepCount(data:sensor.PedometerResponse):void{conststeps:numberMath.floor(data.steps);// 降级路径没有 PEDOMETER_DETECTION 时计步值增加即视为又走了一步if(this.detectionFromCountthis.detectionSink!nullsteps!this.lastSteps){if(this.lastSteps!-1){this.handleStepDetected();}this.lastStepssteps;}// ...再推给 step_count 通道}这里有个刻意的取舍降级路径不自己再去订阅一次PEDOMETER。因为step_count通道本来就会订阅同一个传感器重复订阅容易触发重复回调而且两个通道取消时会互相注销。代价是降级路径要求计步通道也在监听示例同时订阅了两条通道这一条写进了已知限制。关键点三ACTIVITY_MOTION是 user_grant 权限声明必须带 reason这是构建期硬报错不是运行时问题。只在module.json5里写个权限名{name: ohos.permission.ACTIVITY_MOTION}构建直接失败Error Message: The reason and usedScene attributes are mandatory for user_grant permissions.正确写法requestPermissions: [ { name: ohos.permission.ACTIVITY_MOTION, reason: $string:activity_motion_reason, usedScene: { abilities: [EntryAbility], when: inuse } } ]reason指向字符串资源会原样显示在系统授权弹窗上——所以这句文案是给用户看的要写人话{name:activity_motion_reason,value:用于统计步数与识别行走状态}弹窗实测长这样允许pedometer_example访问你的运动数据 用于统计步数与识别行走状态 [不允许] [允许]这一点顺带说明reason不是形式要求它是弹窗正文。写权限申请之类的空话用户看到的就是空话。权限的运行时申请由插件自己做插件实现AbilityAware拿到UIAbilityContext在订阅时调abilityAccessCtrl.requestPermissionsFromUser()。onAttachedToAbility(binding:AbilityPluginBinding):void{this.contextbinding.getAbility().contextascommon.UIAbilityContext;}constatManagerabilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(context,[PERMISSION_ACTIVITY_MOTION]).then((result){constresults:Arraynumberresult.authResults;// authResults[i] 0 表示已授权})所以宿主应用不需要permission_handler见下一节。四、示例工程的两处必要改动把permission_handler从鸿蒙路径上摘掉上游示例开头就申请运动权限Futurebool_checkActivityRecognitionPermission()async{bool grantedawaitPermission.activityRecognition.isGranted;if(!granted){grantedawaitPermission.activityRecognition.request()PermissionStatus.granted;}returngranted;}permission_handler目前没有鸿蒙实现这个调用在鸿蒙上不返回initPlatformState()卡在它后面两条流永远订阅不上——界面表现就是两个?而且日志里看不出任何异常。由于权限已经由插件自身申请这里只需要在鸿蒙上跳过Futurebool_checkActivityRecognitionPermission()async{// 鸿蒙侧不经过 permission_handlerACTIVITY_MOTION 由插件自身在订阅时申请if(!Platform.isAndroid){returntrue;}bool grantedawaitPermission.activityRecognition.isGranted;...}这属于示例为了在鸿蒙上可运行的必要改动不是库的能力缺失。如何引用适配库本仓库是 monorepo包在packages/pedometer下游用 git 引用时必须带pathdependencies:pedometer:git:url:https://atomgit.com/oh-flutter/pedometer.gitref:4.2.0-ohos-1.0.0-beta.1path:packages/pedometer示例工程内部本来就用的是pedometer: path: ../无需改动。编译构建cdpackages/pedometer/example flutter pub get flutter build hap--debug--target-platform ohos-x64首次构建前先生成调试签名仓库里signingConfigs已清空cdohosdevecocli signature generatecd..hdc shell power-shell wakeup hdcinstall-rbuild/ohos/hap/entry-default-signed.hap hdc shell aa start-aEntryAbility-bcom.example.pedometer_example五、真机验证验证在 HarmonyOS 7.0.0(26.0.0) Beta2 的 API 26 模拟器ohos-x64上完成。这个库的好处是模拟器支持注入步数不用真机也能把数据链路走通。权限首次启动弹出系统授权框正文就是上面那句reason。点「允许」后原生日志确认订阅与降级路径FlutterEngineCxnRegistry -- Adding plugin: PedometerPlugin PedometerPlugin -- pedometer channels registered PedometerPlugin -- PEDOMETER_DETECTION unavailable code401, fallback to PEDOMETER changes PedometerPlugin -- step count subscribed步数通道注入 500 步。devecocli emulator sensor--targetPura X View--steps500界面Steps Taken由?变为500同时状态切到walking。2 秒去抖不再注入2 秒后状态自动变stopped。PedometerPlugin -- pedestrian status - walking 17:06:20 PedometerPlugin -- pedestrian status - stopped 17:06:22两次日志相隔正好 2 秒说明原生侧复刻的去抖生效了。再注入一次 900 步重复同样的过程PedometerPlugin -- pedestrian status - walking 17:06:31 PedometerPlugin -- pedestrian status - stopped 17:06:33界面此时显示Steps Taken 900、Pedestrian Status stopped。六、已知限制降级路径要求计步通道也在监听。没有PEDOMETER_DETECTION的设备上行走状态来自PEDOMETER的变化若调用方只订阅step_detection而不订阅step_count就不会有状态事件。两条都订阅常规用法则无影响。有PEDOMETER_DETECTION时优先用它此时不依赖计步通道。示例移除了鸿蒙侧的permission_handler调用权限改由插件自身申请permission_handler的依赖仍留在pubspec.yaml中Android 侧仍在用。步数是自开机以来的累计值语义由系统传感器决定插件不做跨重启的持久化——这一点与上游 Android 一致不是适配引入的差异。七、常见问题Q为什么鸿蒙上 Pedestrian Status 一直是 walking停不下来A因为上游的去抖写在了if (Platform.isAndroid)分支里鸿蒙不在这个分支Dart 侧不会把状态切回 stopped。适配里在原生用setTimeout(2000)补上了这套逻辑日志中能看到walking → stopped相隔 2 秒。Qstep_detection订阅报code401 The parameter invalid是什么原因A设备没有独立的步伐检测传感器。Pura X View 模拟器只模拟了计步所以SensorId.PEDOMETER_DETECTION订阅失败。适配里有降级路径用计步值变化推导状态功能不丢失。Q为什么步数必须取整ADart 侧是_steps e as int如果原生发的是double会直接抛类型错误。同理状态只发0/1——PedestrianStatus._用的是_STATUSES[_type]!其他值会触发断言崩溃。Q声明ACTIVITY_MOTION为什么构建报reason and usedScene are mandatoryA它是user_grant权限鸿蒙要求声明时必须给出申请理由与使用场景。reason指向字符串资源会显示在系统授权弹窗上usedScene说明哪个 ability、什么时候用。Q需要permission_handler吗A不需要。插件实现了AbilityAware在订阅时用abilityAccessCtrl.requestPermissionsFromUser()自行申请宿主应用只需在module.json5里声明权限和理由。上游示例里的permission_handler调用在鸿蒙上会卡住流程已在示例中按平台跳过。Q模拟器上怎么造数据Adevecocli emulator sensor --target Pura X View --steps 500。注意每次注入都是设置绝对值连续注入不同值才能触发步数变化。Q模拟器验过还要真机吗A建议补真机主要验两件事一是真实设备的PEDOMETER_DETECTION是否可用走的是另一条代码路径二是计步的累积行为与系统省电策略的关系——模拟器的注入不会反映这些。小结这个库的适配代码不到 250 行但把一类容易被忽略的问题讲清楚了平台分支会让 Dart 层少跑一段逻辑。Platform.isAndroid那半行代码在鸿蒙上等于去抖器不存在只看原生接口是发现不了的——必须把 Dart 层读到Platform判断的位置。另外两条也都来自平台差异而非接口差异模拟器没有步伐检测传感器要靠降级路径兜住以及 user_grant 权限的reason会直接展示给用户所以它是文案不是形式。本篇用到的库项内容三方库pedometer4.2.0 的鸿蒙适配版适配仓库https://atomgit.com/oh-flutter/pedometer适配 TAG4.2.0-ohos-1.0.0-beta.1适配分支feat/ohos_pedometer_4.2.0包路径packages/pedometermonorepo引用时需带pathdependencies:pedometer:git:url:https://atomgit.com/oh-flutter/pedometer.gitref:4.2.0-ohos-1.0.0-beta.1path:packages/pedometer验证环境项版本Flutter for OpenHarmony SDK3.44.9ohos-0.0.1-canary1Dart3.12.2DevEco Studio26.0.0.621API 26设备HarmonyOS 7.0.0(26.0.0) Beta2 模拟器Pura X Viewohos-x64注入工具devecocli emulator sensor欢迎加入 CPF-Flutter 鸿蒙社区https://atomgit.com/CPF-FlutterFlutter 三方库鸿蒙适配清单https://atomgit.com/oh-flutter/flutter-ohos-adaptation-checklist
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

智能网联汽车开发环境配置:CMake驱动的可复现构建实践 2026/9/27 6:41:36

智能网联汽车开发环境配置:CMake驱动的可复现构建实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
中职学校网站建设的厂家怎么选?报价多少才不亏 2026/9/27 6:41:36

中职学校网站建设的厂家怎么选?报价多少才不亏

中职学校网站建设的厂家怎么选?报价多少才不亏 找中职学校建站厂家,最怕的就是报价虚高,心里没底。很多校长问网站多少钱,对方张口就是几万,细节却含糊其辞。这种“盲盒式”报价,极易让你为无效功能买单。…

阅读更多 →
华为2288hv5 IBMC带外管理实战:从配置到故障排查完整指南 2026/9/27 6:41:29

华为2288hv5 IBMC带外管理实战:从配置到故障排查完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
网站平台建设方案策划书一文搞懂安全架构 2026/9/27 6:41:29

网站平台建设方案策划书一文搞懂安全架构

网站平台建设方案策划书一文搞懂安全架构 域名解析指向哪里,服务器配置怎么调,这是很多技术小白最容易卡壳的地方。 别被那些高深莫测的术语吓住,核心逻辑其实很直白。 今天就把【网站平台建设方案策划书】里的安全底层逻辑拆碎了讲。…

阅读更多 →
网站集约建设原因:不懂代码怎么搭,多少钱才不亏 2026/9/27 6:41:10

网站集约建设原因:不懂代码怎么搭,多少钱才不亏

网站集约建设原因:不懂代码怎么搭,多少钱才不亏 自己不会代码想做网站,最怕的就是问了一圈,报价从几千到几万都有,心里直打鼓:这钱花得值不值?其实,很多甲方一上来就问“做这个网站多少钱”,但懂行的人都知道,价格背后是架构选择。选错了架构,后期…

阅读更多 →
别再伺候框架了:一个条件类看懂 SimpleDAO 的全部哲学——回归 SQL 本质的三件事 2026/9/27 6:41:10

别再伺候框架了:一个条件类看懂 SimpleDAO 的全部哲学——回归 SQL 本质的三件事

先看一段代码,再决定要不要读这篇文章 Setter Getter public class ReportCond extends BaseCondition {/*** 方法说明 拼加条件**/Overrideprotected void addCondition() {add("AND r.build_number ?", buildNumber); // 等值add("…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉