Flutter for OpenHarmony 主框架选型与搭建实战 我从一个真实需求聊起团队接到任务要给 OpenHarmony 设备做一款“移动数据使用监管助手”App 需要实时展示流量消耗、按应用排行、设置预警阈值还要在后台保持统计。选型讨论阶段团队内部吵了好几轮——有人坚持用 ArkTS/ArkUI 写原生有人提议 C 造轮子最后我们定了 Flutter for OpenHarmony。这个决定意味着主框架要重新设计、工程要重新初始化、一堆 Flutter 生态组件要逐个验证鸿蒙兼容性。这篇文章就记录我们落地“主框架”的全过程包括为什么这么选型、目录怎么分、代码怎么搭、哪些坑是网上搜不到答案的给正在用 Flutter 做 OpenHarmony 应用的同学一个可以直接参考的工程样板。1. 这个App为什么要用Flutter来做OpenHarmony端1.1 项目背景与“移动数据监管”的真实业务需求“移动数据使用监管助手”听起来像个流量监控工具实际做起来涉及的东西比想象中多。它要干的不只是显示“本月已用多少 GB”而是四块硬需求。第一数据采集。系统层要持续统计蜂窝网络SIM 卡产生的上传下载流量以及各应用各自消耗的流量。这个数据在 Android 上通常来自NetworkStatsManager在 OpenHarmony 上则需要走原生侧的网络管理/统计相关接口各版本 API 有差异我们后面细说。第二预警机制。用户设置“本月 30GB 封顶”到达 80%、100% 时要有提醒这要求 App 能常驻或定期唤醒检查。第三明细展示。按应用排序、按日维度折线图、套餐剩余天数推算UI 交互量大。第四权限与合规。涉及 SIM 卡信息、用量数据读取在 OpenHarmony 的权限模型下要逐个申请、并在隐私政策里说明。这些需求决定了主框架必须具备三个能力稳定的后台任务通道数据采集与预警、灵活的 UI 容器大量列表、图表、状态切换、跨平台的可复用逻辑层后续可能要出 Android 版。Flutter 正好卡在这个点上UI 层开发效率高业务逻辑能在 Dart 侧下沉原生侧只要提供一个稳定的平台通道即可。我们不需要为每个页面写两套代码。1.2 为什么不是ArkTS/ArkUI也不是纯C团队里最先被否掉的是纯 C 方案。不是说 C 不好而是这个 App 的页面量太大统计明细、图表、设置页、预警通知页全用 C 和声明式 UI 手搓人力成本直接翻倍后续迭代也劝退新人。ArkTS/ArkUI 被否的原因更实际我们团队 Dart/Flutter 技术储备更厚而且这个 App 明确规划了 Android 版本——OpenHarmony 和 Android 两个平台用同一套 Flutter 代码至少能省下 60% 的双端开发量。更重要的是OpenHarmony 的 ArkUI 虽然已经相当成熟但生态里的第三方图表库、日期选择器、存储封装远没有 Flutter 这么丰富我们不想在框架基建上耗尽时间。这里也顺便回应一个社区高频问题——“Flutter 和其他前端框架的优缺点在鸿蒙场景下怎么选”。如果只做 OpenHarmony 单端、团队熟悉 ArkTS、交互特别依赖鸿蒙分布式能力ArkUI 确实更顺。但如果你是多端团队、要快速出产品、需要现成的第三方组件生态Flutter for OpenHarmony 就是更务实的选择。它确实有老生常谈的缺点包体积偏大、Web 渲染性能不如原生可对“工具类 App”来说这些不是核心矛盾。核心矛盾是需求变更速度 vs 开发产能Flutter 的优势正在于此。1.3 主框架阶段的目标范围我们把这个 App 的落地拆成三个阶段。第一阶段本篇只做主框架工程初始化、目录分层、底部导航、路由、状态管理、主题、平台通道骨架、基础权限申请流程。第二阶段做数据采集与统计对接 OpenHarmony 原生侧 API 拿到真实流量数据设计订阅/查询机制。第三阶段做交互与优化图表、排行、预警通知、XTS 认证、性能调优。这样拆的好处是每一篇都可以独立复现读者不用等到三个月后看到全部代码才能跑起来。主框架拿到手里先跑通壳子后面往里面填业务就顺了。2. 主框架设计先把骨头搭对2.1 分层架构与目录结构我见过太多 Flutter 项目从“全部塞在 lib/page”开始三个月后重构成本高到崩溃。这个项目我们从第一行代码就定了分层思路核心是四层结构 单向依赖。core 层完全与业务无关的基础设施包括网络封装、本地存储封装、日志、常量、主题、通用组件。这层不允许 import 任何页面代码。data 层一切数据来源包括平台通道的封装ChannelManager、数据模型、仓库Repository接口与实现。页面不知道数据到底是来自原生通道还是本地缓存它只面向 repository 编程。domain 层轻量业务逻辑如额度计算把套餐总量、已用量、剩余天数换算成百分比和日均限额、预警判断。该层保持纯 Dart不依赖 Flutter SDK 和底层数据源方便单测。presentation 层页面、状态管理、路由。每个功能模块一个目录比如monitor/监控首页、detail/明细、ranking/排行、settings/设置。目录结构长这样lib/ ├── main.dart ├── app.dart ├── core/ │ ├── constants/ │ ├── theme/ │ ├── widgets/ │ ├── storage/ │ └── network/ ├── data/ │ ├── models/ │ ├── datasource/ │ │ └── platform_channel/ │ └── repository/ ├── domain/ │ ├── entities/ │ ├── usecases/ │ └── repository_interface.dart └── presentation/ ├── routes/ ├── pages/ │ ├── monitor/ │ ├── detail/ │ ├── ranking/ │ └── settings/ └── state/单看目录是枯燥的但当你写TrafficRepository的时候如果发现它既要调网络又要调本地缓存还要调平台通道就知道这个分层能救命。我们的硬规矩是domain层不允许出现import package:flutter/...这样月度额度计算逻辑可以直接用纯 Dart 单测覆盖不用起模拟器就能验证边界条件。2.2 核心依赖选型与版本策略OpenHarmony 的 Flutter 生态和 Android/iOS 有个最大区别pub.dev 上的绝大多数包没有 OpenHarmony 适配验证。我的决策原则是“尽量少、尽量稳、适配优先”。主框架阶段只引入五类依赖类型选型理由状态管理Provider 少量 ChangeNotifier依赖极小、无代码生成、OpenHarmony 上兼容风险低路由go_router声明式路由、支持 deep link社区活跃本地存储shared_preferences有官方 ohos 适配的 fork 可用Key-Value 够用图表fl_chart后续第二篇引入纯 Dart 绘制无原生依赖天然跨平台日志自研轻量 Logger避免引入过重依赖OpenHarmony 上的原生日志输出要单独接这里要踩一个很关键的坑不要在 OpenHarmony 上盲信 pub.dev 的最新版本。Flutter for OpenHarmony 的分支一般落后官方主干几个小版本有时候某个包在 Flutter 3.22 上正常但 OpenHarmony 的移植版用的引擎可能卡在 3.7 或 3.10和你拉的分支有关导致二进制不兼容。我的做法是先锁 Flutter 移植版版本比如3.22.x-ohos再看每个 pub 包的历史版本找该 Flutter 版本发版时期的稳定版而不是直接flutter pub add拿 latest。这一步能帮你避开 80% 莫名其妙的编译错误。2.3 数据监管类 App 独有的模块预留除了通用分层我还专门为“移动数据监管”这个业务预埋了三个模块接口这些在普通 App 主框架里往往被忽略但对这个 App 是刚性需求。第一个是常驻统计服务接口。流量统计不能只靠 App 在前台的时候拉取用户切到后台、锁屏SIM 卡的数据仍然在走。所以data层要预留一个TrafficCollector抽象将来实现可能有两种前台轮询简单但不准和原生侧后台任务上报复杂但精确。主框架阶段先把抽象定死方法只有start(SubscriptionConfig config)、stop()、onData(Function callback)具体实现后面再说。第二个是预警调度接口。流量到阈值要弹通知这在 Flutter 端做不到负一屏常驻得依赖 OpenHarmony 的公共通知能力。所以我们不在主框架里做具体实现但domain层定义了ThresholdEvaluator输入已用量和套餐配置输出预警等级无、80% 警告、100% 封顶提醒。这个纯 Dart 类现在就写好后面接通知只是响应它的输出。第三个是权限状态门面。一个工具类 App 的首次体验极其重要用户装完打开第一屏就应该是“本月流量概览”而不是权限弹窗连环 call。我们做了一个PermissionGate集中管理所有权限的申请、拒绝回调、跳转设置页逻辑主框架里保留它的空实现和页面占位第二阶段往里填 OpenHarmony 的原生权限申请即可。3. 环境准备与工程初始化这步卡过的人最多3.1 Flutter for OpenHarmony 该拉哪个分支先说结论省得大家走弯路。OpenHarmony 的 Flutter 适配目前主要由社区和华为共建维护核心仓库是flutter_flutter、flutter_engine和flutter_packages。你需要的是它们的ohos 分支而不是 Flutter 官方主分支。具体做法是分仓库拉取再手动指定版本git clone -b 3.22.x-ohos https://gitee.com/openharmony-sig/flutter_flutter.git git clone -b 3.22.x-ohos https://gitee.com/openharmony-sig/flutter_engine.git git clone -b 3.22.x-ohos https://gitee.com/openharmony-sig/flutter_packages.git这里有个非常重要的环境变量配置。OpenHarmony 的 Flutter SDK 需要知道 DevEco Studio 的 SDK 路径同时为了避免 pub 从公网拉包失败还要配置本地镜像。我实测稳定的组合是# 设置 OpenHarmony SDK 路径换成你自己的 DevEco SDK 目录 export DEVECO_SDK_HOME/path/to/DevEcoStudio/sdk export OHOS_SDK_HOME$DEVECO_SDK_HOME/default/openharmony # 防止 pub 访问公网超时 export PUB_HOSTED_URLhttps://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn强调一句OpenHarmony 移植版 Flutter 对本地环境非常敏感。如果你的机器之前装过标准 FlutterPATH 里同时出现两个 flutter 会在创建工程时引发各种诡异问题比如生成出android/目录但缺少ohos/目录。我自己的做法是配置别名区分标准 Flutter 单独保留在开发机上OpenHarmony 专用 Flutter 放到另一个目录用的时候用绝对路径调用。3.2 创建带 ohos 目录的工程配好环境后创建工程不能直接flutter create my_app你可能会得到没有ohos/目录的标准工程。正确姿势是以 OpenHarmony 移植版 Flutter 3.22 为例# 先生成标准工程结构 /path/to/flutter_ohos/bin/flutter create --org com.example --project-name traffic_guard traffic_guard_app # 进入工程后添加 ohos 平台支持 cd traffic_guard_app /path/to/flutter_ohos/bin/flutter create --platforms ohos .执行完你应该看到工程里多出ohos/目录里面包含entry/src/main/ets这类 OpenHarmony Stage 模型工程文件。这才是正确的起点。如果你发现flutter create没有--platforms ohos选项大概率是环境变量配错了检查flutter --version是否包含ohos字样的版本标识。创建完成后用 DevEco Studio 打开ohos/目录它会自动识别 Stage 模型工程。首次同步 Gradle 依赖会比较慢建议把 DevEco 的 SDK 源切换为华为镜像源。这个阶段你不需要写任何 OpenHarmony 原生代码只要确认两点一是默认 MainAbility 能启动并弹出 Flutter 页面二是 DevEco 里能看到entry模块的构建产物配置。主框架阶段我们只和 Flutter 侧打交道原生侧保持“最小可运行”就好。3.3 构建产物 har/hap 与后续打包链路社区里经常看到有人问“Flutter 能不能像原生那样直接出 hap”答案是能但要走两条链路。你可以在 DevEco Studio 里直接构建entry模块得到.hap包这是最终可安装到 OpenHarmony 设备上的产物也可以先把 Flutter 侧能力打成.harOpenHarmony 的静态共享包再集成到别的鸿蒙工程中。这和 Android 上 Flutter 可以打.aar给原生工程用是同一个思路。我实测中最常遇到的坑是har 包的依赖重复。如果 Flutter 侧工程编译出的.har里已经包含了libflutter.so和引擎相关资源宿主工程再引入一份就会资源冲突。解决办法是把宿主工程对 Flutter engine 的依赖设为provided或者直接在构建配置里排除重复的 so 文件。在 OpenHarmony 上出现这类问题的报错通常是“duplicate resource”或“multiple libs contain same symbol”。我们在主框架阶段就刻意验证了这个链路避免后面接广告 SDK、埋点 SDK 时再来排查。另外一个提示打包要区分 Debug 和 Release。Debug 包用flutter run DevEco 的组合可以热重载但性能差、包大。Release 包必须走flutter build hap或者 DevEco 的 release 构建它会做 tree shaking。这个 App 后续涉及图表库和动画包体积会明显放大早点确认 release 构建流程能少踩很多发布前的坑。4. 主框架代码落地从壳子到能跑4.1 底部导航与页面容器移动数据监管助手的主界面用四 Tab 最合理监控首页本月概览 预警卡片、流量明细按日/月查询、应用排行各 App 消耗排序、设置套餐配置 关于。用 go_router 做底部导航时要注意一个细节不要直接用ShellRoute套四个子路由因为每次切换页面都会重建 IndexedStack 之外的页面状态。正确做法是在HomePage内部用IndexedStack保存四个子页面状态go_router 只负责/home这一层路由。class HomePage extends StatefulWidget { const HomePage({super.key}); override StateHomePage createState() _HomePageState(); } class _HomePageState extends StateHomePage { int _currentIndex 0; static const pages [ MonitorPage(), DetailPage(), RankingPage(), SettingsPage(), ]; override Widget build(BuildContext context) { return Scaffold( body: IndexedStack(index: _currentIndex, children: pages), bottomNavigationBar: NavigationBar( selectedIndex: _currentIndex, destinations: const [ NavigationDestination(icon: Icon(Icons.dashboard), label: 监控), NavigationDestination(icon: Icon(Icons.list), label: 明细), NavigationDestination(icon: Icon(Icons.leaderboard), label: 排行), NavigationDestination(icon: Icon(Icons.settings), label: 设置), ], onDestinationSelected: (index) setState(() _currentIndex index), ), ); } }这段代码是你第一次跑通 OpenHarmony 真机的关键验证点——如果四个 Tab 能来回切换不崩溃、不闪退说明 Flutter 渲染层和 OpenHarmony 的适配没问题。我建议你在写任何业务之前先跑一下这个壳子。4.2 路由与状态管理状态管理我们选了 Provider理由前面说过简单、稳。主框架里统一建立三个全局ChangeNotifierSettingsState保存套餐总量、计费周期起始日、预警开关落库到 shared_preferences。TrafficState当前已用流量、今日增量、各应用排行数据源暂时用 mock第二篇换成真实通道。PermissionState记录每个权限的授权状态驱动首次进入的引导页。必须注意的一点是 Provider 的初始化时机。OpenHarmony 的 Stage 模型下Flutter 页面挂在 MainAbility 上启动流程比 Android 慢如果你在main()里同步初始化所有 Provider 依赖很可能遇到“在 Build 阶段读取尚未初始化完成的存储”的异常。我们用的方案是提前await初始化void main() async { WidgetsFlutterBinding.ensureInitialized(); // 先初始化本地存储和用户配置 await StorageService.init(); runApp(const AppRoot()); }不要小看这个awaitOpenHarmony 的shared_preferences插件在不同版本上的初始化延迟差异极大极端情况下能差出几百毫秒。提前await可以保证SettingsState在页面构建时一定有数据可用。4.3 平台通道的基础骨架Flutter侧如何拿到“移动数据使用量”移动数据使用量在 OpenHarmony 上不是一个 Flutter 侧能直接读到的数据必须走平台通道。主框架阶段我们不实现真实采集但要先把通道协议定好否则后面写原生侧会到处补洞。通道设计如下MethodChannelclass TrafficChannel { static const _channel MethodChannel(traffic_guard/channel); /// 获取当前 SIM 卡信息 static FutureMapString, dynamic? getSimInfo() { return _channel.invokeMapMethod(getSimInfo); } /// 获取今日总流量bytes static Futureint getTodayTotalBytes() async { final value await _channel.invokeMethodint(getTodayTotalBytes); return value ?? 0; } /// 注册后台统计回调 static void registerTrafficCallback(void Function(dynamic event) onEvent) { _channel.setMethodCallHandler((call) async { if (call.method onTrafficUpdate) { onEvent(call.arguments); } }); } }为什么通信协议要在主框架阶段就定因为涉及原生侧权限申请、后台任务注册后面改协议意味着两端联动成本远高于现在。还有一点MethodChannel 的 channel 名要有项目前缀。多个 Flutter 插件共存时channel名重复会导致消息串线、回调没人处理。我用traffic_guard/channel而不是traffic就是为了避免和社区通用插件撞名。关于“Flutter 组件通信”这个高频问题我不妨多说一句组件通信和原生间通信不同它主要靠InheritedWidget、Provider、Callback、Stream。在 OpenHarmony 上最容易踩的坑不是这些而是 MethodChannel 回调里的线程问题——原生侧返回结果时不一定在主线程Flutter 侧默认帮你切回主线程没问题但如果你用 EventChannel 做事件流必须确认原生侧线程模型否则你会遇到“数据到了但 UI 不刷新”的诡异 bug。4.4 主题、深色模式和统一的卡片组件工具类 App 最忌讳花里胡哨但也不能毫无设计感。我们定义了一套基础设计令牌Design Token集中在core/theme里。颜色以数据可视化场景为主主色用深蓝传达可信赖感预警色用琥珀、危险色用红色背景用中性灰阶。class AppColors { static const primary Color(0xFF1B4B91); static const warning Color(0xFFF5A623); static const danger Color(0xFFE94F37); static const backgroundLight Color(0xFFF7F9FC); static const backgroundDark Color(0xFF17191C); }深色模式在主框架阶段就要做原因很简单这个 App 的监控首页很可能长时间亮屏用户对暗色模式的需求极高。实现上用ThemeData.brightnessColorScheme.fromSeed做双主题并跟随系统设置。在 OpenHarmony 上跟系统设置有个前提——要先确认MediaQuery.platformBrightnessOf(context)能正确拿到系统亮度模式有的移植版在早期版本里这里返回的值不准。稳妥做法是在SettingsState里加一个手动切换开关默认跟随系统用户可强制覆盖。通用组件我们只做了三个够用就好TrafficCard显示大数字流量的圆角卡片、ProgressBarWithThreshold带预警线的进度条、EmptyPlaceholder空数据占位。这三个组件在 OpenHarmony 上一定要用RepaintBoundary包一层尤其是ProgressBarWithThreshold——实测在低端设备上连续重绘会掉帧包上之后好很多。5. 实测中的崩溃与修复附排查思路5.1 e/flutter (31173): 未处理异常到底从哪来很多同学第一次在 OpenHarmony 上跑 Flutter 工程看到类似下面这行日志就慌了E/flutter (31173): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method getTodayTotalBytes on channel traffic_guard/channel)我第一次看到也以为是自己代码 bug排查了半天才发现这行日志本质上是 Flutter 框架层的通用输出——任何 Dart 层的未捕获异常都会在dart_vm_initializer.cc这个位置打出来后面的Unhandled Exception才是真实原因。上面的例子是典型的MissingPluginException你调用了getTodayTotalBytes但 OpenHarmony 原生侧还没有注册对应的 MethodChannel 实现。排查思路不要乱第一看异常类型。MissingPluginException说明原生没实现PlatformException说明原生实现了但抛了业务错误TypeError说明返回 JSON 转模型失败。第二看是首次启动必现还是偶发。必现的多是原生侧注册时机问题偶发的要查异步回调。第三如果日志只有flutter前缀而没给 Dart 堆栈可以把debugPrint和FlutterError.onError接上拿到完整 Dart 侧调用链void main() { FlutterError.onError (details) { FlutterError.present(details); }; PlatformDispatcher.instance.onError (error, stack) { debugPrint(uncaught: $error\n$stack); return true; }; // ... }记住一点在 OpenHarmony 上Flutter 侧的异常日志格式和 Android 是一脉相承的但真实堆栈往往在 device log 的另一段。用 DevEco 的 Log 面板过滤flutter和ohos两个 tag能看到的线索比只看dart_vm_initializer.cc那行多得多。5.2 新建项目后跑不起来的常见原因盘点我统计了下团队和社区上反馈的“新建项目跑不起来”案例集中在三个原因。第一是Java/Gradle 环境残留冲突。如果你之前在本机跑过 Android 工程Gradle 环境和 OpenHarmony 的 hvigor 环境可能互相干扰。典型报错是Could not find an installed version of Gradle或者SDK location not found。解决方法是清理~/.gradle缓存里的 OpenHarmony 相关模块或者用 DevEco 自带的 JDK 重新配置JAVA_HOME。第二是工程目录层级不对。很多人直接用 DevEco 打开了整个 Flutter 工程根目录而它应该打开ohos/子目录。DevEco 靠build-profile.json5识别工程根目录没有这个文件于是构建任务找不到entry模块。第三是签名配置缺失。OpenHarmony 应用安装到真机上必须有签名。新建工程的ohos/目录默认是 debug 签名配置能跑模拟器换真机时必须到 AppGallery Connect 申请调试证书并更新build-profile.json5。这个环节最容易在“模拟器能跑真机跑不起来”时被漏掉。我推荐一个排查顺序先flutter doctor确认 Flutter 侧健康再在 DevEco 里手动构建entry看 hvigor 输出最后命令行安装hvigorw clean排除增量缓存问题。不要一上来就怀疑 Flutter 移植版本身大多数“跑不起来”都是工程配置问题不是引擎问题。5.3 下拉刷新与列表滚动的性能优化主框架里监控首页和排行页都用到了下拉刷新这块在 OpenHarmony 上比 Android 更容易暴露问题。官方RefreshIndicator在 Flutter for OpenHarmony 上能跑但低端设备下拉时会出现明显的阴影撕裂感。一个有效的优化是把刷新指示器和列表分割开而不是直接包整个 ListViewRefreshIndicator( onRefresh: _loadData, child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverToBoxAdapter(child: _HeaderSection()), SliverList.builder(...), ], ), )把刷新和内容结构拆成 Sliver刷新的触发区域更可控。另外列表项尽量做成 const 构造减少重建。实测在 RK3568 这类 OpenHarmony 开发板上用constSliverList组合滚动帧率可以从 40fps 提升到接近 60fps。还有一个小技巧排行页的应用图标不要直接用Image.network或Image.asset裸加载在 OpenHarmony 上图片解码是 CPU 密集操作。统一用precacheImage预加载 cacheWidth限制解码尺寸内存和帧率都会有明显改善。5.4 Impeller 渲染引擎OpenHarmony 上要不要开Flutter 3.10 之后官方推动 Impeller 渲染引擎替代 Skia但 OpenHarmony 移植版主框架阶段不建议开启 Impeller。原因很简单Impeller 的 OpenGLES/Vulkan 后端适配需要大量图形栈验证OpenHarmony 上各设备的 GPU 驱动差异又大移植版默认走 Skia 有更充足的兼容性保障。我在开发板上尝试开启 Impeller 后第一个页面能正常渲染但切换到深色模式再切回浅色模式时出现过渲染花屏。如果你的应用对动画渲染要求很高可以等后续版本把 Impeller 的 OpenHarmony 后端稳定了再切。现阶段主框架用 Skia 是务实选择。这个取舍不需要纠结追求稳定大于追求一点图形性能。6. 上线前必须处理的资质与兼容问题6.1 XTS 认证对主框架的影响OpenHarmony 应用想上架到官方应用市场要通过 XTSX Test Suite认证。它是一套兼容性测试集会检查应用是否遵循 OpenHarmony 的接口规范和权限模型。主框架阶段如果不注意后面认证会被一堆小问题卡住。在主框架里就要做对的三件事一是所有权限申请必须动态申请不要在module.json5里声明完就完事运行时要用abilityAccessCtrl走用户授权流程。二是有完整的隐私声明入口设置页必须能跳到隐私政策页面。三是不能有测试残留比如 debug 模式的入口、mock 数据开关Release 包要确保全部关闭。XTS 报告的失败项通常很直接比如“权限声明与运行时行为不一致”“存在非公开 API 调用”。我们的处理办法是预留一个PermissionTrace工具把所有权限申请的路径打日志方便认证失败时回溯。6.2 第三方组件的 ohos 适配检查清单主框架依赖的包不多但每个都要过一遍适配检查。我写了一个检查清单每次引入新包都对照执行是否纯 Dart 实现。纯 Dart 的包如 fl_chart可以直接用依赖原生代码的包要查它是否适配 ohos。是否用了dart:io中 OpenHarmony 不支持的 API。比如Process、部分 socket 实现可能受限。是否有版本锁定。先看它的 pubspec 约束的 Flutter SDK 范围再对照移植版 Flutter 支持范围。是否存在资源冲突。打包后检查资源文件是否和entry模块重复。被卡住最多的通常是带原生插件的包比如shared_preferences。社区里有专门的 ohos fork你直接 pub 官方包在 Android 上没问题在 OpenHarmony 上会报MissingPluginException。处理办法是把 pub 源切到 OpenHarmony SIG 的 fork 地址或者直接把 fork 代码放到本地third_party目录。6.3 从主框架到完整功能后续迭代规划主框架阶段结束的时候项目应该具备能跑通四个 Tab 页、有主题系统、有路由与状态管理、有平台通道协议、有权限申请占位、能打出 release hap 并且通过基础的设备验证。到这里壳子是完整的、可演示的。后续第二篇我会写数据采集层的真实实现OpenHarmony 原生侧如何查询 SIM 信息、如何统计蜂窝流量、如何通过后台任务持续上报以及 Flutter 侧 repository 层的完整封装。第三篇写交互进阶图表、排行、预警通知、关于页的合规信息再做一轮性能优化和 XTS 提交。这个规划的明确意图是让任何人都能按系列文章的节奏逐步完成整个 App而不是只得到一个孤零零的工程模板。开个玩笑说主框架就像房子的承重墙和管线预埋水电走对了后面装什么功能区都顺。水电没走对后面三天两头返工。我们在 Flutter for OpenHarmony 上踩过、填过的这些坑希望你不用挨个再踩一遍。如果你在搭主框架时也遇到奇葩问题尤其是 OpenHarmony 移植版的引擎级问题欢迎在我博客评论区留个运行日志片段我看到会恢复到具体报错。