
一套购物APP从能跑到能用再从能用到经得起专业审视Flutter for OpenHarmony这条路我踩了不少坑也摸出了一些门道。这篇文章不聊空泛的概念就结合一个真实在做的购物APP项目讲讲架构是怎么一步步演进过来的哪些选型是真正有效的哪些地方是OpenHarmony专属的坑以及后续演进的方向怎么规划。无论你是在评估Flutter跨端落到OpenHarmony上的可行性还是已经在做相关的电商类应用这篇内容都应该能给你一些实在的参考。1. 为什么是Flutter为什么是OpenHarmony为什么是购物APP1.1 这个组合不是拍脑袋选出来的先交代一下背景。团队要做的是一个覆盖多个终端的购物应用当时的首要诉求是一套代码能跑在Android、iOS之外还要能快速适配到OpenHarmony设备上。之所以把OpenHarmony单独拎出来是因为它不是一个简单的安卓替代品而是带分布式能力的国产操作系统未来会在手机、平板、智能座舱、电视这些设备上铺开。对于购物这种天然需要跨设备流转的场景这是一个不能忽视的入口。跨端方案其实考察过不少。React Native在OpenHarmony上还在早期适配阶段社区资料少遇到问题基本靠猜。自研一套渲染引擎完全不现实成本太高。Flutter的优势在于它的渲染引擎是自己实现的不依赖系统WebView或原生组件树这意味着只要把Flutter Engine移植过去UI的渲染一致性是有保证的。当时OpenHarmony社区里flutter_flutter仓库已经推进到了一定成熟度至少能跑起来一个完整的应用而且在不断迭代。1.2 购物APP是个非常适合检验架构的场景为什么偏偏选购物APP来聊架构因为购物类应用几乎涵盖了客户端开发会遇到的所有典型问题复杂的页面状态、高频的网络请求、本地缓存与数据一致性、搜索与推荐这种重交互页面、支付与登录这种强安全场景、以及大量的图片与视频流。它是一个什么都有的应用任何一个架构设计上的偷懒都会在某个业务模块里加倍讨回来。我在推进这个项目的过程中最深的一个感受是架构不是被设计出来的是被业务痛打之后被迫演进的。一开始我们也是简单堆页面后来发现页面之间的状态共享、网络层的统一治理、平台能力扫码、相机、支付的接入没有清晰的架构约束根本推不动。所以这篇文章的骨架就是沿着这个被打—反思—重构—再被打—再重构的过程来讲的。1.3 专业的架构演进到底在演进什么很多人一听到架构演进就以为是上微服务、上容器、上各种高大上的框架。放到客户端侧来看架构演进实际上就在做四件事理清边界、管理状态、治理异步、沉淀复用。理清边界是指业务模块之间、UI与数据之间、业务与平台能力之间要有明确的划分谁也不能随便越界。管理状态是指页面之间、组件之间共享的数据流不能失控。治理异步是指网络请求、本地IO、定时器这些并发操作不能到处散落否则内存泄漏和竞态问题永远排查不完。沉淀复用则是把通用的东西网络层、缓存层、埋点、组件库抽出来让新业务不需要从零开始写。这四个点就是这篇博文的一条主线。下面我会先讲整体设计思路再拆解实操细节然后专门聊聊OpenHarmony适配的坑最后给出未来演进的规划。2. 购物APP的整体架构设计思路2.1 分层是架构的第一道安全网我先说一下最终落地下来的分层模型这样后面所有的演进细节都有个参照系。整个APP从下往上分成四层平台层、数据层、业务层、表现层。平台层是对OpenHarmony系统能力的封装比如相机扫码、本地存储、传感器、状态栏、剪贴板等。这些能力通过Flutter的platform channel暴露给上层。这一层有一条铁律上层代码不允许直接import平台相关库所有系统能力必须经过这一层的接口来调用。数据层负责网络请求、数据解析、本地缓存以及数据从远端到内存再到数据库的整个流转过程。业务层则按照购物APP的领域模型来组织比如商品、购物车、订单、用户、支付、营销这六大领域。表现层就是页面和组件只负责渲染和用户交互不做任何业务逻辑。这样的分层在实际开发中带来一个很明显的好处当测试发现一个bug时能迅速定位到是哪一层的责任。比如购物车数量不对先看数据层有没有同步错再看业务层状态有没有算错最后才去看UI层是不是渲染出了问题而不是像刚开始那样全凭猜。2.2 依赖方向必须单向分层只是第一步更关键的是约束好依赖方向。我的原则是表现层依赖业务层业务层依赖数据层数据层依赖平台层依赖关系只能从上往下不能逆向。那底层需要向上层传递数据怎么办通过回调或事件流来实现而不是直接持有上层对象。为了让这个规则落地我在项目里坚持使用接口隔离加依赖注入。业务层只认Repository接口不关心实现方到底是走的HTTP还是走的本地缓存。平台层也是同样思路上层不关心相机能力到底是系统API直接调的还是通过某个中间件转了一层。这个设计在初期会显得多写了很多无用的代码但当你要换一个数据源实现、或者是接入了新的平台能力时你就会发现这些接口抽象省下了大把时间。举一个很实在的例子我们的优惠券列表一开始是写死在本地的假数据后来要切到真实后端API如果当时没有用Repository接口隔离那页面层到处都是修改点。现在只需要替换一个实现类页面上完全不用动。2.3 组件通信与状态管理从setState到Riverpod的演进之路如果说分层是架构的骨架那状态管理就是架构的血液。购物APP里到处都是跨页面、跨组件的数据共享场景用户登录状态、购物车角标、地址选择结果、搜索历史。这些场景逼着我去选一个可靠的通信方案。一开始最朴素的做法就是setState页面少数据简单时挺好用页面多了以后就失控了。后来用了Provider状态是单向数据流了但状态更新粒度太粗页面经常产生不必要的重建这对购物APP里那些图文混排、列表复杂的页面来说是致命的会在快速滑动列表时感觉到明显的卡顿。再后来切到了Riverpod它的优势在于编译期就能发现状态依赖错误、状态可以安全地跨组件共享、支持异步状态原生处理。配合flutter_riverpod的消费者组件页面只关心自己订阅的那部分状态数据变了只有真正依赖它的Widget会重建。这在商品详情页、购物车页这些高频交互页面上效果非常明显。组件间通信如果再带参数的传递需求就结合Router来传参不让页面直接持有其他页面的实例。3. 购物APP架构演进的三步实操拆解3.1 第一步MVP阶段先把业务跑通这个阶段的目标只有一个把核心购物流程跑通验证产品价值。当时我们没有做任何架构设计所有代码都堆在一个package里页面直接new ApiClient发请求数据解析写在页面里状态全部用StatefulWidget管理。这个阶段大概维持了两三周。Demo演示很成功商品列表能刷出来、详情页能打开、购物车能加减商品、能下假订单。但这个版本存在一堆隐患修改一个公共工具函数会让多个页面跟着报错网络层的超时和重试逻辑完全没统一页面销毁后异步回调还在执行内存泄漏问题时有发生测试上更是无从下手没有任何自动化测试全靠手工点点点。我当时心里清楚这种状态撑不到真实用户量上来但它为下一阶段的架构设计提供了极其宝贵的输入到底哪些地方是最痛的。后来回看这个阶段的乱是必要的因为只有在业务真实跑起来之后你才知道架构该往哪个方向用力盲目照搬网上的最佳实践反而可能过度设计。3.2 第二步模块化改造把边界立起来第一个痛苦逼出来的重构方向是模块化。我把应用按业务域拆成了独立moduleapp壳工程、common基础库、auth用户中心、product商品域、cart购物车域、order订单域、pay支付域、search搜索域。每个module都有清晰的对外接口模块之间不允许直接引用对方的实现类只允许通过暴露的接口或路由来通信。路由是个关键决策。购物APP里跨模块跳转极其频繁从首页点击商品跳转详情、从详情加入购物车跳转购物车页、结算后进入订单页。我采用的方案是统一路由注册表每个模块在初始化时把自己负责的路由注册到路由中心其他模块通过路由名字加参数来跳转。这样可以避免模块之间产生编译期的循环依赖也方便后续做动态化或者按需加载。模块化改造中最难的不是技术而是老代码的迁移。我们花了大概一个多月时间把第一阶段的逻辑一块块拆到对应模块里。期间踩了不少坑最大的坑是共享实体的归属问题比如订单里引用了商品信息商品实体到底该放在product模块还是order模块最终的处理是抽取了一个shop_models的独立模块专门放跨域共享的数据模型避免模块之间互相依赖。3.3 第三步专业化打磨向可维护性要效率模块化解决了物理边界但逻辑边界还需要进一步强化。这一阶段我做三件核心的事。第一件事是全面落地Repository模式。购物APP的业务层不再直接依赖ApiClient或者本地数据库而是依赖Repository接口。Repository实现类内部再组合两个数据源远端API与本地缓存。读取数据时先看缓存缓存失效再走网络成功之后写缓存。这套逻辑被封装成统一的BaseRepository基类子类只需要声明数据来源和缓存策略大大减少了重复代码。第二件事是异步治理。Flutter中Future的then回调默认放入微任务队列这个机制用好了非常顺手但也容易出事。比如页面里发起一个网络请求页面销毁后回调还在执行就会报出各种unhandled exception。后来我们专门做一个通用的异步任务管理器统一管理页面生命周期与任务取消的绑定关系页面销毁时自动cancel未完成的任务。这直接降低了线上崩溃率里的异步异常占比。第三件事是测试基础设施。我为核心领域和状态管理逻辑补上了单元测试为关键业务流程加入购物车、提交订单补上了widget test并搭建了基于golden的UI快照测试来防回归。到这一步项目才真正有了一个专业团队该有的安全感。4. OpenHarmony适配的实战避坑记录4.1 引擎和渲染层的那些坑在OpenHarmony上跑Flutter最大的不确定性来自引擎本身的成熟度。我用的版本虽然主流程没问题但Image的编解码性能、字体渲染、以及动画的帧率表现都与成熟的Android端有差距。特别是商品详情页里的大图加载卡片列表快速滑动时在部分设备上能明显感觉到图片出现得偏慢。排查下来发现Flutter在OpenHarmony上还没有完全启用Impeller渲染引擎Skia的后端表现存在性能瓶颈。这是一个生态成熟度问题短期内建议在业务侧做补偿比如图片资源的尺寸做分级加载列表预加载策略调得更激进一些以及避免使用过于复杂的shader特效。我在工程里把图片缓存和预加载的配置在OpenHarmony平台上单独调了一套参数体验改善还是明显的。还有一个非常实际的坑Flutter for OpenHarmony构建产物是AAR格式要想集成进OpenHarmony工程必须通过ohos集成。第一次集成时因为Gradle配置不匹配反复报错。建议专门为OpenHarmony的构建保持独立的构建配置不要跟Android构建混在一起gradle插件的版本要严格对齐官方文档里给的版本矩阵。4.2 PlatformView和硬件能力的接入购物APP里必须用到的原生能力有相机扫码、本地推送、以及一些系统弹窗能力。OpenHarmony上的Flutter接入原生组件有自己的特殊性PlatformView的能力还不像Android上那么成熟。最折腾的是扫码这个功能。方案一开始考虑用PlatformView把原生的扫码组件嵌入到Flutter页面里实测在OpenHarmony设备上PlatformView的创建和销毁存在明显的性能开销且层级覆盖有时会出问题页面上的浮层无法覆盖住原生View。后来换成另一个思路把扫码能力封装成一个全屏的原生页面通过platform channel启动扫完码之后再回到Flutter页面。这样的体验其实更接近主流功能逻辑也绕开了PlatformView的兼容性坑。如果你要在OpenHarmony上做类似的能力接入我的建议是先通过platform channel完成功能闭环让原生页面做好交互再去考虑PlatformView级别的融合。先跑通再优化不要因为UI形态上的完美主义影响了整个项目的节奏。4.3 真机调试与日志排障的方法Flutter项目在OpenHarmony上跑起来后调试方式跟Android有比较大的区别。日志输出没有Android的logcat那么方便很多Flutter侧的日志会统一以e/flutter的形式打到系统日志里看得人一头雾水。我个人的排障习惯是两路齐下Flutter侧的日志用debugPrint统一管理并在debug模式下输出到控制台OpenHarmony侧的系统级崩溃日志则通过设备调试工具导出。遇到Dart层的unhandled exception时不要只看错误消息头部一定要把完整的调用堆栈导出来很多问题其实出在异步任务的生命周期上而不是表面上的那个空指针或类型转换错误。再一个建议是项目里尽早接入一个统一的日志上报体系。购物APP这种业务形态用户的交易链路长一旦线上出问题没有日志根本无法还原现场。我们把关键操作商品点击、加购、下单、支付回调都做了全链路埋点并在日志中带上traceId配合后端日志做贯通排查这比什么都管用。5. 未来蓝图购物APP的演进方向规划5.1 从单端走向分布式场景OpenHarmony跟Android/iOS最大的差异化优势在于分布式能力。购物APP未来不能只守着手机一个终端它天然适合在多设备之间流转。我的规划里有一个非常典型的使用场景用户在家里电视上刷商品扫码后手机接管购物车选定商品后在平板上看详情对比最后在手机或手表上确认支付。这就需要在Flutter侧把状态管理设计成可同步的用户会话、购物车数据、浏览历史这些状态都要能跨设备无缝迁移。OpenHarmony的分布式软总线提供了这套基础设施客户端要做的是让业务层的数据模型天然支持序列化和同步语义而不能把状态牢牢绑定在某一个页面的内存里。架构上我已经在数据层预留了分布式同步的接口抽象数据源可以有远端与本地之外的第三种实现——分布式协作数据源。这一步做扎实后购物车跨设备共享、订单状态跨屏同步这类能力才能以较低的成本落地。5.2 客户端架构与后端微服务的协同演进购物APP的演进不止发生在客户端后端也一样。原来后端是一个单体应用现在已经拆成了用户、商品、订单、营销、支付等微服务。客户端的架构必须跟上这个变化。实践中一件很重要的事是客户端不能感知后端微服务的物理划分否则一个页面要拼数据得并发调四五个服务网络开销和失败率都会急剧上升。因此客户端的数据层仍然以业务域来组织接口由后端BFF层完成聚合客户端只面向门面接口编程。这与DDD里repository聚合根的思想是天然一致的客户端看到的永远是领域模型而不是服务拓扑。另外我在客户端侧已经引入六边形架构的思路来组织接口适配层核心业务逻辑处在最内层对外部世界一无所知网络协议、本地存储、平台通道这些适配器都挂在边界上。这样的好处是即使后端接口从REST迁到GraphQL、或者引入消息推送来替代部分轮询核心业务逻辑也不用改只要替换适配器实现就好了。5.3 智能化购物体验的下一站聊到未来蓝图避不开AI。购物APP是最适合被AI重构的应用形态之一个性化推荐、智能搜索、AI导购助手、自动比价、智能售后。这些能力在客户端的落地形态是Agent交互架构。我的规划是在表现层提供对话式的导购界面业务层增加一个意图理解与行动编排模块通过它对接后端的LLM服务。用户说帮我找一款500元左右、适合送女生的蓝牙耳机Agent层负责拆解意图去商品域查询、筛选、比价把结果组织成页面卡片返回。这个过程中Flutter的组件化能力派上大用场原子组件以卡片的形式动态组装服务端下发布局描述客户端动态渲染这套方案同时解决了动态化和智能化两个问题。客户端AI能力沉淀上还会逐步引入端侧的小模型能力来做一些低延迟的本地处理比如商品图片的相似度匹配、拍照识物但这条路的优先级会排在后端Agent能力稳定之后。技术再性感也要一步步落地。5.4 合规性与生态认证走向专业的必经之路要做专业的商业级应用技术架构之外还有一道门槛OpenHarmony生态的合规与认证体系。购物APP涉及支付、用户数据、常用设备标识等敏感信息整体合规能力必须从架构层面就打好基础。XTS认证是一个绕不开的环节。它包含应用兼容性、安全、稳定性等多个维度的测试直接决定应用能否上架到官方应用市场。从架构角度看数据采集、权限申请、隐私声明的逻辑必须在数据层统一管理不允许业务层自己想申请权限就申请、想采集数据就采集。我建议把隐私合规当成一个横切关注点在Repository接口层加一道统一的合规过滤器任何涉及用户数据的读写都必须经过它。这一块没有捷径越早重视损失越小。如果等项目做完再补合规那改动的成本可能是架构级的轻则返工重则触碰底线得重新设计数据流。个人经验小结架构要为未来留口子但不要一步到位这个项目走到今天最想说的一句话是好的架构不是设计出来的而是在真实业务推动下生长出来的。一开始那个只会setState的Demo并没有错它用最低的成本验证了方向关键是在它暴露出问题之后你有没有勇气下手去重构以及在重构时有没有为下一阶段留好演进的口子。回到OpenHarmony Flutter这个组合它目前确实没有Android/iOS生态那么成熟但跨端与分布式两个能力叠加起来的想象力是真实的。我个人的体会是不用等生态完全成熟再进场可以用一个小业务模块先去试水把平台差异、构建链路、调试体验这些摸清楚有了体感再做规模化判断。如果你也在关注这个方向建议从今天开始就搭一个最小Flutter for OpenHarmony工程把分层、状态管理和平台通道这三件事先跑通。购物APP只是载体架构演进的逻辑是通用的——边界清晰、状态可控、异步可治理、能力可复用能做到这四点你的应用在任何平台上都不会跑太偏。