鸿蒙 PC 移植 JupyterLab 全链路实战——Electron 壳、浏览器内 Python 内核与 HAP 真机避坑

鸿蒙 PC 移植 JupyterLab 全链路实战——Electron 壳、浏览器内 Python 内核与 HAP 真机避坑
适用基线:JupyterLab 4.x|OpenHarmony PC arm64|compatibleSdkVersion / targetSdkVersion 6.0.1(21)|2026-09
| HarmonyOS OpenHarmony 鸿蒙PC JupyterLab Electron Python Pyodide WebAssembly HAP DevEco Studio |
| 把 JupyterLab 以独立桌面应用的形式搬到鸿蒙 PC,真正困难的不是“把页面打开”,而是重新划分 Electron、Jupyter Server 与 Python 内核的运行边界。本文从可复现的工程路径出发,完整拆解 Electron 壳、前端静态化、Pyodide 浏览器内核、HAP 资源打包、SDK 锁定、签名、HNP 共存与真机验收;同时给出 node-static、设备 CPython、外部 Jupyter Server 三种模式的取舍、常见错误码的根因与修复顺序,以及浏览器 Python 在科学计算包、文件系统、网络和终端能力上的真实边界。目标不是做一个“能亮屏的 Demo”,而是跑通可安装、可启动、可编辑、可执行、可保存、可重开的完整 Notebook 闭环。 |
目录
- 0. 30 秒先看结果:这次到底搬成了什么
- 1. 先把概念边界说清:JupyterLab 本体不是 Electron
- 2. 为什么不能原样搬:三个桌面假设同时失效
- 3. 路线选择:默认 node-static + Pyodide,另外两条路什么时候用
- 4. 工程架构:把“服务端依赖”拆成可替换边界
- 5. 环境与目录:先把版本、架构和资源树钉死
- 6. 第一步:从共用 runtime 派生 Lab 身份
- 7. 第二步:把 Python 执行挪进浏览器
- 8. 第三步:资源同步到 web_engine,并构建 HAP
- 9. 第四步:签名、安装与启动
- 10. 六类高频坑:从 10705000 到 ImportError 的完整排查链
- 11. 真机验收:别只验证“能打开”
- 12. Pyodide 的能力边界:能跑 Python,不等于等同桌面 CPython
- 13. 什么时候切到设备 CPython 或 external Server
- 14. 一条可复现的最短路径
- 15. 常见问题 FAQ
- 16. 收束:这类跨平台迁移真正要迁的是“边界”
0. 30 秒先看结果:这次到底搬成了什么
如果只看最终界面,你会觉得这件事像是“给 JupyterLab 套了一个鸿蒙窗口”。实际上,真正完成的是一条从 Web IDE 到 HAP 桌面应用的运行时重构链:JupyterLab 的前端工作区被保留下来,Electron 负责 PC 端窗口和加载,本地静态服务负责交付前端资源,Python 单元格默认不再依赖设备上的 Jupyter Server,而是进入浏览器内核;需要完整科学计算环境时,再切换到设备 CPython 或远程 Server。
表 1 不要用“能打开”代替“能用”:建议至少完成以下验收
| 验收点 | 结果 | 为什么它重要 |
| HAP 可构建、可签名、可安装、可启动 | 必须通过 | 这是 T0,连这一层都不稳,后面的功能没有意义 |
| Launcher / 多文档工作区正常 | 必须通过 | 证明加载的不是单一 Notebook 页面,而是完整 Lab 工作区 |
| 新建 / 打开 Notebook | 必须通过 | 文件与文档模型进入可用状态 |
| Python 单元格执行并回显 | 必须通过 | 证明 kernel adapter → 浏览器 Python 的执行链真的闭环 |
| 保存、关闭、重新打开 | 必须通过 | “看起来能用”升级为“数据能留下来” |
| 文件浏览、Markdown、语法高亮 | 建议通过 | 验证核心前端能力没有被静态化过程破坏 |
| 与 Notebook 姊妹应用共存 | 建议通过 | 验证 bundle、HNP 与签名身份已经彻底分离 |
| 关键判断 这条路线追求的不是一上来就复制 Linux 桌面的全部能力,而是先让“打开 → 编辑 → 执行 → 保存 → 重开”成为稳定闭环,再按需求补完整 CPython、终端和插件生态。 |
1. 先把概念边界说清:JupyterLab 本体不是 Electron
这类移植最容易在第一句话里就把边界说错。JupyterLab 官方把自己定义为面向 Notebook、代码和数据的 Web 交互式开发环境[1];它的 UI 本体运行在浏览器里,传统桌面使用方式通常是本机启动 Jupyter Server,再由浏览器连接。本文中的 Electron 并不是 JupyterLab 的“原生组成部分”,而是为了把 Web 应用包装成鸿蒙 PC 上可独立安装、可从桌面启动的 HAP 应用而引入的承载壳。
这一点非常重要,因为它直接决定迁移目标:你不是要把整个 JupyterLab 改写成 ArkUI,也不是把一套 Linux Python 环境粗暴塞进 HAP;更合理的做法,是尽量保留上游前端,把平台差异压缩在“窗口运行时、静态资源交付、内核执行、文件持久化、签名安装”这几层。
| 一句话架构 JupyterLab 负责“工作区与交互”,Electron 负责“桌面承载”,Pyodide / CPython / external Server 负责“代码执行”。把这三个角色分开,后面的取舍才不会乱。 |

