尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Flutter跨端适配OpenHarmony:宝可梦图鉴搜索模块实战解析

发布时间:2026/9/26 5:29:30

资讯中心
01
ARTICLE

Flutter跨端适配OpenHarmony:宝可梦图鉴搜索模块实战解析

Flutter跨端适配OpenHarmony:宝可梦图鉴搜索模块实战解析
前阵子我在做 Flutter 跨端项目时正好需要适配 OpenHarmony 设备。当时手头有一个很典型的实战需求做一个“万能游戏库” App第一版功能先实现宝可梦图鉴搜索。很多人一听 OpenHarmony 就下意识以为只能写 ArkTS实际上 Flutter 社区早就为它维护了专用分支。这个搜索模块麻雀虽小却串起了环境搭建、数据建模、模糊检索、列表渲染这一整条链路做完之后我觉得非常值得记录。不管你是想接触 OpenHarmony 上的 Flutter 开发还是单纯想实现一个带模糊搜索的游戏图鉴 App这篇实战笔记都能给你一套可以直接抄作业的路径。1. 把Flutter搬到OpenHarmony上先想清楚这四件事1.1 万能游戏库App到底要解决什么我做“万能游戏库”这个项目的初衷是想解决一个很实际的痛点玩家手机里通常同时装着好几个攻略站、图鉴 App 和 Wiki 页面查一个信息要来回切换。尤其宝可梦这种资料量巨大的系列包含编号、属性、特性、种族值、技能学习表、进化链、版本差异等等信息分散是一定的。“万能游戏库”的思路是把这些资料聚合到一个入口里不让玩家在查资料这件事上消耗过多精力。宝可梦搜索就是整个“万能游戏库”最能体现价值的模块也是我这次实战的第一阶段目标。用户输入的可能是一个不完整的名字比如“皮卡”也可能是英文名“pika”可能是编号“025”甚至可能是属性“电”。一个合格的搜索框应该把这些问题全部兜住。真正做产品时还需要考虑更多长尾只记得是“火系”而且“第一世代”怎么办输入“超级”想要看超级进化形态怎么办想对比两个精灵的种族值怎么办。这些都可以落到同一个搜索模块里只是检索维度变多。所以这个模块虽然看起来只是一个搜索页加一个列表但它本质上是一个小型的检索系统。我把核心需求拆成了三层数据层的图鉴数据加载与索引、应用层的查询解析与结果排序、UI层的结果展示与交互反馈。每一层都要可替换、可测试这样后续接入其他游戏数据时比如卡牌、装备、技能表直接复用同一套框架就行。1.2 为什么选Flutter而不是原生ArkTSOpenHarmony 的官方推荐开发语言是 ArkTS配合 ArkUI 声明式组件。团队如果从零开始并且只做 OpenHarmony 一个平台选 ArkTS 完全合理毕竟它能调用最底层的系统能力和系统版本同步升级也最省心。但我的情况不一样。团队里已经积累了相当多的 Flutter 组件和跨端业务逻辑尤其是搜索框、列表、图鉴卡片这类 UI 密集的模块在 Flutter 生态里有成熟的方案直接搬过来可以省掉一大笔重复开发成本。更关键的是Flutter 的跨端属性决定了这次付出的成本可以持续复用。宝可梦搜索的逻辑层从数据建模到打分算法写出来就是纯 Dart 代码不依赖任何平台能力UI 层用的也是 Flutter 通用组件。以后这个 App 要跑 Android、Windows 或者 Web核心逻辑一行不用改最多微调平台分支。而 ArkTS 写出来的东西会被绑定在 OpenHarmony 体系内将来想平行移植到其他平台基本要重写。还有一个现实考量OpenHarmony 的设备形态很广从轻量设备到标准系统都有Flutter 的顶层 UI 逻辑可以在这些形态里保持相对一致。当然OpenHarmony 上跑 Flutter 并不是官方主线的默认选项它需要依赖社区维护的专用分支这意味着版本迭代节奏和官方 Flutter 不一定完全同步。接受这个前提才能做好心理建设后面遇到环境问题时不至于手忙脚乱。1.3 模块边界搜索功能在整体架构中的位置我不想做成一个联网版的“大而全”应用而是先把“万能游戏库”拆成几个相对独立的模块首页聚合、游戏库、图鉴、设置。宝可梦搜索放在“图鉴”模块内部作为第一个落地功能。模块边界划分对后续维护非常关键我这里直接套用了在 Flutter 社区里比较常见的分层方式层级职责是否依赖UI框架数据层加载JSON、归一化、构建索引、执行检索否纯Dart应用层管理查询状态、结果状态、错误状态依赖bloc/cubit管理UI层展示搜索框、结果列表、详情页是数据层只暴露一个仓库接口比如loadPokemonData()返回ListPokemonsearch(query)返回排序后的搜索结果。UI层不直接操作数据所有中间状态交给 Cubit 管理。这样分区的好处是搜索算法可以单独写单元测试不打开 App 就能验证正确性以后如果想把图鉴数据从本地 JSON 换成网络接口只需要替换数据层内部实现上层完全无感。2. 环境搭建与初始化踩平第一公里的坑2.1 准备OpenHarmony SDK与Flutter分支OpenHarmony 上的 Flutter 开发最忌讳的一件事就是直接用官方 Flutter 稳定版 SDK 去尝试因为官方主线根本不认识 ohos 平台。我们需要的是一套由社区维护的专用分支通常是flutter_flutter配合flutter_engine、flutter_ohos使用。我之前在 gitee 上找 OpenHarmony 组织下的仓库把对应的 SDK 分支拉到本地然后通过环境变量把它指给命令行工具。具体步骤大致是这样先安装 DevEco Studio 并下载 OpenHarmony SDK记录 SDK 的安装路径。然后拉取 Flutter 分支代码我建议直接 clone 官方指定的分支目录不要在 main 分支上随意试。拉完以后配置环境变量OPENOHOS_SDK_HOME指向 OpenHarmony SDK 根目录FLUTTER_ROOT指向 Flutter 分支目录。最后重新打开终端执行flutter doctor -v如果配置正确会看到 OpenHarmony 的 toolchain 信息。这个阶段最常见的报错就是那串the current configured flutter sdk is not known to be fully supported. please提示。看到它不用慌这通常只是分支版本和某个工具链版本的识别差异不代表环境完全不可用。我当时的处理方式是先确认拉取的提交版本是否匹配 OpenHarmony SDK 的 API Level再检查两个环境变量是不是被其它配置覆盖了。只要flutter devices或者flutter doctor能识别出 ohos 设备信息基本就可以往下走。2.2 创建ohos平台工程与依赖配置环境没问题之后创建工程很简单在项目根目录执行flutter create --platforms ohos .。注意目录名不要用中文也不要有特殊字符否则后续工具链解析路径时会出一些莫名其妙的错误。创建完以后根目录下会出现ohos目录里面是 OpenHarmony 侧的原生工程配置。依赖选型上我有一套很保守的经验纯 Dart 实现的插件在 OpenHarmony 分支上基本可用凡是依赖原生能力的插件就要谨慎。比如网络请求我用dio这个本身是 Dart 层封装可用但图片缓存如果直接上cached_network_image它底层会依赖平台的文件路径能力OpenHarmony 分支上就可能有坑。状态管理我用flutter_bloc和equatable这俩完全是 Dart 层的逻辑放心用。中文拼音转换我用lpinyin也是纯 Dart 实现后面搜索算法里会用到。除了常规依赖网络权限还要在 OpenHarmony 工程里手动配置。找到ohos目录下的module.json5在requestPermissions里加上ohos.permission.INTERNET否则真机上发不出任何 HTTP 请求。这个点特别容易漏因为 Flutter 侧不会给你任何报错只会表现为网络请求莫名其妙超时。另外如果后面准备加载网络图片域名也要确认是否在系统网络安全配置里被允许。2.3 项目目录规划与数据资源准备工程初始化好之后我先规划了一份尽量贴近生产环境的目录结构而不是把代码全塞进main.dartlib/ app/ app.dart router.dart core/ theme/ utils/ widgets/ data/ models/ repositories/ datasources/ features/ pokemon_search/ cubit/ widgets/ pages/ main.dart数据资源方面我从公开的宝可梦图鉴资料中提取了第一世代 151 只精灵的基础信息整理成assets/data/pokemon.json。字段包括编号id、英文名nameEn、中文名nameZh、属性列表types、身高体重、种族值、特性描述等。图片资源我走了一条稳妥路线先把精灵正面小图放到assets/images/pokemon/目录命名和编号对应。这样做是因为在 OpenHarmony 分支上网络图片加载的缓存机制还不够稳定本地资源是最不会出意外的方案。等核心流程稳定之后再考虑把高清图切到远端用轻量缓存方案兜底。3. 宝可梦图鉴数据建模与搜索打分算法实现3.1 图鉴数据模型从字段设计开始数据模型是整个搜索模块的地基。字段设计不好后续做多维度匹配会很痛苦。我这里的Pokemon模型核心字段如下class Pokemon { final int id; final String nameEn; final String nameZh; final ListPokeType types; // 如 [电] final double height; final double weight; final MapString, int baseStats; // hp, attack, defense... final String ability; final bool isMega; Pokemon({...}); factory Pokemon.fromJson(MapString, dynamic json) { return Pokemon( id: json[id], nameEn: json[nameEn], nameZh: json[nameZh], types: (json[types] as List) .map((t) PokeType.values.byName(t)) .toList(), height: (json[height] as num).toDouble(), weight: (json[weight] as num).toDouble(), baseStats: MapString, int.from(json[baseStats]), ability: json[ability], isMega: json[isMega] ?? false, ); } }id用整数而不是字符串因为它要和图片资源文件名直接拼接。types用枚举而不是字符串既避免拼写错误又能直接映射到中文显示和类型图标。baseStats用Map存种族值因为不同精灵的输出字段数量不完全一致Map 的容错性更好。顺便说一点我特意加了isMega标记因为图鉴里超级进化形态和普通形态往往是同号不同图用布尔标记比在名字里加“超级”两个字更利于搜索排序。3.2 搜索打分算法编号、中英文名、拼音、类型都能匹配最简单的搜索实现是用contains过滤列表但用户输入“025”或者“电”时contains很难给出合理的排序。我的方案是给每个精灵算一个“综合匹配分”所有评分大于 0 的结果按分数降序返回同时可以搭配类型、世代等筛选条件二次过滤。int calculateScore(Pokemon p, String query) { final q query.trim().toLowerCase(); if (q.isEmpty) return 0; // 完全匹配编号、英文名、中文名 if (${p.id}.padLeft(3, 0) q) return 100; if (p.nameEn.toLowerCase() q) return 95; if (p.nameZh q) return 95; // 前缀匹配 if (p.nameEn.toLowerCase().startsWith(q)) return 80; if (p.nameZh.startsWith(q)) return 78; // 拼音匹配 final py pinyin(p.nameZh, format: PinyinFormat.withoutTone).toLowerCase(); if (py q || py.replaceAll( , ) q) return 70; if (py.startsWith(q)) return 68; // 局部包含 if (p.nameEn.toLowerCase().contains(q)) return 60; if (p.nameZh.contains(q)) return 58; if (py.contains(q)) return 50; // 属性匹配例如输入“火”或“fire” for (final t in p.types) { if (t.nameCn q || t.nameEn q) return 40; } return 0; }为什么用打分而不是直接contains因为用户实际搜索时输入的字符质量参差不齐比如想查“妙蛙种子”输入了“妙蛙种”甚至只输入“妙”如果按contains线性过滤结果会非常长且顺序随机。打分排序保证“完全匹配 前缀匹配 拼音匹配 包含匹配 属性匹配”最接近用户意图的精灵永远排在最前面。对于 151 条数据全量计算评分没有任何压力如果未来数据到几千上万条可以考虑在加载时对中文名和拼音建立倒排索引但核心逻辑可以保持不变。这里还藏着一个小坑lpinyin对多音字处理不一定完美比如“耿鬼”的“耿”拼音结果在某些版本里可能不是预期的标准读音。所以我加了py.replaceAll( , )的归一化同时做首字母匹配。如果用户输入的是“gg”我会在代码里额外生成拼音首字母字段firstLetters在加载数据时预先计算好避免搜索时重复调用拼音库。3.3 状态管理用flutter_bloc管理搜索生命周期搜索页面有一个很典型的生命周期初始状态、加载中状态、有结果状态、空结果状态、错误状态。直接用TextField.onChanged改本地变量页面一复杂就会乱。我用flutter_bloc里的 Cubit 来管理因为它比 Bloc 少一层 Event 定义对这种单一异步操作足够轻。class PokemonSearchCubit extends CubitPokemonSearchState { PokemonSearchCubit({required this.repository}) : super(PokemonSearchInitial()); final PokemonRepository repository; Timer? _debounce; void onQueryChanged(String query) { _debounce?.cancel(); _debounce Timer(const Duration(milliseconds: 300), () { final trimmed query.trim(); if (trimmed.isEmpty) { emit(PokemonSearchInitial()); return; } emit(PokemonSearchLoading()); final result repository.search(trimmed); if (result.isEmpty) { emit(PokemonSearchEmpty()); } else { emit(PokemonSearchSuccess(result)); } }); } override void close() { _debounce?.cancel(); super.close(); } }为什么用 300ms 防抖因为宝可梦图鉴的数据量虽然不大但拼音转换和字符串评分在每次按键时都会执行如果把结果列表再配合图片渲染会对 OpenHarmony 开发板上的帧率造成明显压力。300ms 是一个视觉上几乎无感知、又能有效过滤无效计算的折中值。另一个关键点是close()里必须取消定时器否则 Cubit 释放之后定时器可能触发回调造成内存泄漏甚至崩溃。状态类的设计用sealed或者普通继承都可以我这里用了四个子类分别对应四种页面表现。UI 层只需要监听一个 Cubit用BlocBuilder做分支渲染代码非常干净后面加“搜索结果数量显示”“搜索历史”这类功能也比较顺手。4. 从数据结构到页面渲染搜索页与结果列表的UI落地4.1 搜索框、防抖与键盘适配细节搜索页顶部是一个TextField它承接用户输入但我不建议直接把onChanged回调接到 Cubit 上因为输入法联想和用户快速删除文字时会产生大量重复调用。我这里在 Widget 层再用一层防抖把同一个 300ms 的节奏统一管理起来。TextField( onChanged: (text) { context.readPokemonSearchCubit().onQueryChanged(text); }, textInputAction: TextInputAction.search, decoration: InputDecoration( hintText: 输入名字、编号或属性, prefixIcon: Icon(Icons.search), suffixIcon: ValueListenableBuilderTextEditingValue( valueListenable: controller, builder: (context, value, _) { return value.text.isEmpty ? SizedBox.shrink() : IconButton( icon: Icon(Icons.clear), onPressed: () { controller.clear(); context.readPokemonSearchCubit().onQueryChanged(); }, ); }, ), ), )键盘适配方面OpenHarmony 的软键盘弹起行为和 Android 有细微差异我在 Scaffold 外层包了resizeToAvoidBottomInset: true保证搜索框始终不被键盘遮挡。这里有个经验之谈不要在搜索框上过度依赖FocusNode做样式联动否则真机上点击外部收起键盘时容易出现焦点状态错乱。让Scaffold默认处理即可。清除按钮我用ValueListenableBuilder监听输入框内容而不是直接依赖 Cubit 里的状态这样纯 UI 的显隐逻辑不会触发额外的搜索流程。controller.clear()之后手动调用onQueryChanged()确保状态回到初始页显示热门精灵或者全部图鉴而不是留一个空白列表。4.2 结果卡片布局与图片加载策略结果列表我用卡片形式展示每张卡片左侧是精灵缩略图中间是中文名和英文名右侧是类型标签。卡片高度不算高配合ListView.builder足以应对 151 条数据的滚动。我没有一次性加载全部图片而是让卡片组件在滚动到可视区域时才加载对应的 asset 图片这个由ListView本身的懒加载机制完成。class PokemonCard extends StatelessWidget { final Pokemon pokemon; final VoidCallback onTap; override Widget build(BuildContext context) { return Card( child: InkWell( onTap: onTap, child: Padding( padding: EdgeInsets.all(12), child: Row( children: [ Image.asset( assets/images/pokemon/${pokemon.id}.png, width: 56, height: 56, fit: BoxFit.contain, errorBuilder: (_, __, ___) SizedBox( width: 56, height: 56, child: Icon(Icons.catching_pokemon), ), ), SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(#${pokemon.id.toString().padLeft(3, 0)}), Text(pokemon.nameZh, style: TextStyle(fontSize: 18)), Text(pokemon.nameEn, style: TextStyle(color: Colors.grey)), ], ), ), ...pokemon.types.map((t) TypeBadge(type: t)), ], ), ), ), ); } }图片加载策略上我特意用了errorBuilder做兜底。因为我发现 OpenHarmony 分支的 Asset 解析偶尔会有路径大小写问题某些图片加载失败时如果直接抛异常整个列表会崩掉。加了兜底以后即使某张图缺失列表也能正常滚动最多显示一个小图标占位。这个经验对现实世界的生产应用同样适用图片资源缺失不应该打断用户的浏览。类型标签我封装了一个TypeBadge小组件颜色由枚举映射比如火系用红橙色、水系用蓝紫色、草系用绿色。搜索模块只用到了类型的中文名和颜色后续如果要做属性相克表直接在同一个枚举上扩展方法就行。4.3 详情页跳转与通用组件抽象点击搜索结果卡片后跳转到精灵详情页。这个页面除了展示模型里已有的字段我还加了两个可视化维度种族值柱状图、属性标签组。种族值我直接用简单的StatBar组件画横向条不引入额外的图表库因为几行Container就能实现在 OpenHarmony 分支上减少一个原生依赖就减少一份风险。跳转时我没有用第三方的路由库而是直接用Navigator.push。原因很简单这个项目的页面层级很浅用自带路由足够过度封装会带来和平台适配相关的额外问题。如果之后“万能游戏库”要加底部 Tab、深链、跨页面传参再考虑引入go_router也不迟。通用组件的抽象在这里体现得很明显TypeBadge、StatBar、PokemonCard都放在core/widgets目录不依赖任何业务状态。以后做装备图鉴、卡牌图鉴这些组件可以直接复用。做任何 Flutter 项目我都建议遵守这个原则先让业务页面发现重复代码再抽象组件不要一开始就设计一个过大的组件体系。5. 真机调试与性能调优实录5.1 签名安装与日志排查OpenHarmony 真机调试和 Android 有些不一样设备连接后不能直接flutter run装到普通模式因为 OpenHarmony 安装应用需要签名。我在 DevEco Studio 里打开ohos工程让 IDE 自动生成签名配置然后再切回命令行执行flutter run -d device。没有有效的签名配置安装时会直接报install failed之类的错误这是新手最容易卡住的地方。日志排查方面Flutter 侧的日志可以通过flutter logs查看OpenHarmony 系统侧和应用框架的日志则用hdc shell hilog这类工具。我更推荐一个组合先在 OpenHarmony 原生工程里跑通一个最小化的 ArkTS 页面确认签名和装机链路没问题再回到 Flutter 侧跑项目。这样可以把“环境坏了”和“Flutter 代码坏了”两个问题迅速分开。实际调试中我依赖的排查顺序是确认设备能被flutter devices识别确认签名可用确认module.json5里的权限正确最后才去看 dart 代码逻辑。这四步里任何一步出错表现出的现象都可能像“App 闪退”或者“页面白屏”但没有这层排查顺序的话会浪费很多时间在无关代码上。5.2 列表滚动性能与渲染引擎151 条数据的列表在开发板上滚动理论上压力不大但 Flutter 在 OpenHarmony 上默认用的渲染路径还是比较传统的 Skia所以一旦卡片里图片很重、组件层级很深掉帧是很容易出现的。社区里经常讨论阿里 Flutter 团队做 60fps 优化的案例核心思路无外乎减少重建、减少图层合成、降低图片解码压力。我在这个项目里做了三件事第一给每个卡片包了RepaintBoundary把单张卡片的绘制隔离起来滚动时不会把整页都重绘第二给ListView.builder设置了itemExtent让列表项高度固定这样 Flutter 可以跳过一些布局计算滚动更顺滑第三卡片图片统一用固定尺寸避免运行时做大量缩放。关于 Impeller这个新渲染引擎在官方 Flutter 版本里已经逐步铺开但在 OpenHarmony 分支上是否启用、启用后的稳定性都要看对应分支的进度。我的建议是如果你的设备帧率还过得去就别折腾引擎开关如果某些页面滚动明显掉帧可以试试在flutter run时打开对应实验特性但前提是先备份一份当前工程因为引擎切换可能导致部分字体和阴影渲染效果变化。5.3 内存、图片缓存与字符串匹配损耗搜索模块的内存占用主要集中在图片资源。151 张本地小图如果全部加载进内存在低内存设备上可能有几十 MB 的峰值所以我特意避免了一次性预加载。滚动列表时图像会按需解码离开可视区域的卡片由 Flutter 引擎自动回收这样内存曲线是平稳的。字符串匹配损耗在 151 条数据上几乎可以忽略但我在数据加载阶段还是做了一个小优化把所有精灵的拼音全拼和首字母预先计算好存到模型里而不是在每次搜索时现算。这个改动让搜索接口从“每次输入都做昂贵转换”变成“每次输入只做字符串比较”对后续扩展到几千条数据有明显帮助。另外一个容易忽略的优化点搜索结果的Set去重。因为打分函数里“英文名包含”和“属性匹配”在特定输入下可能让同一只精灵命中多个规则如果没有去重列表里会出现同一张卡片体验非常糟糕。我直接在仓库层用LinkedHashSet保住稳定性分数相同的情况按id升序排列保证用户体验可预期。6. 常见问题速查与避坑清单6.1 构建与SDK相关的高频报错报错或现象出现场景解决方案flutter doctor提示SDK版本不完全支持使用了非对应分支的Flutter版本拉取OpenHarmony维护的专用分支检查分支提交与SDK API Level匹配度install failed无法安装到真机OpenHarmony签名未配置在DevEco Studio中配置自动签名或手动导入签名文件HTTP请求超时在OpenHarmony真机运行Flutter工程在module.json5中添加ohos.permission.INTERNET图片加载失败导致列表闪退Asset路径大小写或文件缺失使用errorBuilder兜底统一规范资源文件名中文乱码或字体缺失OpenHarmony设备字体库不完整在MaterialApp主题中指定中文字体资源或使用系统默认字体并测试字号环境类问题的另一个心得尽量给 OpenHarmony 的 Flutter 分支做一份独立的版本记录文件记录 SDK 提交时间、OpenHarmony API Level、DevEco Studio 版本。因为这类工具链迭代很快隔一个月回头排查问题时没有记录会非常痛苦。6.2 搜索相关的行为异常搜索模块本身也有几个容易翻车的地方。第一个是输入法联想导致的重复搜索。用户输入一个字后输入法弹关联词onChanged可能连续触发多次如果没有统一防抖页面会出现结果闪烁。第二个是拼音匹配的边界问题比如用户输入“miao”但“木守宫”在有些拼音库里的输出是“mushougong”命不中“miao”的用户。我给搜索逻辑加了一层“拼音首字母匹配”同时允许用户输入多个以空格分隔的关键词比如“cao xi”可以匹配“草系”这在一定程度上减轻了拼音库的局限性。第三个异常是多音字误判。典型的就是“耿鬼”的“耿”虽然按普通话是“geng”但部分拼音库在特殊组合下会输出异常。我的应对方式是在构建索引时不做额外纠偏而是把“中文名拼音首字母”作为独立字段和“全拼字段”同时参与打分用多路匹配来稀释单路错误的影响。用户实际搜索时只要任意一个索引命中了结果里仍然会出现目标精灵只是排名可能不在一二名整体可接受。6.3 社区资料与后续扩展建议如果在开发中遇到分支本身的问题我的建议是先去 OpenHarmony 组织下的 gitee 仓库翻 issues很多坑是已知问题已经有人给出了绕过方案。在 Flutter 侧也尽量少用太新的语法特性因为 OpenHarmony 分支的 Dart SDK 版本可能滞后于官方主线写高版本语法会编译不过。后续扩展方向上我个人觉得有三件事值得做一是把本地 JSON 数据源升级为增量更新通过网络拉取图鉴信息并缓存到本地这样“万能游戏库”才能真正覆盖所有世代的宝可梦二是加入多关键词组合过滤和排序例如“草毒高种族值”让搜索框成为一个结构化查询入口三是针对桌面和折叠屏形态再做一套宽屏布局OpenHarmony 的设备形态多样搜索页在平板和手机上可以有不同的展示密度。这次做下来我最真实的体会是OpenHarmony 上的 Flutter 开发虽然没有 Android 那么顺手但整条链路已经能跑通真实项目了。环境问题只要按顺序排查大多是有解的。宝可梦搜索这个东西数据规模不大可做的事情却很多非常适合做技术验证。如果你也想拿一个具体功能练手我建议就从这种带搜索、带列表、带详情页的小模块开始跑通一次之后你对整个 Flutter for OpenHarmony 的开发节奏会有完全不一样的感知。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。