首页 / 资讯中心 / 文章详情

Flutter跨平台开发鸿蒙应用:电影推荐Demo实战与避坑指南

Flutter跨平台开发鸿蒙应用:电影推荐Demo实战与避坑指南 ★ FEATURED ARTICLE
最近在折腾Flutter框架的跨平台能力时我被绕了一大圈之后才弄明白同一套Flutter代码能不能真正落到鸿蒙系统上正好手上有一个电影推荐APP的想法索性直接做成Demo跑通了从环境搭建、页面开发到鸿蒙真机安装的完整流程。这个项目没有用到复杂的云端架构核心就是“一套Dart代码多端显示”但在鸿蒙侧踩出来的坑确实比单纯做Android或iOS要多出好几倍。这篇文章就围绕这个电影推荐Demo把整体设计、环境搭建、关键页面实现、真机打包和常见问题全部分享出来适合那些准备在鸿蒙开发中引入Flutter但又不想一上来就啃大段源码的开发者。1. 先想清楚再动手——电影推荐APP在鸿蒙上的整体设计1.1 为什么选Flutter而不是其他跨平台方案在鸿蒙上做跨平台开发第一反应是“直接写鸿蒙原生不就好了”这话对只做一个端的场景成立。但如果是现有团队已经积累了Flutter代码或者产品需要同时交付iOS、Android和鸿蒙三端那跨平台框架的价值就出来了。我选择Flutter核心原因是它的渲染机制UI不是依赖系统原生控件而是由Flutter引擎自己绘制。这就意味着只要Flutter引擎能在鸿蒙上被跑起来页面呈现的视觉和交互逻辑就可以做到高度一致不需要像其他方案那样为鸿蒙重写大量原生控件。对比来看React Native这类依赖原生控件的跨平台框架在鸿蒙上需要维护一整套原生控件的映射工作量和稳定性风险都更高而轻量级的WebView套壳方案虽然简单但交互体验和离线能力都跟不上。Flutter的折衷点在于它牺牲了一点点对系统原生控件的依赖换来了最大限度的渲染一致性。鸿蒙侧的Flutter引擎已经有人在做持续适配虽然不能直接当作官方稳定版本用但跑通常规页面、动画、滚动列表完全可行。这个决策背后还有一个现实考量电影推荐APP的页面以图片列表、卡片、评分交互为主对UI一致性要求高对系统底层API的依赖比较少。把复杂的系统能力放原生侧把业务和UI放Flutter侧刚好能避开当前鸿蒙适配场景里的短板。所以整体的技术路线在动手之前就已经明确Flutter负责跨端业务逻辑和UI鸿蒙原生负责项目外壳、系统能力和签名打包。1.2 电影推荐APP的功能定位与页面架构这个Demo的定位不是做一个商业级产品而是验证一条完整的开发链路从数据获取、推荐排序、用户交互一直到鸿蒙上的安装运行。功能被刻意控制在五个核心模块里首页推荐流、电影详情、评分、收藏和“更多推荐”列表。这样既能把Flutter跨端能力展示出来又不至于让项目失去控制。页面划分上我做了三屏结构。首页是推荐的电影卡片流用户滑动浏览卡片上直接展示海报、标题、标签和评分点击卡片进入详情页详情页里可以评分、收藏同时根据当前电影的标签推荐三部相似影片收藏页负责汇总用户标记过的电影并按收藏时间排列。整体看下来三个页面已经覆盖了电影类APP最常用的闭环也足够用来验证导航、状态管理和本地数据持久化。页面与核心组件的关系可以参考下面这张表页面核心职责关键组件推荐首页展示按标签权重排序后的电影卡片流ListView.builder、电影卡片Widget电影详情页展示完整信息并支持评分、收藏评分组件、收藏按钮、相似推荐区域收藏页展示本人收藏过的电影收藏列表、空状态视图本地数据模块提供种子数据与本地缓存Movie模型、DataSource接口、JSON缓存这个结构在鸿蒙上完全是Flutter侧的自绘页面不需要针对鸿蒙重新布局。真机验证时我发现字体和圆角这类视觉细节比原生页面更容易保持一致这也是自绘引擎带来的直观收益。1.3 技术选型与依赖清单技术选型围绕“尽量少给鸿蒙适配增加负担”来定。状态管理采用Provider理由是它只依赖Dart层不碰系统控件而且ChangeNotifier的写法很容易理解。网络请求采用dio因为项目后续要切换到远程接口dio的拦截器、取消请求、超时控制都比较顺手。本地持久化用shared_preferences电影推荐场景只需要保存几个JSON字符串完全够用。图片加载用cached_network_image它能缓存网络图片避免在卡片流里频繁重复请求。不过这里有个非常关键的前提所有第三方依赖都要确认能在鸿蒙适配分支上正常工作。第三方包如果依赖了Android或iOS原生插件鸿蒙侧如果没有对应实现编译时不会报错运行时会直接闪退或功能缺失。所以我在项目初期只引入了上面几个纯Dart层插件或已有鸿蒙适配的插件其余能自己实现的绝不多加依赖。依赖清单可以按下表参考依赖版本建议用途flutter适配鸿蒙的分支版本避免用最新稳定版跨平台框架主体provider与当前Flutter版本兼容即可状态管理dio4.x或5.x网络请求shared_preferences支持鸿蒙的适配版本本地缓存cached_network_image支持鸿蒙的适配版本图片加载与缓存版本选择上我的建议是不要追新。鸿蒙适配分支往往滞后于Flutter官方版本如果你用了太新的Dart语法或者引入了太新的依赖最终return的可能是一堆编译错误。锁定一个稳定组合比什么都要重要。2. 搭建鸿蒙上的Flutter开发环境2.1 环境准备开始之前先把工具链准备好。我本机环境是Windows但这套流程在macOS上类似只是环境变量和路径会稍有变化。需要准备四样东西鸿蒙开发者工具、鸿蒙SDK、Flutter的鸿蒙适配分支、以及JDK。我建议先把鸿蒙开发者工具安装好因为它会自动带上一套匹配的鸿蒙SDK后续只需要在IDE里确认SDK路径。第一次启动IDE时SDK管理界面会提示是否下载SDK。建议把API版本和工具链都勾上尤其是构建工具和SDK组件缺少任何一个后面编译的时候都会报“组件缺失”。下载SDK其实没什么技巧耐心等完就行。比较推荐的做法是同时把模拟器也装好因为真机调试之前先用模拟器跑通流程能省下很多排队等待的时间。准备Flutter的鸿蒙适配分支也需要提前做。我一开始图省事直接使用官方Flutter稳定版结果构建鸿蒙包的时候直接提示找不到鸿蒙目标平台。这个坑在社区里很常见。Flutter官方版本目前只内置了Android和iOS等平台鸿蒙作为一个新系统平台需要用到专门的适配分支。把本机Flutter替换成适配分支之后flutter命令才会多出鸿蒙相关的构建能力。环境准备的操作步骤可以整理成这样安装鸿蒙IDE完成基础配置。安装鸿蒙SDK和模拟器镜像。下载或克隆Flutter的鸿蒙适配分支。将适配分支的bin目录加入PATH环境变量。在IDE里设置SDK路径确认flutter能识别到鸿蒙SDK。2.2 获取适配鸿蒙的Flutter引擎分支这一步是整个项目能否继续的地基。Flutter本身是一个跨平台引擎但鸿蒙不是它原生支持的目标平台所以需要找到维护鸿蒙适配的引擎分支。常见做法是从适配分支的发布页直接下载压缩包解压到本地然后把它当作普通的Flutter SDK来用。也可以用Git克隆分支我习惯用这种方式因为后续想查看引擎源码时更方便。克隆完成后需要把bin目录配置到全局PATH。在Windows上打开系统环境变量把类似C:\flutter_harmonyos\bin追加到PATH前面在macOS或Linux上直接写到shell配置文件的export语句里。配置完成之后在终端执行flutter doctor如果一切正常你应该能在诊断信息里看到鸿蒙相关工具链的状态至少不会像官方版那样只强调Android和iOS。这里必须强调一个细节以后所有Flutter项目都编译在这个分支下不要在你的项目目录里手动混合两个版本的Flutter SDK。我之前试过用官方版创建工程再切到鸿蒙分支构建结果flutter create生成的平台目录里根本没有鸿蒙目录后面只能重新创建工程。最稳妥的做法是一开始就用适配分支创建项目让项目的平台结构从一开始就包含鸿蒙。2.3 创建混合工程并打通原生入口拿到适配分支后创建工程的方式和普通Flutter工程没有本质区别唯一区别是flutter create时平台参数要加上鸿蒙目标。命令大致长这样flutter create --platformsohos,android,ios movie_recommend_demo执行完成后工程根目录下会多出一个ohos目录这就是鸿蒙的原生壳工程。接下来需要用鸿蒙IDE打开这个ohos目录或者打开整个Flutter工程并在IDE中识别它。此时会看到鸿蒙原生侧有一个入口模块这个模块相当于一个小容器Flutter引擎会把绘制结果渲染到这个容器里。原理解释一下你在Flutter侧写的所有页面、动画、手势最终都是Flutter引擎自己绘制完成的鸿蒙原生侧只负责提供一个窗口、把屏幕触摸事件传给Flutter引擎、把引擎渲染出的画面呈现出来。所以打通原生入口的关键就是让鸿蒙模块初始化Flutter引擎并加载Dart代码生成的产物。IDE通常会自动关联但如果你用的鸿蒙IDE版本较老可能需要手动添加原生依赖把Flutter引擎作为原生模块引入。打通入口之后我建议先在原生壳里放一个仅供验证用的按钮或页面确保鸿蒙壳本身没问题再开始写Flutter侧的业务代码。这能帮你把“原生壳问题”和“Flutter问题”隔离开排查时思路会清晰很多。2.4 验证最小Demo能跑起来第一步验证的目标只有一个让Flutter默认计数器页面跑在鸿蒙模拟器上。直接连接模拟器然后在终端执行flutter run -d ohos如果一切顺利你会看到IDE先执行编译再打包最后把应用安装到模拟器上。第一次构建的时间会稍微长一点因为引擎的鸿蒙适配层也需要参与编译。这个等待过程十分正常不用一看到长时间没反应就以为卡死了。默认计数器页面能在模拟器上点击并递增数字之后说明环境链路已经通了。接下来我会在这个基础上把工程清空替换成电影推荐Demo。这里还有一个小建议换成真机之前先做一次flutter build hap --debug或通过IDE构建hap包确认打包流程没问题。模拟器能跑不代表真机能装签名和安装权限是另一套问题留到后面统一处理。3. 电影推荐APP的核心细节解析与实操要点3.1 数据层接口封装与本地缓存干净的数据层能让后续换接口时少动UI。我在项目里定义了一个Movie模型包含电影ID、标题、海报地址、标签列表、评分和简介几个字段。Dart类写起来很直接class Movie { final String id; final String title; final String posterUrl; final ListString tags; final double rating; final String summary; Movie({ required this.id, required this.title, required this.posterUrl, required this.tags, required this.rating, required this.summary, }); factory Movie.fromJson(MapString, dynamic json) { return Movie( id: json[id] as String, title: json[title] as String, posterUrl: json[posterUrl] as String, tags: ListString.from(json[tags] as List), rating: (json[rating] as num).toDouble(), summary: json[summary] as String, ); } MapString, dynamic toJson() { return { id: id, title: title, posterUrl: posterUrl, tags: tags, rating: rating, summary: summary, }; } }数据源层面我定义了一个抽象接口MovieDataSource只暴露一个方法FutureListMovie fetchMovies()。第一个实现是LocalDataSource从本地JSON文件读取种子数据这样Demo在没有服务器的时候也能跑第二个实现是RemoteDataSource用dio请求远程接口并解析成电影列表。UI层只依赖抽象接口所以切换数据源时不改页面代码。这里还有一个容易被忽略的实操点启动时读取本地缓存的速度非常快但如果缓存里已经有旧数据直接用旧数据渲染会让用户看到过期内容。我在Demo里的做法是先展示缓存数据再后台请求远程接口接口返回成功后更新列表并重写缓存。这看起来是很常规的做法但它对体验的提升非常明显尤其是在鸿蒙模拟器网络不稳定的场景下至少不会白屏。3.2 推荐算法简单但有效的标签权重方案电影推荐如果直接用协同过滤数据量不够时效果反而很弱。我采用的是标签权重打分方案思路非常简单用户每对一部电影做出正向反馈比如收藏或给出高于3分的评分就把这部电影的标签累加到用户偏好向量里。推荐候选电影时用它包含的标签去匹配用户偏好向量匹配分越高排序越靠前。代码上维护一个MapString, double userProfilekey是标签名value是权重。这个映射在状态管理类里维护每次收藏/评分都会触发更新。排序前先每部候选电影算分再把所有电影按分值降序排列。打分逻辑的核心就几行double _scoreMovie(Movie movie, MapString, double userProfile) { double score 0; for (final tag in movie.tags) { score userProfile[tag] ?? 0; } return score; }为了让结果更自然我会在基础分上再加一点热度分。热度分可以来自电影本身的评分或者预设的播放量数据。但要注意热度分权重不能盖过用户偏好否则用户看来看去都是排行榜上的热门片推荐就失去了个性化。在Demo里热度分的权重只占0.2用户标签匹配分占0.8。这个比例是我手动调出来的具体项目可以根据实际反馈重新调整。这个方案虽然简单但已经能产生“看过一个科幻片首页就会多推科幻片”的可感知效果。它最大的优点是完全在Dart层实现不依赖任何鸿蒙或Android原生能力所以跨端一致性非常好。3.3 UI层卡片式推荐流的实现首页的推荐流是电影推荐APP最重要的门面。我使用ListView.builder做长列表每个item是一张电影卡片。卡片结构从左到右依次是海报缩略图、电影信息和右侧的收藏按钮下部是标签行和评分。卡片之间用间距分开整体背景做成深色这样海报图片的对比度会更高具体界面看起来也会更像一个观影产品。电影卡片的核心实现可以概括为Widget _buildCard(BuildContext context, Movie movie) { return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: () Navigator.push( context, MaterialPageRoute(builder: (_) MovieDetailPage(movieId: movie.id)), ), child: Padding( padding: EdgeInsets.all(12), child: Row( children: [ Image.network( movie.posterUrl, width: 80, height: 120, fit: BoxFit.cover, errorBuilder: (_, __, ___) Container( color: Colors.grey[800], child: Icon(Icons.movie), ), ), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(movie.title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), Wrap( spacing: 6, children: movie.tags .map((tag) Chip(label: Text(tag), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap)) .toList(), ), Text(评分${movie.rating.toStringAsFixed(1)}), ], ), ), IconButton( icon: Icon(isFavorite ? Icons.favorite : Icons.favorite_border), onPressed: () context.readRecommendationModel().toggleFavorite(movie.id), ), ], ), ), ), ); }这里有几个UI细节值得说。第一海报图片必须提供errorBuilder。推荐流里图片一旦有一张挂掉占位容器如果没做整个卡片的高度会塌掉列表顺序就会跳动。第二标签用Wrap而不是Row因为电影标签个数不固定超过屏幕宽度时自动换行会更稳。第三收藏按钮的点击区域要足够大但卡片上的InkWell会导致按钮点击时出现双层水波纹所以我会把收藏按钮单独包一层避免和卡片的点击手势冲突。3.4 状态管理从setState到Provider的决策过程最开始图省事所有页面直接setState结果写了几个页面之后发现回调传参很乱。比如收藏页要同步首页的收藏状态详情页评分之后还要回到首页重新加载列表这种跨页面的数据同步用setState真的会写到崩溃。后来我把状态提升到一个全局的RecommendationModel里用Provider做依赖注入。这个Model继承了ChangeNotifier里面维护电影列表、收藏ID列表、用户标签偏好和当前推荐顺序。任何页面通过context.readRecommendationModel()拿引用修改状态后调用notifyListeners()UI自动重建。选择Provider而不是其他方案主要是因为它足够轻。在鸿蒙适配分支上第三方状态管理库如果依赖原生能力反而会增加适配风险。Provider的依赖只在Dart层不会去碰原生控件所以它能直接跟随Flutter引擎在鸿蒙上跑。真机验证下来Provider的刷新频率和UI重建都没有异常这个项目用它完全够。4. 实操过程关键环节的完整实现4.1 首页推荐流的页面代码实现先搭建一个最基础的首页。首页在启动时会从Model里异步加载数据通过Consumer监听状态变化。完整页面结构大概是这样class HomePage extends StatelessWidget { const HomePage({super.key}); override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(电影推荐)), body: ConsumerRecommendationModel( builder: (context, model, child) { if (model.isLoading model.movies.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (model.movies.isEmpty) { return const Center(child: Text(暂时没有可推荐的电影)); } return ListView.builder( padding: const EdgeInsets.all(12), itemCount: model.movies.length, itemBuilder: (context, index) { final movie model.movies[index]; return MovieCard(movie: movie, isFavorite: model.isFavorite(movie.id)); }, ); }, ), ); } }这里有一个很重要的小细节model.isLoading model.movies.isEmpty这个条件是为了区分“首次加载”和“刷新数据”。如果数据已经在缓存里加载远程接口时不应该把整个页面换成加载转圈否则用户每次进首页都会闪一下白屏。鸿蒙模拟器上可能不明显但真机和低配设备上这个闪烁会被放大。MovieCard组件我切成单独一个文件里面接收电影对象和收藏状态不直接依赖全局Model。这样做的理由是卡片在列表里会频繁重建让它保持“哑组件”身份只根据传入参数渲染内存和刷新成本都更低。4.2 评分与收藏功能的联动评分和收藏是推荐算法的输入所以这两个功能不是孤立存在的。详情页里用户给某部电影打了5分这个信号要能改变后续的首页推荐顺序。我在Model里设计了三个核心方法。toggleFavorite负责切换收藏状态updateRating负责更新评分二者都会触发_applyUserPreference来更新标签偏好然后重新计算推荐列表。void toggleFavorite(String movieId) { if (_favoriteIds.contains(movieId)) { _favoriteIds.remove(movieId); _subtractPreference(movieId); } else { _favoriteIds.add(movieId); _addPreference(movieId); } notifyListeners(); _reorderRecommendations(); }评分联动逻辑类似但评分是连续的所以更加细腻3分以下不增加权重3分以上按分数线性增加。这个阈值来自一个很朴素的产品假设用户愿意给高分意味着他喜欢这类标签给低分说明他不喜欢。这里踩过的一个坑是每次调用_reorderRecommendations都会创建一个新的排序列表而用户连续滑动时如果频繁触发评分和收藏列表会反复重建导致卡片跳动。解决方法是做一次防抖收藏和评分的触发频率都不高但在真实使用中仍要注意。我最终在_reorderRecommendations里加了300毫秒的延迟只有用户停止操作后才做最终排序。4.3 鸿蒙打包与真机调试实录功能都写在Flutter侧之后真正的考验才开始把它变成一个能在鸿蒙真机上安装的hap包。我先在鸿蒙IDE里打开ohos目录然后配置签名。对个人开发者来说最方便的是使用IDE的自动签名能力它会自动创建调试证书和Profile并把当前设备的标识加到允许列表里。签好名之后可以在IDE里直接选择构建产物也可以回到命令行执行flutter build hap --release。我试过两种方式IDE构建更适合排查编译错误命令行更适合集成到持续集成流程。Release包构建完成后会在工程目录下生成一个hap文件接下来连上真机开启开发者模式通过IDE的安装工具把这个hap推送到设备上。第一次真机安装时应用启动比模拟器慢一些这是因为Release包首次启动时要做一些引擎初始化。启动完成后首页的卡片流滚动很流畅评分和收藏的点击响应也没有明显延迟。整个过程说明用Flutter在鸿蒙上做电影推荐类的交互页面性能上是可行的。4.4 性能优化检查内存泄漏与滑动流畅度做完功能后我用IDE自带的性能分析工具看了一下首页的GPU和内存曲线。主要观察两个点一个是滑动列表时是否持续掉帧另一个是内存是否只涨不降。如果出现卡片在滑动过程中闪烁或掉帧优先检查图片加载。cached_network_image本身有缓存但我发现当海报图尺寸太大时解码耗时依然很高。解决办法是让后端或数据源提供按宽度裁剪的缩略图Demo里则手动限制海报宽度为200像素左右。这个优化虽然小但效果显著。内存泄漏方面最容易出问题的是一些异步回调没有取消。比如页面已经退出网络请求才返回这种情况下如果不判断组件是否仍在树中Model回调就会指向已经不存在的页面。我的做法是在所有需要取消请求的地方使用异步辅助工具或者在State的dispose阶段置一个_isDisposed标志回调里先判断再更新UI。这个习惯在鸿蒙上同样适用真机长时间滑动后内存曲线会比不做处理平稳很多。5. 常见问题与排查技巧实录5.1 编译报错“找不到鸿蒙引擎”这个报错几乎每个初上手的人都会遇到。现象是命令行构建时提示找不到鸿蒙SDK或者OHOS相关路径。原因通常是IDE的SDK路径没有传递给Flutter适配分支。解决方法是在工程根目录下维护一个配置文件把SDK路径写进去。配置内容大致是ohos.sdk.dir/path/to/your/harmonyos/sdk写完配置后重启IDE再执行flutter doctor确认鸿蒙工具链能识别。如果仍然报错检查环境变量里是否残留了旧版Flutter的指向。把旧版Flutter从PATH里挪掉确保终端输入flutter --version时是鸿蒙适配分支这个根因就能排除一大半。5.2 中文乱码与字体适配我在鸿蒙模拟器上碰到过一次比较尴尬的情况英文和数字显示正常中文标题全部变成方块。罪魁祸首是鸿蒙适配分支在渲染中文时默认字体回退不完整。这个现象在Android上不容易出现因为系统里预装了大量中文字体但鸿蒙适配分支不能完全依赖系统字体。解决办法有两种。第一种是在MaterialApp的主题里显式设置字体family让Flutter优先使用自带或项目打包的中文字体第二种是把一个中文字体文件放进assets并在pubspec.yaml里声明。Demo里我采用的是第二种因为字体的视觉一致性更好。这一步看着小但如果没做好整个APP的中文界面会非常影响观感。5.3 网络请求在鸿蒙上失败因为Demo一开始用本地数据我直到后期才接入远程接口结果一接入就在鸿蒙模拟器上遇到超时。排查下来有两个原因。第一鸿蒙应用默认没有网络权限必须在原生侧配置文件里声明网络权限第二如果接口是http明文地址在部分调试模式下会被直接拒掉。解决办法是在鸿蒙模块的配置里补上网络权限声明并把调试环境的接口地址改成https。如果后端暂时没有https证书本地调试可以临时开启明文流量但正式包一定不要这么干。对Demo来说最保险的方式还是以本地种子数据跑通主要链路远程接口后续再按需调整。5.4 真机无法安装/签名问题最让人头疼的问题是模拟器上跑得好好的真机却提示安装失败或签名校验失败。这通常是签名信息不对造成的。鸿蒙真机要求hap包必须使用包含当前设备标识的调试证书签名自动签名只对勾选过的设备生效。解决办法是回到IDE打开签名配置重新生成自动签名并确保当前真机已经被连接并被识别。如果设备之前被移除需要重新添加设备标识再重新构建hap。这里的一个重要提示是每次更换调试设备都要重新签名别拿上一台机器的包往新设备上硬塞。5.5 避坑速查表场景典型错误处理方式创建工程flutter create后没有ohos目录使用鸿蒙适配分支创建不要混用官方版编译找不到鸿蒙SDK在配置文件中指向鸿蒙SDK路径中文显示中文变方块项目内打包中文字体并显式声明网络请求超时/请求失败声明网络权限并改用https地址真机安装签名校验失败重新生成包含当前设备的自动签名列表卡顿滑动时明显掉帧压缩海报图并检查显式高度这张表是我在完整跑完项目之后整理出来的基本覆盖了新人在鸿蒙上遇到的主要问题。如果你按照这个顺序排查绝大多数情况都能快速定位。6. 最后说点个人体会这个项目做完之后我对Flutter跨平台和鸿蒙开发都有了新的认识。先说结论Flutter在鸿蒙上跑通业务是能做到的但前提是别对“开箱即用”抱有期待。鸿蒙侧的适配分支还在快速迭代我建议把项目运行关键依赖的版本固定住不要因为看到新版本就盲目升级每次升级都可能带来引擎行为的变化升级前先在最小工程里验证。还有一个很深的体会是做鸿蒙适配时问题排查一定要学会“切分”。遇到报错先确认是鸿蒙原生壳的问题还是Flutter层的问题还是数据层的问题。别一上来就翻页面代码。我这次很多时间其实花在了环境配置和签名上真正写页面逻辑只占了一小部分。如果你也能把环境调试和业务开发分开项目推进起来会顺很多。最后分享一个小技巧遇到鸿蒙上诡异的显示或运行问题时先建一个最小还原Demo。把一个列表、一个网络请求、一个字体页面分别拆出来验证定位到具体现象再回到完整项目里修。这比在完整APP里盲猜要高效得多。电影推荐APP只是个起点后面还有缓存策略、离线推荐、推送这些可以继续扩展先把地基打牢后面的路才好走。
阅读完成 · 觉得有帮助?
咨询建站