图 1 迁移后的整体架构:保留 JupyterLab 前端,把 Electron、静态资源与 Python 内核解耦。
2. 为什么不能原样搬:三个桌面假设同时失效
2.1 假设一:系统里天然有桌面 Electron 运行时
普通 Windows / macOS / Linux 桌面应用可以把 Electron runtime 随应用一起发货,并依赖成熟的 Chromium、Node.js 与桌面窗口能力。到了鸿蒙 PC,你不能假定系统预装了与你版本匹配的桌面 Electron 运行时;工程需要借助 OpenHarmony PC 侧的 Electron 适配层与 web_engine,并按 HAP 的资源与模块规则重新组织。项目主线使用的就是 `libelectron.so` 承载路径[2]。
2.2 假设二:本地随时可以 `python -m jupyterlab`
标准 JupyterLab 桌面体验背后其实有一整套 Server 语义:contents、sessions、kernels、WebSocket、终端、扩展与认证。如果选择“完整本地模式”,就要把 CPython、Jupyter Server 以及依赖一起带到 OHOS arm64。真正麻烦的不是纯 Python 包,而是 NumPy、SciPy、cryptography 等包含 C/C++/Rust 扩展的依赖:它们需要与 OHOS 的 ABI、musl 工具链和目标架构匹配。
2.3 假设三:把前端 build 目录复制进包里就能跑
JupyterLab 是 Web 应用,但它并不是“纯静态站点”。如果直接把前端资源丢给静态服务器,很多默认调用仍会寻找 Server API。因此所谓“前端静态化”并不是简单复制文件,而是把内核、内容、会话等能力改成浏览器侧或适配层可提供的实现。JupyterLite 的做法证明了这条方向:内核可以在浏览器的 Web Worker 中运行,Python 可由 Pyodide 或 Xeus Python 提供[3]。本文工程采用的是相似的浏览器内核思想,但桌面壳、文件落盘与 HAP 打包仍有自己的适配层。
3. 路线选择:默认 node-static + Pyodide,另外两条路什么时候用

