指南
方案对比
手机客户端想要显示安装包里没有的界面——由模型生成的回答、来自合作方或其他团队的功能、无需发版就能变化的页面——已有几种成熟的做法。它们的区别在于:界面由什么绘制,下发的代码能做什么,以及宿主应用要为承载它们做多大的改动。本页把它们与 nsh 放在一起比较。
#几种做法
| 由什么绘制 | 能表达什么 | 约束方式 | 适合生成式界面吗 | 宿主应用的代价 | |
|---|---|---|---|---|---|
| WebView(H5) | 浏览器引擎 | HTML、CSS、JS 能做的一切 | 同源策略;原生能力通过手写的桥接暴露 | 模型擅长写 HTML;但结果看起来、用起来都是网页 | 每个视图一个浏览器引擎;还要维护桥接 |
| 服务端驱动 UI | 应用自己的原生视图 | 只能组合应用内置的组件和动作,用 JSON 描述 | 完全受限:协议就是边界 | 容易生成,但能表达的很少:协议之外没有本地状态和逻辑 | 每个应用都要为每个组件及其版本实现渲染器 |
| 小程序容器 | 通常是 Web 引擎加一层私有封装 | 平台特有的框架和 API | 容器自己的权限模型 | 私有方言,模型不熟悉 | 体积很大的容器 SDK |
| 跨平台应用的热更新(例如 React Native 搭配代码推送服务) | 该框架的渲染器 | 整个框架的能力 | 没有约束:更新就是受信任的应用代码 | 这类更新并不是为按请求生成的代码设计的 | 整个应用都得用该框架编写 |
| nsh | UIKit 和 Android 视图 | 带状态、逻辑、动画和布局的组件;宿主注册的原生视图 | 签名包;每个视图一个虚拟机,限制由宿主设定;能力按视图授予 | 为此而设计:一个 TSX 模块、类型化的 API、无界面验证 | 在现有原生应用里放一个视图、加一个库 |
#nsh 的不同之处
- 是原生界面,不是网页。 模块由平台的视图组成,文本选区及其菜单、输入法、无障碍和滚动都是系统自己的——这也是 nsh 在 GPUI Shell 之外存在的原因。
- 不止一套协议。 服务端驱动 UI 只能重新组合应用已有的东西;nsh 模块有自己的状态、逻辑、动画和布局,模型可以生成应用开发者事先没有预料到的界面。
- 由宿主约束。 下发的代码是不可信的。nsh 在运行任何代码之前检查签名和吊销列表,为每个视图分配独立的虚拟机并设定内存、调用时长和节点数限制,由宿主决定模块能访问哪些网络主机、网页和系统设置(沙箱与能力)。
- 嵌入,而不是迁移。 应用仍然是原生应用,沿用原来的工具链;nsh 只是放在需要显示模块的地方的一个视图(iOS、Android)。
#什么时候其他做法更合适
- 界面本身就是文档或现成的网页:WebView 可以原样显示。
- 页面集合固定且很少,变化的只是内容和顺序:服务端驱动 UI 完全不需要运行时。
- 整个应用本来就是用某个跨平台框架编写的:用它自己的更新机制下发代码即可。