zjchina.net

Drogon · ROS 2 · 独立开发笔记

ENGINEERING NOTES/工程笔记

从内容站到协作认知架构:鸿蒙适配实战

2026-09-24 深夜,我们把 zjchina 的定位从「内容站架构方法论」升级为「协作认知架构方法论」。 24 小时后,鸿蒙版工程骨架落地——这是定位升维后的第一场实战。 而在本文上线前夜,一次「APP 没有刷新键」的小修复,意外做成了未来多机协同「事件去重」的第一个原型。 本文记录这场实战的技术细节、踩坑过程与决策逻辑,作为 ADR 0004 的注脚。


一、为什么鸿蒙是「协作认知架构」的第一块试金石

ADR 0004 把 zjchina 的定位从「内容站」升维到「协作认知架构」——简单说,就是从「做好一个网站」变成「做好一套能连接物理世界的系统」。

鸿蒙适配恰好踩中三个维度:

维度鸿蒙场景我们的机制
空间可达工厂大屏、导购机器人触屏、无人店收银台ArkWeb 薄壳 + 服务端渲染(零 JS 首屏)
时间可验证交易记录可回溯、决策过程可审计事件日志(类似飞行记录仪)+ 内容指纹链
边界生长传感器(RFID/重量)、防截屏、全屏展示平台能力隔离(鸿蒙特有代码单独存放)

鸿蒙不是「又一个平台」,而是协作认知架构向物理世界延伸的第一个触点。


二、技术方案:ArkWeb 薄壳,不改现有架构

2.1 三轨道不变,鸿蒙只是多一个「容器」

我们的网站有三条渲染轨道(类似三条生产线):

┌─────────────────────────────────────────────────────────────┐
│  内容轨道(首页、文章页、决策日志)                            │
│  服务端直接生成 HTML,无需下载 JS,打开即读                     │
│  → 鸿蒙浏览器直接打开,零改动                                  │
├─────────────────────────────────────────────────────────────┤
│  应用轨道(后台管理)                                          │
│  浏览器下载 wasm(编译后的代码),交互复杂                       │
│  → 鸿蒙浏览器可运行,但非最优                                  │
├─────────────────────────────────────────────────────────────┤
│  壳轨道(桌面/手机 App)                                       │
│  原生窗口包裹网页内容                                          │
│  → 鸿蒙 H1 = ArkWeb 薄壳(第一个原生容器)                     │
│  → 鸿蒙 H3 = 原生交易页(未来)                                │
└─────────────────────────────────────────────────────────────┘

关键决策:鸿蒙不改变三条轨道,而是给「壳轨道」增加一种交付形态。内容页面(服务端渲染)在鸿蒙浏览器里零改动运行——这是「中立契约层」的第二次兑现(第一次是服务端渲染/客户端渲染双端同源)。

2.2 窗口级能力:防截屏与全屏

防截屏(鸿蒙 API 26 的 setWindowPrivacyMode):

  • 截屏/录屏时窗口自动变黑,无需修改网页代码(系统在窗口层拦截)
  • 坑位:API 26 需要特殊权限(ohos.permission.PRIVACY_WINDOW,系统级授权)
    • 设计文档假设「无需权限」已过时
    • 工厂场景(企业证书)可用;公开版若拿不到授权则通过配置关闭
  • 降级策略:如果权限不足,catch 错误继续加载(不阻断使用,但日志留痕)

全屏沉浸(setWindowLayoutFullScreen):

  • 内容延伸至状态栏/导航栏,工厂大屏场景必需
  • 待实测:安全区边距(env(safe-area-inset-*))在鸿蒙浏览器是否正确传递

2.3 工程骨架:Stage 模型,零依赖

harmony/
├── AppScope/app.json5              # 应用标识:net.zjchina.shell
├── build-profile.json5             # API 26.0.0, 签名配置
├── entry/src/main/
│   ├── module.json5                # 防截屏权限声明
│   ├── ets/entryability/EntryAbility.ets  # 防截屏+全屏逻辑
│   ├── ets/pages/Index.ets         # ArkWeb 壳(加载网页)
│   ├── ets/model/AppConfig.ets     # 配置中心(开关集中管理)
│   └── resources/                  # 字符串/颜色/页面配置
└── scripts/harmony-build.sh        # 一键构建(环境变量注入)

关键设计:

  • AppConfig.ets:所有窗口能力开关集中管理(防截屏/全屏/网址),避免魔法数字散落各处
  • harmony-build.sh:构建时注入环境变量(SDK 路径等),不污染全局 shell 配置
  • 零依赖:oh-package.json5 无第三方依赖,纯鸿蒙原生代码 + 系统浏览器