图 2 三种服务模式的取舍:先把核心闭环跑通,再决定是否为完整科学计算生态支付移植成本。
表 2 三种服务模式没有绝对优劣,选择依据是“运行边界”而不是功能数量
| 模式 | 执行位置 | 优点 | 主要代价 | 推荐场景 |
| node-static + Pyodide | 浏览器 Web Worker / WASM | 启动链短;不要求设备先装 Python;最利于先跑通 HAP | 包兼容受 WASM wheel、浏览器网络与线程模型限制 | 教学、脚本、轻量数据分析、离线 Notebook、产品原型 |
| 设备 CPython | 鸿蒙 PC 本机 Python + Jupyter Server | 行为最接近桌面 Jupyter;Server 语义完整 | 解释器、native wheel、体积与更新链路复杂 | 强依赖本地包、需要终端/PTY、需要原生扩展 |
| external Server | 局域网 / 云端 Jupyter Server | 本地包最轻;远端可保留 Conda/GPU/完整生态 | 依赖网络、Token、证书、CORS/反向代理 | 企业计算集群、GPU 工作站、统一环境管理 |
当前主线文档把 `node-static` 作为鸿蒙 PC 的默认模式,并使用 Pyodide 作为浏览器内 Python 内核[2]。这里还有一个版本兼容点值得特别说明:早期轻量分支或旧截图里可能看到 Skulpt。Skulpt 是纯浏览器 Python 实现,体积和接入门槛很低,但语言与第三方包兼容性更有限;当前主线转向 Pyodide 后,执行语义更接近 CPython,且可以加载大量已经编译到 WebAssembly 的科学计算包[4]。
| 版本核对 如果你手上的分支状态栏仍显示 Skulpt,不要直接照着 Pyodide 的包安装与 WASM 说明排错。先确认 `runtime`、前端配置和内核包来自同一基线,再继续。 |
4. 工程架构:把“服务端依赖”拆成可替换边界
跨平台移植最怕把所有差异揉进一个巨大的 `if (ohos)`。更稳定的做法,是先把上游能力拆成边界,再让每个边界有自己的替代实现。这次移植可以分成五层:HAP / Stage 外壳、Electron 运行时、本地静态服务、JupyterLab 前端、Python 内核。
表 3 真正可维护的迁移:平台差异集中在边界层,而不是改遍整个上游代码
| 层级 | 原桌面环境常见做法 | 鸿蒙 PC 适配做法 | 尽量不动的部分 |
| 应用交付 | exe/dmg/AppImage 或浏览器访问 | HAP + Stage 生命周期 | JupyterLab 业务前端 |
| 窗口与 Web Runtime | 系统浏览器或 Electron | OpenHarmony Electron / web_engine | 页面 DOM、Lumino、CodeMirror |
| Web 服务 | Jupyter Server 提供 HTTP/WebSocket | node-static + 适配层,或 external | Lab 静态资源 |
| Python 内核 | ipykernel + CPython | Pyodide Web Worker;可选设备 CPython | Notebook 消息与单元格交互模型 |
| 文件与会话 | Server contents/session API | 本地适配、浏览器持久化或远端 Server | `.ipynb` 文档格式 |

