HarmonyOS NEXT 有一个对存量应用致命的特性:不再兼容安卓——APK 装不上了,所有车间 App 都面临”重写或退出”的选择题。上一篇的 X5 壳是我们的安卓答案,这一篇是从零开始的鸿蒙答案:一个新的 ArkTS 工程,把同一个车间 App 在 NEXT 上重新长出来。
这篇的视角和前几篇不同:它是一次从 0 到 1 的完整记录——不是我接手的老系统,而是我从空目录开始建的项目。从 0 到 1 的文章最怕写成教程复读(”新建工程、写个 Hello World”),我尽量写教程不会告诉你的部分:一个 Android 老兵的世界观转换清单、五个真实的坑和各自的解法、以及从 0 开始时那些”试了又推翻”的方案痕迹——它们比最终代码更能反映工程判断。
一、世界观转换:Android 老兵的四条震撼
用 Android 的肌肉记忆写 ArkTS,前三天全在踩观念的坑。整理成四条,每条都是真实撞上的:
第一条:语言不是 Java 也不是 TS,是”被约束的 TS”。 ArkTS 在 TypeScript 基础上砍掉了一批动态特性(禁 any、禁运行时改对象结构、禁 unboxed 联合类型的部分用法)——换来的是 AOT 优化和运行时确定性。Java 老兵的直觉”先声明后赋值、随手加字段”在这里会编译失败,静态化的代价要提前用接口定义偿还。我的适应期结论:把 ArkTS 当成”带类型系统的 Java 写法、TS 语法”来写,痛苦减半。
第二条:UI 是声明式的,XML 布局的肌肉记忆全部作废。 ArkUI 的组件树写在 build 函数里,状态驱动画面的心智模型是 React/Vue 系的——Android 写惯了 findViewById 和手动 notify 的手会先卡住,卡点不在语法在”不再手动控制刷新”。状态装饰器(@State、@Link、@StorageProp)各管一片作用域,跨页面共享用 AppStorage——权限模型比 Android 的全局单例严格。
第三条:模型变了。 Activity/Fragment 的世界换成了 Stage 模型的 UIAbility——生命周期语义对得上但粒度不同,配置从 AndroidManifest 换成 module.json5。这部分是”翻译”不是”重学”,老 Android 的组件化经验大多能平移。
第四条:NEXT 无法侧载。 最现实的一条——不像安卓可以随手装 APK,NEXT 的设备只认签名包:开发要签名调试证书、发布要正式证书加描述文件、内部分发要走企业通道或应用市场。**”发个安装包给车间试试”这个动作本身不存在了**,发布流程从第一天起就是工程的一部分。
二、架构决策:一个桥名,换 Web 零改动
工程定位沿用了移动篇安卓壳的哲学:ArkWeb 组件加载 MES 的 H5 页面,业务全在 Web,原生只补扫码等硬能力。但移植项目有一个黄金决策点——桥的接口名。
安卓壳向 H5 注入的桥对象叫 AndroidWebView,H5 页面上所有 AndroidWebView.xxx() 的调用点遍布业务代码。鸿蒙版如果换个名字(比如 HarmonyWebView),H5 就要全量改造或者写适配层。最终的决策是:鸿蒙的 javaScriptProxy 注册时沿用 AndroidWebView 这个名字——名字里的”Android”在鸿蒙上听起来别扭,但 Web 端一行不改、两端行为立即对齐。名字的语义成本和改造的工程成本放一起算,我选了让渡语义。
这个决策还带来一个意外的健壮性:H5 侧的桥调用是”对象名加方法名”,两端壳只要实现同名同参方法,H5 无法感知自己跑在哪个系统上——未来加第三个端(比如 PC 壳),契约继续成立。桥的方法集做了裁剪:安卓版十五个方法,鸿蒙版先实现扫码、拨号、清缓存、版本号四个高频项,其余按 H5 的实际调用频率渐进补齐(README 里的 TODO 清单就是这张优先级表)。
扫码用了系统级 ScanKit(华为的识别引擎,等价于安卓壳里的 HMS 通道),识别结果通过 runJavaScript 回传 H5 的同一个约定函数——回传协议两端一致。
三、五个坑与解法:教程不会写的部分
坑一:PDF。 ArkWeb 加载 PDF 链接直接报错(安卓 WebView 新版内嵌了 PDF 渲染,NEXT 的 ArkWeb 没有)——车间看单据是刚需。解法是拦截:监听 Web 组件的页面开始加载事件,识别 PDF 类型的 URL 就阻断加载、跳转到原生实现的 PDF 阅读页。这是壳工程的标准打法——“Web 做不了的 URL 模式,原生拦截接手”。
坑二:安全区。 NEXT 的默认视口不处理沉浸式状态栏,H5 页面内容顶到状态栏下面。解法是两层配合:壳在页面加载完成时注入 JS 改写 viewport 的 viewport-fit=cover(让 H5 自己感知安全区),同时原生侧写了状态栏避让占位组件(高度通过 AppStorage 全局共享)。视口注入加原生占位双保险,比单边处理稳。
坑三:返回键。 WebView 的历史栈和页面路由栈是两个栈,返回键只退页面路由会直接退出整个 App。解法是 onBackPress 拦截:WebView 能后退就先让网页后退;再补了一个业务特例——工作台页是 H5 的 hash 路由(/#/Workbench),返回时要映射到首页路由而不是靠历史栈。混合栈的返回语义,是所有 WebView 壳的共同坟墓,安卓版当年踩过的坑在鸿蒙换了个姿势又踩一遍。
坑四:路由选型的摇摆。 工程里留着整段被注释的 Navigation 方案——先试了 NEXT 主推的 Navigation 路由(组件级导航栈),发现对”壳工程”这种页面极少、以 Web 为主的形态太重,退回传统的 Router 模式。被注释掉的方案是最诚实的文档:它记录的不是失败,是”为什么最终形态长这样”。
坑五:开发工具链。 DevEco 的构建链在打包时吃过 JVM 内存(项目里留着打包工具的崩溃现场日志),调堆参数后才稳。另有一个流程性的不适应:签名文件(证书、描述文件)的管理比安卓严格得多,证书和机器的对应关系搞错一次就锁半天。
四、多环境与从 0 到 1 的过程管理
壳要多环境切换(不同客户部署在不同服务器),安卓版的方案是本地配置,鸿蒙版升级为云端服务器列表:启动时从固定地址拉取环境清单(名称、地址、描述),渲染成选择页(左滑出现操作栏),选择结果持久化在本地偏好存储。把”环境”从配置文件升级为云端数据,是给”新客户接入不用发版”留的路——和后端交付线的配置外置思想同源。
从 0 到 1 的过程管理有两条心得值得记录。其一,TODO 清单进 README:功能完成度、待补的桥方法、已知问题全列在项目根 README 里——一个人从 0 建项目最容易死在”自己不知道做到哪了”,README 即看板。其二,废弃方案注释保留:Navigation 方案、侧边栏方案的整段代码留在原地加注释,而不是删掉——三个月后的自己需要知道”这条路为什么没走”。
还有一个纯生态层面的记录:**HarmonyOS NEXT 的资料环境是”官方文档丰富、社区答案稀疏”**——坑基本都能靠官方文档+源码试出来,但搜索不到前人的踩坑帖,每个问题的解决时间都比安卓同类问题长。这也是把它写成文章的动机之一:给后来的移植者留几块垫脚石。
五、面试视角:六个问题拆到底
Q1:为什么值得为鸿蒙重写一个壳?
答:外因是 NEXT 不兼容安卓,存量 App 面临退出;内因是壳的重写成本被架构压到了最低——业务在 Web,原生只剩扫码等少数桥方法,重写是”桥方法级”而不是”应用级”。判断依据是壳的薄:如果当年做的是全原生 App,鸿蒙化的成本会高一个数量级,决策可能完全不同。
Q2:ArkTS 写起来和 Java/TS 比怎么样?
答:它是”被约束的 TS”:砍掉动态特性换 AOT 性能,Java 老兵要过的坎是”不再随手改对象结构”,TS 老手要过的坎是”类型不是建议是纪律”。声明式 UI 对 Android 经验者是重构肌肉记忆——状态驱动画面的心智要先建立,装饰器的作用域规则(@State/@Link/@StorageProp)要当权限模型学。总体判断:会 Java 和 TS 的人,ArkTS 的语法层一周上手,生态层(坑和最佳实践)才是长尾。
Q3:桥是怎么设计的?和安卓壳什么关系?
答:沿用安卓壳的桥对象名和方法签名,javaScriptProxy 注册同名对象——H5 零改动、双端行为对齐,未来第三端继续复用这个契约。方法集按 H5 实际调用频率渐进补齐(README 的 TODO 就是优先级表),扫码走系统 ScanKit、结果用 runJavaScript 回传同名约定函数。这次决策教会我:移植项目的第一杠杆是接口契约的沿用,不是代码的翻译。
Q4:ArkWeb 有哪些坑?
答:三个典型:PDF 不内嵌渲染(安卓新版 WebView 有),要按 URL 模式拦截跳原生阅读页;沉浸式安全区不自动处理,要注入 viewport 改写加原生占位双保险;WebView 历史栈和页面路由栈是两棵树,返回键要拦截合并,还有 hash 路由页面的特殊返回映射。共同规律:壳工程的坑 80% 发生在”两个世界的边界”上——Web 与原生的交接处。
Q5:从 0 开始怎么管理过程?
答:两条土办法:TODO 清单进 README 当看板(功能完成度、桥方法优先级、已知问题一人也要有看板);废弃方案保留注释(Navigation 方案试过退回 Router,为什么不走要写在原地)。外加一条:NEXT 无法侧载,签名和发布流程从第一天就是工程的一部分,证书管理当成环境配置而不是临时动作。
Q6:怎么看鸿蒙 NEXT 的开发生态?
答:官方文档和工具链完整度已经够支撑生产开发(扫码、网络、存储、Web 组件都有系统级 API),但社区答案是稀疏的——同样的问题安卓有一百篇踩坑帖,NEXT 要自己试。对团队的含义:第一个项目要预留双倍的问题排查时间,并且把踩坑沉淀成文档(这篇就是)。对生态的判断:跟随设备保有量走,壳形态是当下成本最低的跟进方式。
小结
- NEXT 不兼容安卓是存量 App 的选择题:壳的薄决定了重写是”桥方法级”成本——架构的远见在迁移日兑现;
- 移植项目的第一杠杆是沿用契约:桥对象名不动、方法签名不动,H5 零改动双端对齐;
- ArkTS 是被约束的 TS:语法层一周上手,真坑在”两个世界的边界”——PDF 拦截、安全区、混合返回栈;
- 被注释的方案是最诚实的文档:Navigation 到 Router 的摇摆要留在原地,三个月后的自己需要知道为什么;
- 发布流程从第一天起是工程的一部分:NEXT 无法侧载,签名证书就是环境配置;
- 生态现状是官方文档丰富、社区答案稀疏:第一个项目预留双倍排查时间,踩坑即文档。
下一篇预告:PowerShell 开发引擎——一份 1846 行的脚本管四个项目二十个微服务:零配置自动发现、Windows 进程工程的坑(CreateProcess 206、5GB 日志 105 秒读取)、命名互斥体防双起,以及那个和已发布 Java Agent 文互为姊妹的模型热重载引擎。