2026/10/17 16:17:23

Flutter on OpenHarmony实战:艺考真题题库App开发全记录

Flutter on OpenHarmony实战:艺考真题题库App开发全记录 1. 项目概述与技术选型分析做了一年多跨平台业务我对Flutter的生态和限制已经有比较清楚的认识。这次接到一个艺考真题题库App的开发需求目标平台是OpenHarmony第一反应不是先去搭页面而是先盘一遍技术路线。题目很直接能不能用Flutter跑在OpenHarmony上题库的题目详情页能不能做得顺滑媒体资源图片、音频、视频怎么塞进安装包里。先说明一下这套组合的价值艺考题库类App本质上是“内容练习解析”的结构对UI表现力、列表滚动性能、状态切换的流畅度要求都不低。传统做法是每个平台各写一套成本直接翻倍而Flutter for OpenHarmony这套方案可以让业务代码在Android、iOS、OpenHarmony三端复用尤其适合内容型工具App。这次实战我选择用Flutter作为UI主框架通过OpenHarmony适配层跑通整个链路从环境搭建到题目详情页的完整实现把整个过程中踩过的坑如实记录下来。技术选型背后的理由主要有三点。第一团队内已有较多Flutter业务沉淀题库相关的题目渲染、计时模块、做题记录同步等代码可以直接复用不需要在OpenHarmony上用原生重写一遍逻辑。第二艺考题库的核心用户是考生他们使用设备的系统分布比较杂既有Android/iOS设备也有部分新型平板设备跨平台一次编写多端复用在业务侧是刚需。第三OpenHarmony的分布式能力和多设备协同是加分项但项目初期最紧迫的还是把题目浏览、练习、解析这些基础功能跑通。所以整体方案确定为Flutter负责业务UIOpenHarmony负责系统适配与分发。这个项目还有一个容易被忽视的点题库App的详情页不是简单的一张详情图而是针对不同科目有完全不同的题型结构。音乐类有声频播放、美术类有图片对比、传媒类有视频素材这些多媒体能力必须在最初的设计中预留好接口。我接下来说说项目整体结构怎么搭才能既保证开发效率又能扛住后续题量增长。1.1 整体需求拆解与功能范围这个艺考真题题库App面向三类专业方向美术与设计、音乐舞蹈、传媒编导。每一类下的题目格式差异很明显。美术类以作品赏析、构图分析为主题干里是长文本作品图片音乐类需要给出乐谱图片和试听音频传媒类则经常出现视频片段分析题需要内嵌视频播放器。基于这个需求我把功能拆成四个模块题库浏览按年份、科目筛选、答题练习顺序作答选项联动、答案解析正误判断详解内容、个人记录做题数、正确率、收藏错题。题目详情页是核心中的核心因为所有模块最终都要落到“一题一题地看、一题一题地做”。这也是为什么我先把详情页的数据格式定死再回头写列表和筛选。考虑到目标平台是OpenHarmony我还额外预留了三个适配点字体渲染差异、系统返回手势、深色模式。这三个点在iOS和Android上都有现成方案但在OpenHarmony上需要逐步验证我放到第5部分详述。1.2 Flutter在OpenHarmony上的支持现状如果上来就想跑通Flutter for OpenHarmony得先接受它目前还属于社区驱动的状态。官方Flutter SDK默认不包含OHOS平台需要拉取专门适配的分支然后手动配置环境变量和SDK路径。这里的关键点在于要区分“OpenHarmony应用”和“OpenHarmony适配的Flutter引擎”这两个层级。前者是目标产物后者是承载Flutter UI的运行环境。我整理一下当前可用的工具链组合OpenHarmony SDK提供系统API、ArkTS等原生能力Flutter for OHOS分支基于标准Flutter代码库增加了OHOS平台嵌入层负责把Dart代码渲染到系统窗口上构建产物是HAP包通过DevEco Studio进行安装和调试。实测下来标准Flutter项目迁移到OHOS需要改动的地方不多主要涉及平台通道的注册方式和部分插件的原生实现。这里我特别标注一个经验不要一上来就到处找“全家桶”第三方插件很多Flutter插件在OpenHarmony上根本没有原生端实现。正确做法是先把业务逻辑和UI跑通哪些插件缺原生实现就自己补一个method channel桥接走系统API。比如本地存储、网络请求这些都可以用OpenHarmony的能力做适配而UI层面的滚动、布局、手势则完全交给Flutter引擎处理这也是最稳妥的路线。1.3 目录结构与三端复用策略为了让项目同时兼顾Android/iOS/OpenHarmony三端我在工程结构上做了严格分层。顶层分为appFlutter业务代码、ohosOpenHarmony原生壳工程、android/ios平台壳。业务代码全部放在Flutter目录不持有平台特有的依赖这样桌面端、移动端甚至以后要做的Windows版本都能复用。具体的目录规划如下project_root/ ├── app/ # Flutter业务主目录 │ ├── lib/ │ │ ├── models/ # 题目数据模型 │ │ ├── pages/ │ │ │ ├── question_list/ # 题库列表页 │ │ │ ├── question_detail # 题目详情页 │ │ │ └── profile/ # 个人中心 │ │ ├── services/ # 网络/缓存服务 │ │ ├── widgets/ # 通用组件 │ │ └── utils/ # 工具方法 │ └── pubspec.yaml ├── ohos/ # OpenHarmony壳工程 │ ├── entry/src/main/ # 入口与资源配置 │ └── build-profile.json5 ├── android/ # Android壳工程 └── ios/ # iOS壳工程在Flutter业务目录里我用主题Theme、路由Router、状态管理Riverpod三个基础组件搭建骨架。主题负责统一字号、间距、颜色因为艺术类题库的排版相对灵活题干里常出现加粗、缩进、图片混排。路由使用go_router但为OpenHarmony特意保留了页面转场动画的自定义能力避免三端转场风格不一致。采用这种结构的收益在后续开发中非常明显写题目详情页的时候只需要专注Dart代码不用关心底层是什么系统遇到平台差异时再去ohos目录里补桥接代码不会污染业务层。整个项目的开发节奏因此快了很多大多数功能一次编写后桌面端预览和真机调试同步进行。2. 题目数据模型与题库内容设计题库类应用的成功与否一半取决于数据模型是否设计得足够灵活。艺考真题有一个显著特点题干和选项不是简单的纯文本而是结构化程度很高的富文本加多媒体组合。如果一开始就把题目字段压平后面处理不同题型时会遇到大量硬编码分支代码会越来越难维护。所以我在项目开工前花了整整一个下午设计题目的JSON结构把后面所有题型的差异都考虑进来。2.1 题型划分与数据字段设计根据艺考真题的特征我把题型划分为单选题、多选题、判断题、连线题以及带媒体素材的图文题/视听题。每种题型共享一部分基础字段同时各自持有扩展字段。基础字段包括题目ID、科目、题型、年份、难度、题干、选项列表、解析、答案。扩展字段则允许按题型叠加比如视听题会有audioUrl和videoUrl图片题会有imageList。实际开发中我发现直接用一个扁平类结构会比嵌套继承更好维护。Dart里我定义了一个QuestionModel内部用Map存储扩展字段配合工厂构造函数实现JSON解析。这样做的好处是新增题型时不用改模型类只需要在渲染层增加对应的题型组件。项目初期题量不超过几千道JSON解析性能完全不是瓶颈重点在于稳定性。代码结构如下class QuestionModel { final String id; final int type; // 1单选 2多选 3判断 4视听 final String subject; final int year; final int difficulty; final String stem; // 题干文本 final ListString stemImages; // 题干图片 final ListOptionModel options; final Listint answer; final String analysis; final MapString, dynamic extra; // 扩展字段 QuestionModel({ required this.id, required this.type, required this.subject, required this.year, required this.difficulty, required this.stem, required this.stemImages, required this.options, required this.answer, required this.analysis, this.extra const {}, }); factory QuestionModel.fromJson(MapString, dynamic json) { return QuestionModel( id: json[id] as String, type: (json[type] as num).toInt(), subject: json[subject] as String, year: (json[year] as num).toInt(), difficulty: (json[difficulty] as num).toInt(), stem: json[stem] as String, stemImages: ListString.from(json[stemImages] ?? []), options: (json[options] as Listdynamic) .map((e) OptionModel.fromJson(e as MapString, dynamic)) .toList(), answer: Listint.from(json[answer] ?? []), analysis: json[analysis] as String, extra: json[extra] as MapString, dynamic? ?? const {}, ); } }字段设计为后期“随机出题”“按知识点标注”留了接口example里如果未来要接入新题型比如填空题、排序题只需要扩展type枚举和对应UI组件老数据不受影响。2.2 本地题库资源与线上更新策略艺考真题的媒体资源有图片、音频、视频体积差异很大。如果全部打进HAP包里安装包会非常臃肿但完全走线上加载又担心考生在考试前网络不稳定。我采用的方案是“核心题库内置补充题库增量下载”的双轨策略。本地内置的资源只包含近3年真题的文本和缩略图音频视频这类大文件按需下载。HarmonyOS的原始包大小限制对HAP包有严格要求所以我把题库数据打包成可分离的HAR或者直接放在rawfile目录动态加载。增量题库则通过应用内网络请求拉取下载完成后放在应用私有目录通过统一的资源管理器读取。这里的重点是抽象出资源管理接口让业务代码不用感知资源到底是本地路径还是网络URL。在Flutter侧我封装了一个MediaResourceProvider内部根据uri前缀判断资源类型和位置加载图片、音频分别交给Image.network、本地文件读取或缓存管理器。启动时预加载当天要练的题目的图片缩略图做题时切换页面就不会出现白屏等待。2.3 JSON解析性能与防崩溃设计题库数据解析是详情页流畅度的重要前置条件。虽然题目数量不大但解析JSON发生在进入做题页面时如果阻塞UI线程会出现明显的卡顿。我处理方式是把栈顶的松耦合任务放到后台Isolate执行先渲染出题干框架等数据解析完成后更新详情区。这样用户感受不到解析耗时。还有一点值得注意题目数据来自外部编辑团队JSON结构偶尔会有字段缺失或者类型不一致。比如options可能是空数组、answer可能是字符串而非整型列表。为了防止线上崩溃我统一在fromJson中加了防御性转换解析失败时丢弃该题并记录日志。具体做法是写一个safeParse方法对每个字段做类型判断不匹配时给默认值这样即使某道题数据结构损坏也不会影响整个题库加载。static Listint parseAnswer(Object? raw) { if (raw is List) { return raw.map((e) e is int ? e : int.tryParse($e) ?? 0).toList(); } if (raw is int) return [raw]; if (raw is String) { return raw .split(,) .map((e) int.tryParse(e.trim())) .whereTypeint() .toList(); } return []; }这段代码看起来简单但它实际省掉了后续很多排查时间。题库后台人工录入数据时经常出现答案格式不统一比如把[1,3]写成1,3防御性解析直接消除了这类问题。3. 题目列表到详情页的链路实现题库列表页是用户进入详情页的必经之路。艺考真题App的列表层级一般是科目页-年份筛选-题目列表-详情页。每一次进入详情页都会携带大量参数如果直接走路由传参参数一旦复杂就会让路由表变得难以维护。我采用的方法是集中式路由列表页状态保持让详情页前置页面在返回时能保住滚动位置和筛选状态。3.1 列表页布局与滚动性能优化题目列表页用ListView.builder构建每一条是一个圆角卡片展示题目编号、题型标签、年份和难度星级。列表数据量在一两千条以内时直接构建卡片即可不需要复杂的懒加载分页。但为了后续题库扩展我预留了分页加载接口用ScrollController监听滚动到底部时自动加载下一页数据。性能优化的关键点在于卡片内的题干预览文本不要超过两行剩余用省略号处理图片缩略图统一用cacheWidth参数压缩到200px左右难度星级用Stack叠加实现避免每颗星都生成一个Widget。这项优化在搭载OpenHarmony的低端设备上效果明显滚动帧率从偶尔掉帧变为稳定60FPS。列表项上我还做了快速定位能力右侧有一个可拖动的字母索引条对应年份或科目分类。这个组件在传统列表库中很常见但在Flutter里需要自己用GestureDetector计算索引位置。初版做出来后有点偏移后来发现是列表ContentView的padding高度没算进去修掉这个小bug后定位就很精准了。3.2 路由传参与状态保持进入详情页时我推荐用带状态的路由配置列表页把当前题目列表的完整数据快照以及当前选中的题目索引传给详情页。这样详情页可以左右滑动切换题目而且不需要向网络重新请求数据。具体实现采用go_router的extra参数在路由跳转时传入QuestionListArguments内部包含题目列表和初始索引。class QuestionListArguments { final ListQuestionModel questions; final int initialIndex; QuestionListArguments(this.questions, this.initialIndex); }这里要注意Flutter的路由extra在Android和iOS上传递的对象在页面重建时会丢失OpenHarmony同样存在这个问题。所以我没有依赖路由恢复机制保存题目列表而是把列表数据保存在一个全局的题库仓库中详情页只持有一个列表key和初始索引需要时从仓库取。这样即使详情页被系统回收重新进入时也能恢复完整数据。列表页的滚动位置保持是通过PageStorageKey实现。给ListView设置PageStorageKey后页面切走再返回Flutter会自动恢复滚动偏移。这个机制在OpenHarmony适配中实测可用不需要额外写平台代码。3.3 下拉刷新与筛选联动实现题库列表页还有一个高频交互按年份、科目、题型做多条件筛选。每切换一个筛选条件就需要向后端请求新数据。我采用状态管理Riverpod管理筛选条件和列表数据筛选条件变化时自动触发异步加载加载时列表显示骨架屏加载完成后平滑过渡。下拉刷新使用经典的RefreshIndicator和OpenHarmony的触摸手势兼容实测没有出现手势冲突。但有一点要注意OpenHarmony的滚动容器和Flutter的Scrollable手势识别优先级需要单独测试初次适配会出现下拉刷新触发不灵敏的问题解决方法是调整RefreshIndicator的triggerMode为onEdge。筛选面板采用底部弹层设计这样列表页不会被多层跳转占用。弹层内部按年份、题型、难度分为三组每组用Wrap布局排列标签。选择条件后点击“确定”将条件写入Riverpod状态列表页通过ref.listen监听条件变化自动刷新数据整套联动不需要手动管理生命周期。4. 题目详情页核心交互与多媒体实现题目详情页是这次实战的重头戏。它不只是展示题干和选项还要支持答题-判定-解析的完整闭环并且针对不同科目显示不同的媒体内容。交互流程设计成三阶段浏览题目阶段、提交答案阶段、解析结果阶段。三个阶段用状态类区分UI根据状态渲染不同的按钮和反馈区域。4.1 详情页整体布局与三阶段状态切换详情页采用自定义滚动视图顶部是题号栏第X题/共Y题下方依次是题干区、媒体区、选项区、操作区。操作区在答题前只有一个“提交答案”按钮用户选择选项后按钮变为可点击状态提交后进入解析阶段选项变色、正确答案高亮、解析内容展开、按钮变为“下一题”和“收藏本题”。三阶段状态用枚举定义enum QuestionStage { browsing, answered, analyzed }状态切换时我用AnimatedSwitcher对选项区和解析区做过渡动画切换过程柔和自然。题库App不需要花哨特效但适当的动效会让作答体验更接近主流学习类产品。这里要注意AnimatedSwitcher需要给子widget设置唯一Key否则动画切换时会复用旧组件导致内容闪变。答题区默认情况下每个选项都是圆角卡片左边是序号A/B/C/D右边是选项文本。多选题会显示“本题为多选”的提示并允许选择多个选项选择过程中提供顶部提示条提醒剩余可选项数量。美术图片题的选项可能是图片此时选项卡片采用等宽图片平铺点击后图片放大预览。4.2 题干富文本渲染与题目类型自适应题干内容大部分是文本图片混排偶尔会有分行、缩进、加粗等样式。纯Text组件没法满足这种富文本效果我用了两种方式组合常用场景直接用flutter_widget_from_html解析简单的HTML片段遇到在线公式、特殊排版时则用自定义的RichText构建器。富文本解析放在独立工具类中避免页面代码膨胀。对于不同类型的题目详情页的媒体区展示策略也不同单选/多选隐藏媒体区减少干扰图片题展示缩略图点击看大图支持双指缩放听例题显示音频播放器带播放进度和倍速切换视频题显示视频播放器支持进度拖动和全屏切换这些类型判断放在一个buildMediaArea方法中通过QuestionModel的type做switch分发每种类型对应一个独立Widget。后续新增题型只需要在switch里加一个case不会影响其他题型。4.3 音频与视频播放器的选型和适配媒体播放器是详情页最容易出问题的地方。OpenHarmony上Flutter社区生态里可用的视频播放插件不完善视频播放器我最终没有依赖第三方插件而是通过MethodChannel桥接到OpenHarmony原生VideoPlayer组件把播放控制权交给原生层。Flutter侧只负责展示播放器视图以及把用户点击的进度值传给原生层。这样绕开了插件不支持的问题也保证了播放性能。音频播放则相对简单OpenHarmony原生提供音频播放能力Flutter侧通过桥接实现播放、暂停、seek、倍速。同时我在Flutter层实现了音频播放状态管理方便对播放中的题目统一做处理比如切换题目时自动停止上一题音频。注意点Video和Audio的桥接连通后要在页面销毁时手动释放资源否则会出现播放器占用系统通道导致后续题目无法发声的问题。有条件的项目可以在OpenHarmony原生层完成播放器的UI封装然yield给Flutter侧通过Texture控件渲染到页面上。但我们项目周期较紧采用原生控制栏Flutter容器嵌入的方式也能满足基本功能。在线视频的缓冲策略使用原生播放器的默认行为测试在较长视频拖动进度时基本不会卡死。5. 状态管理与本地缓存方案选型状态管理决定了题库App在多页面、多交互状态下的稳定程度。这次项目选用Riverpod而不是更老牌的Provider原因是Riverpod的编译期安全和自动刷新机制更适合列表页-详情页这种频繁切换的场景。在OpenHarmony上状态管理的选择不受平台限制只要不涉及原生依赖都能正常工作。5.1 Riverpod状态管理在题库场景下的落地我把题库状态划分为全局状态和页面局部状态两类。全局状态包含科目列表、收藏集合、做题历史记录。页面局部状态包含当前筛选条件、当前列表数据、详情页的作答状态。这样划分的原因是收藏和做题历史可能在多个页面修改需要全局共享筛选条件和题目列表只属于题库页不需要全局广播。写一个普遍好用的做题历史Providerfinal answerHistoryProvider StateNotifierProviderAnswerHistoryNotifier, MapString, Listint((ref) { return AnswerHistoryNotifier(); }); class AnswerHistoryNotifier extends StateNotifierMapString, Listint { AnswerHistoryNotifier() : super({}); void submitAnswer(String questionId, Listint answer) { state {...state, questionId: answer}; } }在做题详情页中用户每提交一次答案就会触发submitAnswer同时把做题记录持久化到本地。Riverpod的优势在于当题目列表页返回时能立刻感知全局做题状态标记哪些题已经做过显示不同的背景色。5.2 基于本地数据库与SharedPreferences的持久化策略艺考真题App需要一个稳定的本地持久化方案来保存用户的做题记录、收藏和最近浏览题号。Flutter端的标准做法是sqflite或者shared_preferences但这些插件在OpenHarmony上原生实现并不完整。经过实测shared_preferences在OpenHarmony上可用适合存键值对但如果存大量做题记录键值对会导致序列化和反序列化开销过大。我采用混合方案用量小的高频数据收藏ID集合、当前进度、用户设置存入SharedPreferences用键值对做题历史记录这类结构化数据则通过桥接调用OpenHarmony的偏好存储或关系型数据库保存。业务侧统一封装一个LocalStorageService接口上层只调用save/get方法底层根据数据大小自动选择存储通道这样切换存储实现时不需要改业务代码。5.3 网络请求与离线题库的衔接除了本地缓存题库App还需要从服务器拉取最新真题。网络层我基于dio封装针对OpenHarmony的运行时权限做了适配。包括加载图片时需要检查网络权限下载题目附件需要保证文件存储权限断网情况下自动回退到本地缓存数据。离线策略我设计为三级第一级是内存缓存页面级第二级是本地序列化缓存Hive类似结构第三级是原始数据文件缓存。每次网络请求成功时会同时更新三级缓存请求失败时按缓存优先级从内存-本地-文件依次读取。这样考生在无网环境下依然能正常练习已经缓存过的题目。注意OpenHarmony应用沙箱对网络权限控制比较严格需要在config.json中显式声明网络权限。这个问题很容易被新手忽略明明代码没写错但请求就是不通。我在写桥接模块时专门写了权限检测工具调试模式下如果发现权限缺失会在日志中打印Petition提示。6. 常见问题与排查技巧实录从项目启动到第一个可用版本跑通前后遇到不少问题有些是Flutter自身的坑有些是OpenHarmony适配特有的问题。我把这些问题和排查过程完整记录下来能帮同路人少走弯路。6.1 OpenHarmony构建环境与插件适配问题最大的坑出现在构建阶段。初版项目在DevEco Studio中打开ohos目录Flutter标准SDK默认无法直接编译HAP需要切换到flutter for ohos的分支SDK。很多人拉取代码后配置了环境变量也切换了SDK但还是编译不过问题根源是Flutter引擎版本和OpenHarmony SDK版本不匹配。排查思路先看OpenHarmony SDK版本与Flutter ohos分支的最低API level要求是否对应然后在全局gradle.properties里填入flutter ohos的SDK地址。构建时如果还是报错根据报错信息定位是C引擎编译失败还是平台通道代码问题。前者多半是NDK版本不对后者检查MethodChannel注册名是否和原生层一致。插件适配问题上我的经验是优先选择纯Dart实现的插件需要原生代码的插件比如文件选择器、图片选择器打开源码检查有没有ohos目录如果没有就得自己写适配或者用MethodChannel桥接系统API。这个排查过程比较费时建议在技术选型阶段就把常用插件在OpenHarmony上的适配程度列个表避免开发到一半发现某个核心插件无法使用。6.2 题目详情页滑屏卡顿与内存占用优化详情页左右滑动切换题目时如果每道题都包含大量图片和文本页面重建的开销会很大。初版测试中OpenHarmony设备上出现明显的滑屏掉帧内存也持续增长。我先用Flutter性能分析工具Performance Overlay定位发现瓶颈是PageView.builder的缓存策略默认情况下当前页和相邻页都会被实例化图片解码缓存占用了大量内存。优化方案分三步第一步把PageView的allowImplicitScrolling改为false减少预加载页面数量。第二步对题干图片列表做缓存限制超过4张时只加载当前展示的两张其余懒加载。第三步音频和视频播放器在PageView切换时延迟初始化只有在用户停止滑动后才创建播放器实例。优化后帧率恢复到正常水平。还有一个容易被忽略的点页面销毁时要把PageController和播放器全部释放用dispose方法手动清空否则OpenHarmony上重复进出详情页内存会缓慢上涨。6.3 系统返回手势与页面路由冲突处理OpenHarmony的系统返回手势比Android传统导航栏更宽泛和Flutter的手势识别有时会冲突。具体表现是详情页横向滑动切换题目时偶尔错误触发返回上一页。这是因为Flutter的PageView左右滑动和OpenHarmony系统先从边缘滑动返回的手势同时识别了。解决方式是全局禁用详情页的系统返回手势换成应用内自定义的返回按钮和AppBar返回箭头。同时监听系统返回事件执行“先关闭图片预览、再暂停视频、最后退出页面”的分级逻辑。这套方案在OpenHarmony上稳定运行也不影响用户正常返回。如果在其他页面需要保留系统返回手势可以在RouteAware中判断当前路由是否有横向滚动组件有则禁用edge-to-edge返回无则保持默认。6.4 真机调试与日志定位技巧OpenHarmony上调试Flutter应用日志输出不像Android那样直观有时Dart侧打印的日志会被系统过滤掉。我用了一个小技巧在Flutter侧的debugPrint包一层Log工具类统一输出到原生Logcat并且打上全局前缀“FLUTTER_OHOS”。这样在DevEco Studio的日志面板里也能用“FLUTTER_OHOS”关键字过滤出Dart层的日志。真机调试时热重载在OpenHarmony上支持不完整经常出现修改Dart代码后界面不更新的问题。我的经验是纯UI改动可以依赖热重载涉及Runner工程配置或MethodChannel注册的改动必须重新编译。如果遇到热重载后状态丢失重新启动应用即可不需要额外清理构建产物。这套日志和调试定位方法虽然简单却能节省大量联调时间。尤其是桥接原生层和Flutter层时两边的日志前缀保持一致问题出现的环节一眼就能判断出来。7. 经验体会与后续扩展建议项目跑通之后回头再看整个Flutter for OpenHarmony艺考真题题库的实战过程最核心的收获可以浓缩成一句话方案选型比编码更重要。选对技术栈、设计好数据模型、规划好适配链路后面代码写起来会流畅很多反之如果一开始没把OpenHarmony的适配差异考虑进去开发途中系统能力缺失的问题会接二连三地冒出来。我个人在X上浏览OpenHarmony社区的更新动态发现它的设备覆盖和系统能力越来越完善后续可以进一步探索分布式能力在题库场景中的价值。比如考生在电视大屏上浏览题目手机作为答题遥控器做题记录通过分布式数据同步多设备实现在不同设备间无缝衔接。这些都是比较合理的扩展方向。如果同样想尝试这个技术组合的开发者我建议从小型Demo开始先把列表-详情-答题闭环跑通再逐步引入音频和视频最后再考虑复杂的状态管理。越是跨平台项目越要先保证最核心的业务链路稳定再考虑锦上添花的功能。最后放一句话收尾这套方案不一定适合所有App场景但如果你正在为“多系统、单代码库”的目标发愁Flutter for OpenHarmony值得花一个周末仔细试一试。