三、踩坑记录:API 26 vs 设计文档

坑位设计文档假设实际情况(API 26)解决方案
防截屏权限无需权限需系统级权限(PRIVACY_WINDOW)声明权限,catch 错误降级
错误回调签名isMainFrame 直接参数isMainFrame 在 event.request 对象上按官方类型定义修正
版本号格式"26"(数字)"26.0.0"(字符串)按构建工具错误提示修正
API 26 运行环境下载本地镜像即可调试当时 DevEco Studio 的本地模拟器列表中没有 API 26 镜像(镜像清单随 IDE 版本更新,以实际列表为准);在线模拟器虽有 API 26,但命令行 hdc install 装本地签名包被拒DevEco Run 直连 Pura X 在线模拟器,云端签名部署

这个坑的关键不在「下载」,而在「安装通道」:在线模拟器运行在云端,本地命令行工具因签名体系不一致无法把应用装进去;而 DevEco Run 走云端通道,自动完成构建、签名、部署一条龙,直接把应用送上 Pura X 在线模拟器(API 26)。所以验收全部跑在 API 26 在线模拟器上——防截屏是全功能生效而非降级;唯一未闭环项是云端环境拿不到 hilog(即上方清单第 8 项)。


四、跨语言边界:让「契约」当裁判

鸿蒙适配是「跨语言交互问题」的第三次出现(前两次:C++ 后端 ↔ Rust、Rust ↔ 浏览器 wasm)。

纪律不变:

  1. 边界只传契约,不传调用:鸿蒙代码(ArkTS)与 Rust 核心之间只传数据类型(JSON 格式),与浏览器→后端、服务端渲染→后端是同一批类型
  2. 漂移锁从三向扩四向:现在数据格式校验是「Rust 计算 + 文档定义 + C++」三向锁定;鸿蒙加入后,ArkTS 侧类型从统一的数据规范自动生成——校验机制不变,只是多一个使用方
  3. 平台能力仍走通道隔离:碰鸿蒙系统功能(传感器/窗口/防截屏)的代码永远住在鸿蒙特有目录,核心逻辑保持纯净可编译到鸿蒙,不出现平台判断代码污染

H2 验证(后续):只暴露核心逻辑的一个纯函数(如 Markdown 渲染),鸿蒙代码调用,同一测试用例双端断言——不做 UI。


五、对网页编排的影响:零影响

内容页面(首页、文章页、决策日志)服务端渲染,鸿蒙浏览器直接打开,无需任何改动。

唯一需要实测的假设,验收也给出了结论:

  • 鸿蒙浏览器是否支持 Service Worker?(设计文档「默认支持」此前只是假设)
    • 若支持:离线缓存加速 + 断网兜底(显示友好离线页)
    • 若不支持:服务端渲染仍可用(只是没缓存加速),后台管理页不开放(wasm 依赖缓存)

验收清单与结果:

  1. 部署方式:命令行 hdc install → DevEco Run 部署(在线模拟器绕过本地安装限制)✅
  2. 防截屏(截屏时窗口黑屏)✅ API 26 全功能生效
  3. 全屏(内容延伸至安全区)✅
  4. 离线缓存(在线首访/二访/断网)✅(网络连接活跃)
  5. 内页跳转(文章详情页)✅(鸿蒙浏览器加载网站)
  6. 动画性能(wasm 粒子效果)✅(渲染进程独立,内存占用合理)
  7. 服务端渲染首屏(零 JS 可读)✅(鸿蒙浏览器直接消费 HTML)
  8. 稳定性(无错误日志)⚠️(在线模拟器日志权限限制)

合计 7/8 通过(Pura X 在线模拟器,API 26):防截屏全功能生效;唯一未闭环项是云端环境拿不到 hilog 日志,留待真机或本地模拟器补验。


六、上线前夜:APP 没有刷新键,事件驱动替代轮询

准备发布本文时发现一个真实问题:Service Worker 为了让二次访问秒开,会先展示本地缓存、再在后台静默更新。浏览器里用户还能手动刷新,可页面装进鸿蒙壳之后——APP 没有刷新键,新文章可能一直不出现。

6.1 第一反应是轮询,但它被否决了

直觉方案很简单:页面每隔几十秒请求一次「版本号」,发现变化就弹提示。否决理由同样简单:博客的发布间隔可能长达数周,定时请求里 99.99% 都是「没有变化」——为了一次发布,让每个访客的设备持续空转耗电,这笔账不划算。APP 在后台时连接还会被系统冻结,轮询并不可靠。