图 3 构建链路:身份化、资源同步、Hvigor、签名和真机验收必须连成一条可重复流水线。
5. 环境与目录:先把版本、架构和资源树钉死
表 4 建议在真正改代码前把这些基础条件一次核对完
| 项目 | 建议基线 | 说明 |
| Node.js | 18+ | 用于 bootstrap、资源同步与构建辅助脚本,不代表目标设备需要预装 Node.js |
| DevEco Studio | 可正常使用 HarmonyOS SDK 与 hvigorw | 第一次建议用图形界面完成 Sync 和调试签名 |
| compatibleSdkVersion | 6.0.1(21) | 当前已验证基线;不要无意写入不匹配的 beta stage |
| targetSdkVersion | 6.0.1(21) | 与上面保持一致,降低 web_engine 工具链漂移 |
| 目标架构 | arm64-v8a / aarch64 | 设备侧 `.so`、可选 CPython 与 native wheel 必须同架构 |
| bundleName | org.jupyter.lab.ohos | 必须拥有独立签名 profile,不能复用姊妹应用签名 |
| ohos_JupyterLab/ |
| 路径漂移说明 不同提交可能把 `electron/`、`web_engine/` 展平到仓库根目录,也可能保留在 `ohos_hap/` 下。不要死记仓库层级;真正要死记的是“应用资源最终进入 web_engine 的 resfile”。 |
6. 第一步:从共用 runtime 派生 Lab 身份
Jupyter Notebook 7 与 JupyterLab 大量复用同一套前端组件,因此在 OHOS 端让两个工程共享 Electron runtime 是合理的工程选择。这样既能减少重复维护,也能把平台修复统一沉淀在一套 runtime 里。代价是“产品身份”必须彻底分离,否则签名、HNP、bundle 和环境变量会互相污染。
| # 仅同步 Electron 主进程与 static server |
一个合格的 bootstrap 至少应该自动处理以下四件事:
- 把 `org.jupyter.notebook.ohos` 替换为 `org.jupyter.lab.ohos`,确保系统把它视为独立应用。
- 把 UI 品牌与启动文案从 Notebook 切换为 JupyterLab,避免“外壳变了、产品身份没变”。
- 清理旧工程的签名材料,让 DevEco 为新 bundle 重新签发 profile。
- 把 `jupyterlab_python.hnp` 调整为应用私有,避免与已安装的 Notebook 抢占同名 public HNP。
| 为什么不手改 这类身份修改看似只有几个字段,但它们分散在 app.json5、build-profile.json5、module.json5、运行时环境变量和资源文案里。脚本化的价值不是省几分钟,而是避免下一次同步上游时漏掉某一处。 |
7. 第二步:把 Python 执行挪进浏览器
7.1 node-static 模式的关键,不是“静态”,而是“内核换位置”
把 JupyterLab UI 变成静态资源只能解决“页面从哪里来”,不能解决“代码在哪里执行”。默认路线的核心是:Notebook 单元格执行请求不再转发给设备上的 `ipykernel`,而是交给浏览器内核适配层,再由 Pyodide 在 Web Worker / WebAssembly 中执行。
| Notebook Cell |
Pyodide 官方定义是“基于 WebAssembly/Emscripten 的浏览器与 Node.js Python 发行版”,本质上是 CPython 的 WASM 移植[4]。它比“只解释一小部分 Python 语法”的轻量方案更接近真正的 Python 运行时,同时仍保持浏览器侧执行的部署优势。
7.2 先用最小代码验证内核,不要一上来测大型包
| print("hello harmony pc") |
这个测试足以验证语法解析、函数调用、循环、列表对象、标准输出与结果回显。只有这条链稳定后,再进入第三方包验证。
7.3 Pyodide 能装包,但别把“官方支持”误写成“你的 HAP 已适配”
Pyodide 可以通过 `micropip` 安装纯 Python wheel,也能加载已经为 wasm32/emscripten 构建的二进制包;官方发行版还包含 NumPy、pandas、SciPy、Matplotlib、scikit-learn 等大量包[4]。但这是 Pyodide 发行版层面的能力,不等于你的 HAP 已经把对应 WASM、lock 文件、wheel、网络访问策略和缓存路径全部打包好。
| # 只有当你的 Pyodide 分发中已经包含对应资源时再做这一步 |
| 边界意识 遇到 `micropip` 找不到包时,先区分:它是纯 Python wheel、Pyodide/emscripten wheel,还是只提供 Linux/Windows/macOS 原生 wheel。后者不能直接塞进浏览器内核。 |
8. 第三步:资源同步到 web_engine,并构建 HAP
这一阶段最值得形成肌肉记忆的是“资源路径契约”。Electron entry 只是应用入口,真正被 web_engine 装载的运行时和前端资源需要进入正确的 resfile。路径放错时最危险,因为构建过程可能完全成功,直到真机启动才给你一个没有上下文的白屏。
| # 同步 Electron 主进程、JupyterLab 前端、Pyodide 等资源 |
| 不要放错模块 `ohos_hap/electron/src/main/resources/resfile/...` 看起来也像“资源目录”,但它不是当前方案真正的应用资源打包树。构建成功 ≠ 资源进包。 |
8.1 锁定 SDK,避免 `import lazy` 被工具链组合误伤
| { |
如果 DevEco 的 Sync、Project Structure 或签名 Fix 改写了 `build-profile.json5`,构建前要重新检查这两个字段。跨平台适配工程最怕“代码没变,工具链悄悄变了”。把已验证组合钉死,比追最新版本更重要。
8.2 关闭 GPU:先换稳定性,再谈硬件加速
OHOS Electron 的 GPU 合成路径在某些运行时组合里可能表现为启动白屏或 XComponent / GPU 进程异常。对 JupyterLab 这种以文本编辑、Notebook 和 2D 图表为主的计算 IDE,优先把 UI 稳定跑起来通常比追求硬件合成更划算。
| // Electron 主进程的典型做法 |
| 排障顺序 白屏时不要第一反应去改前端。先检查资源是否真的进包,再确认 GPU 是否禁用,最后才看页面自身报错。这样排查成本最低。 |
9. 第四步:签名、安装与启动
鸿蒙侧很多“安装失败”并不是业务代码问题,而是产品身份没有完全隔离。bundleName、签名 profile、HNP 类型和 `products[].signingConfig` 四个字段必须同时成立。
9.1 每个 bundle 都要有自己的签名 profile
自动调试签名 profile 与 bundleName 绑定。由 `org.jupyter.notebook.ohos` 生成的 `.p7b` 不能直接拿来给 `org.jupyter.lab.ohos` 签名。正确做法是清理旧签名材料,在 DevEco 的 Signing Configs 中为新 bundle 重新自动签名 / Fix。
9.2 生成材料以后,还要确认 product 真正引用了它
| { |
如果 `products[].signingConfig` 还是空串,Hvigor 可能直接跳过 SignHap,最后给你一个 `electron-default-unsigned.hap`。所以判断签名是否成功,最直观的不是“我刚点过 Fix”,而是看最终产物文件名和构建任务里是否真的执行了 SignHap。
9.3 HNP 用 private,才能与姊妹应用长期共存
| // electron/src/main/module.json5 |
如果 Notebook 已经把同名 HNP 注册为 public,Lab 再声明同名 public 包,系统会按设备级全局包处理,安装阶段就会冲突。改为 private 后,原生包作用域收回到应用自身,两个 HAP 可以各自持有一份。注意:这是模块元数据,修改后必须重新 `assembleHap`。
9.4 安装与启动
| # 方式一:发送后用 bm 安装 |
10. 六类高频坑:从 10705000 到 ImportError 的完整排查链

图 4 排障顺序:先构建与资源,再签名与 HNP,最后才进入运行时与 Python 包。
表 5 错误码真正有价值的不是“记答案”,而是形成稳定的排查层级
| 错误 / 现象 | 典型根因 | 直接检查 | 修复 |
| CompileArkTS 10705000 | SDK / stage 组合导致 `import lazy` 被拒绝 | build-profile.json5 的 compatible/target/stage | 锁定 6.0.1(21),移除不匹配 stage,重新 Sync |
| 启动白屏 | 资源放错模块,或 GPU 合成异常 | web_engine/resfile 是否有 app 资源;GPU 参数 | 重新 build-package;确认 disableHardwareAcceleration / --disable-gpu |
| SignHap 00303074 | 复用旧 bundle 的签名 profile | `.p7b` 是否对应新 bundleName | 清空旧签名材料,为 Lab 重新 Fix / 自动签名 |
| Install 9568320 | 构建得到 unsigned HAP | 产物名;products[].signingConfig | 设为 `default` 后重新 assembleHap |
| Install 9568407 | 同名 public HNP 已被另一应用占用 | module.json5 的 hnpPackages type | Lab 改 private,重新构建 |
| Python ImportError / 安装失败 | wheel 类型不匹配、WASM 资源未带齐、CORS/网络受限 | 包是否有 pure Python 或 emscripten wheel | 预打包兼容 wheel,或改用设备 CPython / external Server |
10.1 为什么白屏是最容易误判的问题
白屏看起来像前端问题,实际上至少有三种不同来源:第一,资源根本没进 HAP;第二,Electron 窗口创建成功但 GPU 合成路径挂了;第三,静态服务已经起了,但加载 URL 或端口没有对上。这三类问题的修复方向完全不同。
- 先解压 / 检查 HAP 资源或确认 build-package 的目标目录有完整应用文件,排除“空包”。
- 确认主进程已经执行 `disableHardwareAcceleration()`,并带上禁用 GPU 的启动参数。
- 检查 static server 是否启动、端口是否被占用、BrowserWindow 最终加载的 URL 是否与实际监听地址一致。
- 最后才打开前端 DevTools / 日志追踪 JS 运行错误。
11. 真机验收:别只验证“能打开”

图 5 真机验收闭环:只有“保存并重开”成功,才算真正完成 Notebook 主流程。
一个桌面 IDE 的验收不能停在“窗口出来了”。建议把功能拆成 T0、T1、T2 三层,先保证底座,再看日常能力,最后评估哪些桌面增强项值得继续移植。
表 6 把功能分层以后,团队会更容易判断“未实现”到底是缺陷还是主动取舍
| 层级 | 能力 | 建议状态 | 说明 |
| T0 | HAP 构建、签名、安装、启动 | 必须通过 | 任何一个失败都说明交付链还不稳定 |
| T0 | Launcher 与 Notebook 渲染 | 必须通过 | 证明主工作区可用 |
| T1 | 新建 / 打开 / 编辑 Notebook | 必须通过 | 日常使用核心 |
| T1 | Python 单元格执行 | 必须通过 | 默认走 Pyodide 浏览器内核 |
| T1 | 保存 / 重开 | 必须通过 | 验证持久化,不接受“只在当前页面看得到” |
| T1 | 文件浏览、Markdown、高亮补全 | 建议通过 | 大部分属于前端能力,应尽量保持 |
| T2 | 终端 / PTY | 可延期 | 浏览器内核天然不等于本地 shell |
| T2 | 完整 native Python 生态 | 按需 | 需要设备 CPython + OHOS wheel 或远端 Server |
| T2 | 系统托盘 / 桌面原生菜单 | 按平台取舍 | 不要为了“像 Windows”而强搬不存在的系统概念 |
11.1 一个推荐的 Notebook 验收脚本
| # Cell 1:基础执行 |
执行完以后不要立即结束。把 Notebook 重命名,保存,关闭应用,再次启动后从文件浏览器重新打开。如果内容、单元格执行计数和输出能按预期恢复,才算完成了一次真正的持久化验收。
12. Pyodide 的能力边界:能跑 Python,不等于等同桌面 CPython
浏览器内核最大的价值,是把 Python 运行时从“设备必须原生支持”变成“WebAssembly 可以承载”。但 WebAssembly VM 与浏览器安全模型也带来了明确边界。Pyodide 文档明确指出,线程、多进程、原生 socket、PTY/termios 等能力受限或不可用;网络请求也要服从浏览器的 CORS、证书和代理策略[5]。
表 7 不要把“浏览器能执行 Python”误解成“桌面 Python 的所有系统能力都存在”
| 能力 | Pyodide 浏览器内核 | 设备 CPython | external Server |
| Python 语法 / 标准库 | 大部分可用,个别模块受限 | 完整度最高 | 由远端环境决定 |
| NumPy / pandas / SciPy | 取决于 Pyodide 分发与已打包 WASM 包 | 需要 OHOS native wheel | 通常最完整 |
| `pip install` 任意 PyPI 包 | 否;只可直接用纯 Python / emscripten wheel 等兼容包 | 取决于 OHOS wheel | 通常可按服务器平台安装 |
| 原生 socket / PTY / 终端 | 明显受限 | 可实现但需系统适配 | 通常完整 |
| 多进程 / 原生线程 | 受 WebAssembly/浏览器限制 | 按设备 Python 能力 | 按服务器能力 |
| 离线运行 | 可做到,但需把资源预打包 | 可做到,包体会更大 | 依赖网络 |
| 升级成本 | 前端资源 / WASM 包级别 | 解释器 + native 依赖 | 服务器侧集中升级 |
| 一个实用原则 如果目标是课堂演示、算法练习、轻量数据处理和离线 Notebook,Pyodide 很合适;如果目标是大型科学计算、系统编程、GPU、PTY 或大量 native 包,应该尽早切换到设备 CPython 或 external Server。 |
13. 什么时候切到设备 CPython 或 external Server
13.1 设备 CPython:当“离线 + 完整本地”是硬要求
设备 Python 模式的优势是语义最接近传统桌面 Jupyter:kernel、文件系统、终端和第三方包都可以回到 Server 模型。但它把移植成本从“Web 兼容”转移到了“语言运行时与 native 生态”。OpenHarmony PC Developer 侧已经在推进 CPython 3.12 与 `ohos_aarch64` wheel 生态[6],这条路线会随着生态成熟越来越可行,但每个包含 C 扩展的包仍然需要独立验证。
| JUPYTERLAB_OHOS_SERVER_MODE=python JUPYTERLAB_OHOS_PYTHON_DIST=/path/to/python-ohos-aarch64-3.12 node pkg/ohos/build-hap.mjs |
13.2 external Server:当“本地只是入口,计算在别处”
如果企业已经有 JupyterHub、GPU 工作站或远程 Conda 环境,external 模式往往是工程上最划算的方案。鸿蒙 PC 只需要提供稳定的 JupyterLab 客户端,真正的 kernel、文件与包管理留在服务器侧。这样既保留完整科学计算生态,又能把 HAP 体积和 native 依赖压到最低。
| export JUPYTERLAB_OHOS_SERVER_MODE=external |
| 安全边界 external 模式需要把 Token、TLS、反向代理、跨域策略和网络可达性一起设计。它不是“填一个 URL 就结束”,但这些问题比在客户端重新编译整套科学计算栈更容易集中治理。 |
14. 一条可复现的最短路径
把前面的工程细节压缩成一条可以重复执行的路径,顺序如下。第一次建议在 DevEco 中完成 Sync 与签名,后续再把稳定步骤逐步迁移到命令行。
| # 1. 获取工程 |
如果你的仓库目录与上面略有差异,优先以当前分支的 `README.OpenHarmony_CN.md`、`OHOS_ADAPTATION.md` 和实际 `build-profile.json5` 为准。真正需要保持不变的是步骤关系:身份化 → 资源入包 → 工具链锁定 → 签名 → 安装 → 功能验收。
15. 常见问题 FAQ
Q1:为什么不直接把完整 Python + Jupyter Server 打进 HAP?
可以,但这会立刻把问题升级成 CPython 运行时、OHOS aarch64 native wheel、HAP 体积、升级与安全补丁的组合工程。默认 Pyodide 路线的价值,是先把核心 Notebook 闭环从这些依赖里解耦。
Q2:Pyodide 既然支持 NumPy,为什么还要说“科学计算栈受限”?
因为 Pyodide 官方支持的是“发行版中已有的 WASM 包或兼容 wheel”。你的 HAP 是否离线带齐这些资源、是否允许运行时联网下载、是否遇到 CORS、内存与线程限制,是另一层问题。
Q3:早期分支显示 Skulpt,当前文档写 Pyodide,应该信哪个?
信你实际分支的 runtime 与内核配置。Skulpt 与 Pyodide 是两条不同的浏览器 Python 路线;截图、文档和代码如果不在同一提交基线上,排错会被带偏。
Q4:安装时报 9568320,但我已经在 DevEco 里自动签名了?
先看输出文件名。如果还是 `unsigned.hap`,继续检查 `products[].signingConfig` 是否真的指向 `default`。签名材料存在,不代表 SignHap 任务一定执行。
Q5:安装时报 9568407,卸载 Notebook 后又能装了,为什么?
这是典型的同名 public HNP 冲突。Lab 侧把 `jupyterlab_python.hnp` 改为 private,再重新构建,让两个应用各自拥有独立作用域。
Q6:应用启动白屏,最先查什么?
先查 `web_engine/.../resfile/resources/app` 是否有完整资源,再查 GPU 禁用是否生效,最后检查 static server 的端口与 loadURL。不要一开始就重写前端。
Q7:这套方案适合生产环境吗?
如果你的需求是轻量本地 Notebook,它已经具备很清晰的工程闭环;如果需要大型 native 包、GPU、终端或企业级多用户计算,建议把它当客户端,连接 external Server,或继续补设备 CPython 生态。
16. 收束:这类跨平台迁移真正要迁的是“边界”
把 JupyterLab 搬到鸿蒙 PC,最有价值的部分并不是最终那张“能打开 Notebook”的截图,而是重新理解一个复杂桌面工具到底由哪些可替换边界组成。JupyterLab 的前端工作区并不需要因为平台变化而重写;真正需要适配的是窗口运行时、Server 语义、Python 内核、资源打包、签名身份和文件持久化。
这也是为什么“Electron 壳 + 前端静态化 + 浏览器内 Python”是一条很实用的第一阶段路线:它先把最难的 native Python 生态从启动链上拿走,让 HAP 能稳定安装、让 Launcher 能打开、让 Notebook 能执行、让文件能保存。等 T0/T1 稳住,再根据业务场景把设备 CPython、终端、完整科学栈或远程 Server 一项项接回来。
做跨平台迁移时,最危险的思路是“把原平台所有东西原封不动搬过来”;更有效的思路是先问:哪一层是真正的产品价值,哪一层只是原平台的实现方式。这次保住的是 JupyterLab 的交互式计算体验,替换的是承载与执行边界。只要这个原则不变,未来无论 Electron runtime、Pyodide、OHOS Python 生态还是 JupyterLab 上游继续升级,工程都还有清晰的演进路径。
| 最终检查 构建成功不算结束;只有 signed HAP 可安装、启动不白屏、Notebook 可执行、文件能保存并重开、姊妹应用能共存,这次移植才真正闭环。 |
参考资料
[1] Project Jupyter — JupyterLab: A Next-Generation Notebook Interface Project Jupyter | Home
[2] OpenHarmonyPCDeveloper — ohos_jupyter / JupyterLab HarmonyOS PC 适配仓库 ohos_jupyter:基于 OpenHarmony 生态的 JupyterLab PC 客户端项目 - AtomGit
[3] JupyterLite Documentation — Adding kernels / browser-based kernels Adding kernels — JupyterLite 0.9.0-alpha.1 documentation
[4] Pyodide Documentation — Python in the browser / loading packages Pyodide — Version 314.0.7
[5] Pyodide Documentation — WebAssembly / browser compatibility constraints Pyodide Python compatibility — Version 314.0.7
[6] OpenHarmony PC Developer — Python 生态与 ohos_aarch64 wheel 方向 Python 生态 · OpenHarmony PC Developer
更多推荐


所有评论(0)