1. 文言文翻译这个需求,为什么值得用Flutter做成鸿蒙App?
先交代一下背景。前阵子有个朋友找我,说家里孩子上初中,语文课开始啃文言文了,白天在学校听老师讲《出师表》还能听懂七八成,晚上回家做作业翻参考资料,遇上没见过的实词虚词还是得一个个查,查半天还不一定查得准。他问我能不能做一个专门针对文言文翻译的小工具,最好手机上就能用,不用装一堆臃肿的软件。
我当时的第一个念头是:这需求其实不算小众。国内初高中学生几千万,文言文是语文考试的固定板块,断句、实词、虚词、翻译又是多数学生的老大难。市面上的古汉语词典要么收词不全,要么解释太学术化,要么界面做得像上世纪的产品,真正适合学生随手查的体验型工具几乎没有。所以做一个轻量、干净、翻译结果直白的文言文翻译App,确实有真实场景在支撑。
那为什么非要扯上Flutter和鸿蒙?因为朋友家里主力设备正好是华为手机,他要求App先在鸿蒙上跑顺,后续再考虑上iOS和安卓。如果只用HarmonyOS原生那套ArkTS写,等于从头做一遍,后续还要维护三个平台三套代码,对一个人力有限的小项目来说完全不划算。Flutter的跨平台特性正好卡在点上:一套Dart代码,UI逻辑全部复用,鸿蒙、安卓、iOS三端都能跑,只是鸿蒙这端需要额外做一层适配。
所以这篇文章我打算把完整的开发流程摊开来讲,从工程环境搭建到核心翻译功能实现,再到真机调试和发版前的检查项,全部按我实际跑通的顺序来写。内容偏实战,适合已经会用一点Flutter但没在鸿蒙设备上跑过项目的开发者,也适合那些正在纠结“要不要用Flutter接鸿蒙”的团队参考。
我个人判断,短期之内Flutter和鸿蒙的关系会越来越像当年Flutter和安卓那样——不是谁取代谁,而是融合。ArkTS原生开发照样有它的生态位,但Flutter这种跨端框架在鸿蒙上的价值会随着设备量增长被更多人看到。下面开始进入正题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 新手最容易翻车的Flutter鸿蒙开发环境搭建
很多人在鸿蒙上用Flutter跑项目,第一步就卡住了。原因很简单:鸿蒙不是安卓,Flutter官方发布渠道对鸿蒙的支持还处于“社区适配+官方开放”的阶段,你不能像配安卓SDK那样装完就万事大吉。我按自己的踩坑顺序,把完整流程拆出来。
2.1 前置准备:版本选择比安装更关键
先说结论:开发机Windows和macOS都能用,但我更推荐Windows来做这一轮验证,因为鸿蒙生态里的工具链对Windows的兼容性最成熟,遇到问题的解决方案也最多。
需要准备的东西有这几样:
- Flutter SDK,版本建议用3.7.x左右的稳定分支,太新或太旧的版本对鸿蒙适配支持都不好。这个版本号很关键,因为Flutter官方对鸿蒙的支持力度在不同版本之间差异很大。
- DevEco Studio,也就是鸿蒙的IDE,用于创建鸿蒙工程壳、打包HAP、管理签名。一般用3.1及以上版本。
- Node.js,鸿蒙工具链里有几个脚本依赖Node环境做资源编译。
- OpenHarmony的SDK。这个就是让Flutter代码最终能变成鸿蒙应用的编译底座。
其中最容易让人懵的是OpenHarmony SDK。请注意,这里说的是OpenHarmony(开源鸿蒙)的SDK,而不是HarmonyOS(商用鸿蒙)的SDK。两者的区别简单理解:HarmonyOS是华为手机实际运行的系统,OpenHarmony是它的开源底座。Flutter目前适配的是OpenHarmony这一层,你在开发阶段用的是开源版本的SDK,但编译出来的产物能安装到HarmonyOS手机上跑,因为底层ABI是兼容的。我实测下来,用OpenHarmony SDK编出来的HAP包能正常装进HarmonyOS设备,没遇到兼容性问题。
2.2 把flutter_flutter仓库切到OpenHarmony分支
Flutter官方仓库本身不直接带鸿蒙引擎,社区的解决办法是使用三方的flutter_flutter仓库。具体操作是这样:
bash复制git clone https://github.com/OpenHarmony-sig/flutter_flutter.git
cd flutter_flutter
git checkout OpenHarmony-3.7
这里有一个重点:这个仓库的构建产物才是带OpenHarmony引擎的Flutter工具链。你之后所有flutter命令都要通过这条路径下的bin/flutter来调用,不能再用系统PATH里那个普通Flutter,否则编译鸿蒙工程时会报找不到ohos模块。
路径配好之后,最好设置环境变量,把flutter的bin目录加进去。然后运行:
bash复制flutter doctor
正常的话,在输出里能看到类似“Flutter (OpenHarmony)”的条目,这就说明工具链已经就绪。如果看不到,大概率是版本没切对,或者是环境变量仍然指向旧版Flutter。
2.3 DevEco Studio里新建鸿蒙壳工程
Flutter代码本身不直接打包成HAP,它需要先有一个鸿蒙工程作为宿主壳,Flutter编译出的产物以模块形式嵌入到这个壳里。这里的逻辑跟Flutter接iOS类似:iOS端需要一个Xcode工程壳来打包ipa,鸿蒙端则用DevEco的工程做壳。
具体操作:用DevEco Studio新建一个Empty Ability工程,包名按你自己的域名反写来填,比如com.example.wenyan。建好之后,把Flutter模块用命令行挂进去。鸿蒙SDK目录里提供了一个工具脚本,大概长这样:
bash复制flutter create --platforms ohos wenyan_app
如果你的flutter工具链已经带ohos平台支持,这步会直接生成带ohos目录的Flutter工程。如果没有,就得手动在DevEco工程里创建Module,引入flutter的ohos插件包。个人经验:直接跑上面的命令最省事,省去在IDE里各种图形化配置的麻烦。
2.4 环境配置中我踩过的三个坑
第一个坑:flutter create之后工程目录里没有ohos文件夹。这种情况十有八九是Flutter版本旧了,或者没有把flutter_flutter仓库的bin目录放进PATH。我一开始就是因为PATH里既有普通Flutter又有Flutter for OpenHarmony,命令被旧的拦截了。
第二个坑:运行flutter doctor时提示找不到ohos sdk。原因多半是OHOS_SDK_HOME环境变量没设置,或者设置路径指向了HarmonyOS的SDK而不是OpenHarmony的SDK。这个变量要指向你下载的OpenHarmony SDK根目录,里面必须能看到ohos-sdk这样的子目录才算对。
第三个坑:依赖下载慢。国内网络环境下,pub.dev经常连不上,需要配置镜像源。在环境变量里加:
bash复制PUB_HOSTED_URL=https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
然后重启终端再试。这三个坑我花了差不多一整个下午才全部绕过去,提前写出来,你们能省不少时间。
3. 从零拆开文言文翻译App的页面与词库设计
环境通了之后,先别急着写翻译逻辑,想清楚App到底要有哪些功能模块。这个步骤决定了后面开发是顺畅还是反复返工。
3.1 文言文翻译App的三大核心模块
一个真正能用的文言文翻译工具,至少要有三层能力:
第一层是输入与理解:用户输入一段文言文,可能是几个字的成语,也可能是一整段原文。App要能处理完整的句子,在翻译前先做断句和分词,把连续的文字切成一个个有意义的单位。
第二层是查询与翻译:切分出来的词语要在词库中找到对应的释义。文言文和现代汉语最大的区别在于一词多义现象极其普遍,“之”可以是助词、代词、动词,“谢”可以是感谢、道歉、辞别、调落。所以词库不能只存一个意思,必须按词性、语境、常见句式分开存储。
第三层是输出与学习辅助:翻译结果不能只给一行白话文,最好能标注出关键词的用法,比如哪些是通假字、哪些是词类活用、哪些是特殊句式。这个对学生用户来说价值非常大。
我最终把App结构定为三个页面:首页(搜索+翻译结果)、词库页(按教材单元分类的常用词表)、收藏页(用户翻译过的句子和查过的词)。页面不多,但每个页面的信息密度都做得比较高。
3.2 词库结构设计:不只存释义,还要存例句和用法
词库是整个App的地基。如果词库质量不行,后面翻译功能做得再花哨都是空中楼阁。我是以人教版初高中语文教材为主要蓝本,手动整理了一份初始词库,覆盖了教材里出现频率最高的三百多个实词和二十多个虚词。
每条词目的数据结构大概是这样的:
dart复制class WenyanWord {
final String name; // 词汇本体,比如“殆”
final String pinyin; // 拼音
final List<Meaning> meanings; // 多个释义
final List<String> examples; // 例句,文言文原文
final List<String> translations; // 例句对应的白话译文
final String usage; // 语法提示:通假、词类活用、古今异义
}
每个Meaning里再细分子字段:词性(名词/动词/形容词/虚词)、释义文本、常见搭配、例句编号。这样设计的好处是,后续做翻译时可以直接按“词性+语境”做匹配,而不是傻傻地取第一个释义。
虚词的处理要特别用心。“之、其、而、以、于、则、乃、且、若、为”这十个虚词是中高考的高频考点,每个词都有少则五种、多则十几种用法,比如“之”的六种常见用法应该被单独建表,按语法功能分层。我在这部分花的时间最长,但收益也最大,因为用户搜索最多的就是这些词。
3.3 分词器:没有分词就没有翻译
文言文和现代汉语不一样,它没有空格来区分词语,甚至没有标准标点,全靠读者自己断句。我做了一个轻量级的MaxMatch分词器,思路很简单:从左往右扫描,每次尽量匹配最长的已知词条。
比如“学而时习之”,先看“学而时习之”这个整体在不在词库,不在;再看“学而时习”,不在;一步步收缩到“学”,命中,记录;接着处理“而时习之”,继续收缩匹配,匹配到“而”,然后是“时”,最后是“习”和“之”。这种贪心匹配算法效率很高,对长句也能做到线性扫描,而且对词典的完整性要求极高——词库里的词越全,分词结果越准。
当然,实际使用中会遇到词库没覆盖的词。我的兜底方案是按单字切分,每个字作为独立词条参与翻译,如果单字也是生僻字且词库没有,就保留原文并标记“未收录”。这个逻辑虽然简单粗暴,但很实用,至少不会让用户看到一堆乱码。
4. 组件通信与Provider状态管理:把三块功能串成一个应用
页面结构定好之后,接下来要解决的是Flutter里最让人头大的问题:页面之间怎么共享数据,状态变了怎么通知界面刷新。我直接用了Provider这套方案,下面详细说说为什么选它、怎么接入。
4.1 为什么是Provider而不是setState或Bloc
Flutter的状态管理方案多到能写一本书,但对这个项目来说,Provider是最务实的选择。原因有三:第一,它基于InheritedWidget实现,是Flutter官方的设计哲学,不需要引入大量第三方概念;第二,API简单,几行代码就能让一个模型对象变成全局可监听的状态;第三,社区资料多,遇到问题搜一下基本都有答案。
setState当然也能用,但只限于单个页面的局部状态。像翻译历史、收藏列表这些需要跨页面共享的数据,用setState管理会非常痛苦,你得手动把数据传来传去,每改一处都要小心翼翼。Bloc又太重型,对一个小工具类App来说,引入event和state两套类体系完全是杀鸡用牛刀。
4.2 Provider接入的四步流程
第一步,在pubspec.yaml里加依赖:
yaml复制dependencies:
provider: ^6.0.5
第二步,定义状态类。比如收藏列表的状态类:
dart复制class FavoriteModel extends ChangeNotifier {
List<FavoriteItem> _items = [];
List<FavoriteItem> get items => _items;
void add(FavoriteItem item) {
_items.add(item);
notifyListeners();
}
void remove(String id) {
_items.removeWhere((e) => e.id == id);
notifyListeners();
}
}
这里继承了ChangeNotifier,它自带一套通知机制:数据变化时调用notifyListeners(),所有监听这个模型的组件都会自动重建。这一步的核心点就是要理解:Provider的作用不是存储数据,而是把数据变化“广播”出去。
第三步,在main.dart里用MultiProvider包裹整个应用:
dart复制void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => FavoriteModel()),
ChangeNotifierProvider(create: (_) => TranslationHistoryModel()),
],
child: WenyanApp(),
),
);
}
MultiProvider的好处是可以一次性注册多个全局状态对象,避免Provider嵌套地狱。
第四步,在页面上通过context.watch或context.read来使用状态。watch用于监听——数据一变,当前组件就重建;read用于一次性读取——我只想拿个当前值,不想监听变化。
dart复制final favoriteModel = context.watch<FavoriteModel>();
final itemCount = favoriteModel.items.length;
用起来真的很简单。但简单归简单,有几个细节必须注意:
- build方法里不要写耗时操作,否则每次notifyListeners都会卡界面。
- 不要在build方法里用context.read来读需要响应变化的值,否则界面不会刷新。这个错误非常隐蔽,我调试了很久才发现问题出在read和watch的选择上。
- 收藏列表和翻译历史的模型要设计成独立类,不要混在一个大模型里,否则任何一个小改动都会触发全局刷新,浪费性能。
4.3 组件通信的三种选择:回调、EventBus和Provider
聊完横向的状态共享,再补一个纵向的组件通信问题。Flutter的组件树是父子关系,父组件和子组件之间怎么传消息?我实际用下来,主要有三条路。
最简单的是构造函数传参加回调。子组件定义时声明一个回调函数,比如输入框文字变化时调用onChanged,父组件在构造子组件时把处理函数传进去。这种方式适合层级不深、逻辑简单的场景,代码直白没有额外依赖。
第二种是使用EventBus。当两个完全不相干的组件要通信,又不想通过父组件中转时,EventBus就派上用场了。比如用户在一个页面点击收藏,需要让另一个页面也同步更新角标,这时可以发一个FavoritesChangedEvent,订阅方收到事件后自行处理。但这个方案要慎用,因为事件多了以后,代码的调用关系会变得难以追踪,调试起来像在查悬案。
第三种就是上面讲的Provider,适合跨页面共享状态。我的原则是:父子关系优先用回调,无关组件优先用Provider,EventBus留着做事件通知而不是数据管理。
我在这个项目里的具体分工是:原文输入框和翻译结果区是父子关系,用回调传递输入内容和翻译动作;收藏按钮跨页面同步更新,通过FavoriteModel这个Provider来统一管理;翻译历史列表和收藏列表都监听各自的Provider,互不干扰。
5. 文言文翻译核心:断句、分词与古文白话转换逻辑
页面和状态管理做完了,真正的重头戏才刚开始——文言文怎么翻译成白话文。这里面的难点和大部分人对翻译软件的想象完全不同,我分开讲。
5.1 断句是翻译的第一步,先解决“从哪里断”的问题
现代白话文有标点,读起来毫无障碍。但文言文在原始文本里是没有标点的,或者说句读本身就是一种学术能力。用户从网上复制来的文言文段落,很多时候也根本没有任何标点符号,这就导致翻译器根本不知道该把哪几个字当成一个句子来处理。
我采用的断句策略是三步走:
第一步,先根据明显的句末语气词切分。文言文里“也、矣、焉、耳、乎、哉、耶、欤”基本都是句尾标志词,碰到这些字优先断句。
第二步,在没有语气词的段落里,根据句子结构特征推断。比如主语出现、动词短语完整、出现“曰”“谓”等引语动词,都可能是断句的边界。
第三步,如果上面两步都没有结果,那就按语义切分。把整段文字送入分词器,按词之间的关联强度来分组。这个方法准确性不算最高,但作为兜底已经很够用。
实际操作时,我也加了一个小技巧:把常见的文言文固定句式做成正则表达式。比如“其……乎”表推测语气,“不亦……乎”表反问,“何以……为”表疑问,这些结构一旦匹配成功,就可以直接把手夹在中间的内容当成一个分句。正则匹配的速度极快,几百字的段落在手机上也不过是几毫秒的事。
5.2 翻译引擎选型:本地词库优先,在线接口兜底
断句和分词只是前置处理,真正决定翻译质量的是词义匹配和句子组装。我在开发时评估过三种方案,做了一个对比:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 纯本地词典规则引擎 | 离线可用、响应快、数据可控 | 覆盖有限,复杂句式翻译生硬 | 常用词查询、教材同步学习 |
| 在线翻译API | 覆盖广、翻译流畅 | 依赖网络、有调用成本、古文效果不稳定 | 生僻文本、长段落翻译 |
| 本地词库优先+在线API兜底 | 兼顾速度和覆盖面 | 需要维护两套逻辑 | 综合型工具App |
我最后选了第三种方案。具体逻辑是:先本地跑一遍,如果段落里每个词都在词库里找到了释义,而且句式属于常见句式的匹配范围,那就直接用本地引擎出结果,完全离线。如果出现了未收录词,或者句式过于复杂,本地引擎无法组装出通顺的白话文,就调用在线翻译接口做兜底。
在线接口我采用的是免费的古文翻译API,这样用户基本没有使用成本。但要特别注意一个问题:在线接口对文言文的翻译质量其实很不稳定,有时候翻得像模像样,有时候各种“人工智障”级别的错误。所以我的策略里设置了“优先展示本地翻译结果、在线结果作为备选摘录”的模式,用户可以在界面上切换查看两个结果。这个设计学生党很喜欢,因为可以对照参考。
5.3 古文白话转换的规则引擎:三种句式的处理
本地引擎的核心可以分为三块:实词翻译、虚词翻译、句式重组。
实词翻译相对简单,在词库里查释义,按频率选择最常用的意思。文言文里“走”是跑的意思,“去”是离开的意思,“怠”是疲倦的意思,这些直接映射就好了。
虚词是最难的,因为它们本身没有实际含义,只起语法作用。我的方案是按语法位置来匹配用法。举个具体例子,“之”的六种用法:
- 在“动词+之”结构中,作代词,指代人事物,译为“他它”。
- 在“形容词+之+名词”结构中,作助词,相当于“的”。
- 在“主谓之间”时,取消句子独立性,不译。
- 跟“所”“其”等组合成“之所以”“其……之”固定搭配时,按固定搭配处理。
- 在“何……之有”这种宾语前置句式中,作助词,表强调。
- 在动词前作动词,意为“去、往”。
这些规则的判定顺序是有讲究的。我一开始是顺序执行,后来发现一个“之”同时符合多个条件时会选错。改成优先级加权之后效果好多了——先判固定搭配,再判句法位置,最后判语义角色。
句式重组这块,主要处理倒装句和省略句。比如宾语前置句“何陋之有”,正常语序是“有何陋”,白话翻译应该是“有什么简陋的呢”。这类特殊句式在初中教材里反复出现,所以我在引擎里建了一个句式库,专门存那些高频句式模式,配上重组规则。文言文翻译不能按字直译,要先把语序调整成白话文语序,再替换字词,最后润色成通顺的现代汉语。三步走完,翻译质量基本能到八成以上。
5.4 翻译准确度实测:哪些场景表现好,哪些场景必须提示用户
我用自己的测试集跑了一轮,测试集是从初中语文教材里选的二十个典型句子,包括《论语十二章》《岳阳楼记》《出师表》里的名句。
表现最好的是那些结构清晰、句式典型、词库覆盖完整的句子。比如“学而不思则罔”,分词结果为“学/而/不/思/则/罔”,每个词都在词库有对应条目,“而”作连词表转折,“罔”译为“迷惑而无所得”,整套逻辑走下来,翻译结果很准。
表现不稳定的是那些省略主语、成分残缺的句子。比如“温故而知新”,原文省略了“人”,本地引擎直接翻成“温习旧知识并且知道新知识”,虽然意思接近但总感觉缺乏主语。这种场景我会在翻译结果上方加一条提示,告诉用户“该句存在省略成分,仅供参考”,避免误导。
6. 真机调试、性能优化与发版前的避坑清单
代码写完只是完成了开发的一半,真机跑起来、性能过得去、顺利装上鸿蒙系统,这个过程藏着不少只有动手才会发现的问题。这一章专门讲从模拟器到真机的跨越。
6.1 把App跑上鸿蒙真机:连接、签名和安装
开发阶段用DevEco Studio自带的模拟器问题不大,但翻译类App涉及中文输入和页面交互,模拟器上的体验和真机有差异,所以我建议直接上真机调试。
鸿蒙手机连电脑要先打开开发者模式:在设置里连点版本号七次,然后在开发者选项里打开USB调试。用USB线连电脑,手机上弹出授权对话框时点允许。DevEco Studio会自动识别设备,如果识别不到,检查一下数据线是不是只支持充电不支持数据传输。
这里有一个比较容易忽略的点:鸿蒙应用安装是需要签名的。DevEco Studio默认会使用自动签名,但你需要在项目的签名配置页面里填写自己的调试证书信息,自动签名才能生效。没配签名的话,编译会报错,或者装上真机后应用闪退。我第一次跑真机时就栽在这上面,查了半天日志才发现是签名的问题。
装到真机上以后,先用几个典型的测试用例过一遍:输入一句短文言文,看翻译速度;输入一大段长文,看是否有卡顿;切换页面、添加收藏、查看历史,看状态刷新是否正常。我强烈建议把这个测试清单固定下来,每次改动代码后都跑一遍,避免改一个bug引入另一个bug的连锁反应。
6.2 Flutter Impeller渲染引擎在鸿蒙上的适配情况
再聊一个进阶话题:渲染引擎。Flutter从3.10版本开始默认启用Impeller作为iOS端的渲染引擎,它比旧的Skia方案性能更好,帧率更稳定,人称卡顿和掉帧的情况更少。
但这个项目用的是OpenHarmony适配的Flutter分支,Impeller并没有默认开启——鸿蒙端目前更多还是用Skia做软件渲染。在我实测的过程中,界面整体流畅度是可以接受的,页面切换和列表滚动都没有明显掉帧,只有在翻译很长段落时可能会出现不到一秒的卡顿,因为分词和词典查询是CPU密集操作。
如果你们后续要处理更复杂的动画,或者列表数据量特别大,可以在鸿蒙工程里尝试启用Impeller验证效果,但不要抱太大期望,因为驱动适配还没完全成熟。我的处理方式是把重计算放到异步队列里执行,不阻塞UI线程。用Dart的Future配合compute函数做并行计算,UI保持流畅,翻译结果延迟也基本控制在200毫秒以内。
6.3 发版前的自检清单
最后给大家一份我自己整理的发版前检查清单,每一条都是实践逼出来的:
- 检查离线模式下所有核心功能是否仍然可用。搜索、分词、本地词库翻译必须能在无网络环境正常工作。
- 检查在线兜底接口异常时的降级逻辑。接口超时不能白屏,要提示用户“网络不可用,已显示本地翻译结果”。
- 检查收藏数据是否持久化。用户收藏的句子和词条,重启App后必须还在。这里需要用到shared_preferences或者sqflite做本地存储。
- 检查中文字体的显示效果。鸿蒙系统自带字体对中文支持很好,但要留意生僻字是否能正常渲染,部分不常见字如果字体缺失,会出现方框。
- 检查App图标和应用名称。鸿蒙桌面会显示应用的label,设置成“文言文翻译助手”会更友好。
- 检查HAP包体积。Flutter引擎本身是要占体积的,实测打包出来大概在20MB上下,和一些纯原生小工具比确实偏大。如果对体积敏感,可以试试渠道拆分。
6.4 后续可以扩展的方向
框架已经跑通,后续的功能迭代就有了稳定的底座。我个人比较看好的扩展方向有三个。
第一个是加入拍照翻译。学生经常要用手机拍课本上的文言文段落,如果把OCR识别接进来,用户拍照后自动提取文字再走翻译流程,使用体验会有一个质的提升。
第二个是增加“教材同步学习”模块。按照单元章节拆分词库,结合课文上下文语境来给词条配讲解,相当于把一个翻译工具升级成学习工具。这个方向如果有真实教师参与内容共建,价值会成倍放大。
第三个是接入TTS朗读功能。文言文朗读的音调对理解也有帮助,尤其是那些通假字和破音字,听一遍比看一遍印象深得多。鸿蒙系统自带TTS接口,调用成本也不高。
最后分享一个我个人的实际体会。做跨端应用这几年,我最大的感受是:跨平台框架的坑大部分不在框架本身,而在于你对目标平台特性的理解程度。这次在鸿蒙上适配Flutter,环境搭建阶段虽然折腾了一些时间,但架构设计一旦跑通,后面新增功能的效率确实很高。如果你也想做类似的工具类App,别被环境搭建吓退,照着上面流程走一遍,大概率半天之内就能看到自己的页面在鸿蒙真机上跑起来。