6.2 「发布」本来就是可以监听的事件

重新审视机制后发现,浏览器早就准备好了答案:

  • 每次发版,构建脚本都会重新生成 Service Worker 脚本 sw.js——版本号、资源清单、完整性指纹全部写进它的字节,且这个文件本身被设置为永不缓存;
  • 浏览器在每次打开页面时自动比对它:字节变了,就安装新 SW,页面随之收到一个 updatefound(发现更新)事件;
  • 于是判定收敛成一个极简状态机:首次安装静默接管(新访客看到的本就是最新内容,不该被打扰);页面已被旧版本控制时再收到更新事件,才弹出横幅,并且同一次更新只弹一次。

对于没有导航的场景——APP 切到后台再切回来、网络重新连通、从系统页面缓存恢复——则在对应的用户行为事件里主动检查一次。全程没有任何定时器:发布间隔再长,通知成本都是零。

用户点「立即刷新」时,新 SW 已经完成接管并清空旧缓存,这一下刷新必然拿到新内容,不会在新旧版本之间反复横跳。

6.3 这是未来多机协同「事件去重」的第一个原型

这个功能看似只是个更新提示,架构上却特意做了一件事:通知入口与触发源解耦。横幅和更新动作并不关心「是谁发现了新版本」——Service Worker 的更新事件只是第一个信号源;将来股票行情、无人店多机协作的实时事件,经过 SSE/Push 这样的长连接通道,可以直接触发同一个通知入口,UI 与更新逻辑一行都不用改。

核心判定只有两个状态——「是否已被旧版本接管」「本次会话是否已提示」——保证同一事件只打扰一次。这与多机协同里「同一事件只处理一次」的幂等去重是同一个问题:去重必须做在事件入口,而不是等消息堆到界面上再去过滤。状态机用 10 组测试向量锁死,包括「首次访问不提示」「同一更新不重复提示」「事件乱序到达也不误报」。

也诚实标注边界:这个机制保证「下次打开页面或 APP 回到前台时」立即通知,而不是挂机不动时秒级弹窗。真正的秒级推送(长连接/系统推送)是下一阶段的能力——接缝已经留好。

这篇文章的上线,就是它的第一次线上实测:如果你正从旧版本打开本站,页面顶部此刻应该已经出现「发现新版本,内容已更新」。


七、下一步:从「能跑」到「好用」

H2(后续):鸿蒙代码调用 Rust 核心逻辑(如 Markdown 渲染),验证数据格式四向锁定。

H3(未来):鸿蒙原生交易页(结算/支付/订单确认),核心逻辑在 Rust,UI 双份(鸿蒙原生 + 网页版)。

实时通道(接缝已留):新版本横幅的通知入口与触发源解耦,下阶段接 SSE/Push 时直接复用——行情跳动、多机协作事件与「内容更新」走同一个入口、同一套幂等去重。

5.1 无人店:鸿蒙 H1 是「导购机器人触屏」的技术预演——鸿蒙浏览器承载商品讲解(内容轨道),鸿蒙原生页承载交易(壳轨道),传感器数据经通道入事件日志。


八、结语:协作认知架构的第一块砖

鸿蒙 H1 不是「又一个平台适配」,而是协作认知架构向物理世界延伸的第一块砖。

它验证了:

  • 三轨道不变:内容/应用/壳的路由表、渲染模式、降级链
  • 中立契约层:内容页面零改动跑在鸿蒙浏览器
  • 通道隔离:平台能力(防截屏/全屏/传感器)住在鸿蒙特有目录,核心逻辑保持纯净
  • 可观测降级:低版本或权限不足的设备上,防截屏按设计走 catch 降级(不阻断加载);API 26 在线模拟器全功能生效(低版本降级路径尚未在真机实测)

上线前夜补的事件驱动更新提醒,则验证了另一件更面向未来的事:事件可以从任何通道来,但入口只有一个、同一事件只处理一次——这条纪律先在最不起眼的「更新提示」上跑通,等它的是行情事件流和多机协作。

下一块砖:股票模拟盘的「乐观执行 + 资金事件流」,然后是无人店的「多机协作」。


参考文献:

  • ADR 0004:协作认知架构定位升维(docs/decisions/0004-collaborative-cognition-architecture.md)
  • 鸿蒙策略预研(docs/superpowers/specs/2026-09-25-harmony-support-strategy.md)
  • H1 落地状态(docs/superpowers/specs/2026-09-25-harmony-h1-status.md)
  • 页面编排要求(docs/superpowers/specs/2026-09-25-harmony-page-layout-requirements.md)
← 返回首页全部文章