diff --git a/POC/Flutter-OH-POC.md b/POC/Flutter-OH-POC.md new file mode 100644 index 0000000..f01bac2 --- /dev/null +++ b/POC/Flutter-OH-POC.md @@ -0,0 +1,507 @@ +# Flutter_OH(OpenHarmony)适配 POC 验证报告 + +> **文档状态:** 部分实施;OHOS 工程生成与 debug HAP 构建已通过 +> +> **验证范围:** 现有 Flutter Android / iOS App 基线 → `harmony` 分支 → OpenHarmony 模拟器 +> +> **结论边界:** 本轮没有真机。本文只用于判断开发、构建、业务代码复用和集成路径的可行性;不得将模拟器结果表述为鸿蒙生产可用或真机功能已验证。 + +## 修订历史 + +| 版本 | 日期 | 状态 | 说明 | +| --- | --- | --- | +| 0.1 | 2026-09-02 | POC 方案已冻结 | 定义范围、验收矩阵、证据要求及决策规则,实施后持续回写实际结果 | +| 0.2 | 2026-09-02 | 部分通过 | 记录 Flutter_OH 3.41.10-ohos-1.0.0 / Dart 3.11.5 的依赖解析和 `main_dev.dart` debug HAP 构建通过;确定首期 ArkTS 采用宿主 `entry` MethodChannel 路径 | + +## 0. 结论摘要(实施后填写) + +### 0.1 本 POC 回答的问题 + +本 POC 不回答抽象的“Flutter 能不能做鸿蒙”,而基于 Continental Retail APP 已可运行的 Android / iOS Flutter 基线,回答以下可交付的问题: + +1. 能否用 Flutter_OH 在 OpenHarmony 模拟器上完成工程生成、构建、安装、启动和调试? +2. 当前 Dart 业务层、Flutter UI、状态管理、网络、路由和 H5 容器能复用多少;哪些部分必须做 OHOS 专项适配? +3. Dart 公共 API → App 宿主 `entry` → ArkTS 的原生能力链路是否可实现;当前 `native_*` facade 是否适合接入 OHOS? +4. 嵌入 H5 的 WebView / JSBridge 容器能否按现有协议工作? +5. 是否值得进入真机验证与正式鸿蒙适配阶段;需要投入什么改造和持续维护成本? + +### 0.2 最终结论卡(实施后填写) + +| 项目 | 结果 | +| --- | --- | +| 推荐级别 | `部分通过;尚不足以给出 Conditional Go` | +| 使用的 Flutter_OH 版本 | Flutter `3.41.10-ohos-1.0.0`;Dart `3.11.5` | +| App 基线 | `harmony_3.41.9` 分支;本轮使用 `lib/main_dev.dart` | +| 模拟器基线 | 待记录 DevEco Studio、SDK、设备镜像/API、系统 Build | +| 已证明的能力 | OHOS 工程存在;依赖解析完成;debug HAP 可由 Flutter_OH + hvigor 构建输出 | +| 未证明的能力 | 模拟器运行/热重载、Dart/ArkTS 桥接、真机相机与实体扫码、相册/文件、权限、定位、推送、性能、签名发布、真实 F6 页面 | +| 下一阶段 Gate | 先完成宿主 MethodChannel 探针与模拟器运行,再至少一台目标真机上的原生能力、真实 H5/F6、稳定性与发布验证 | + +**结论规则:** 本轮 HAP 构建通过仅证明工具链和 Dart 编译链路可用,不能推导出 App 已可运行或原生能力已接通。没有真机时,即使模拟器中所有计划项通过,本 POC 的最高结论也只能是 **Conditional Go**。只有工具链、代表性业务闭环、JSBridge 和 ArkTS 原生桥接均不存在不可控阻塞时,才能建议进入真机阶段。 + +### 0.3 已获得的构建证据与未关闭项 + +在 App 仓库根目录执行 `. .\enable-ohos.ps1`,再进入 `app` 目录执行: + +```powershell +flutter build hap --debug -t lib\main_dev.dart +``` + +依赖解析及 hvigor 构建成功,输出 `app/ohos/entry/build/default/outputs/default/entry-default-unsigned.hap`。该产物是**未签名的 debug HAP**,不等同于已安装、已启动或可发布的完整验证。构建期间仍有 `targetSdkVersion` 未显式配置的 hvigor warning,需在后续 OHOS 工程配置中处理。 + +首次依赖解析曾因 Dart `3.11.5` 不满足 `^3.12.0`,以及 Flutter 固定 `meta 1.17.0` 与较新 Riverpod generator 的 analyzer 约束冲突而失败。当前 `harmony` 兼容组合为 `flutter_riverpod 3.2.1`、`riverpod_annotation 4.0.2`、`riverpod_generator 4.0.3`、`pigeon 26.3.1`;已对受影响包重新执行 Riverpod codegen 后构建通过。`native_scan` 现存 Pigeon 产物的生成版本标头仍须在后续以锁定的 Pigeon 26.3.1 重新生成或核验,这是生成物完整性检查,不代表 OHOS bridge 已完成。 + +## 1. 验证对象、范围与边界 + +### 1.1 POC 对象 + +- **代码基线:** 已有、可运行的 Android / iOS Flutter App 源码;实施开始前记录一个确定的 Git Commit。 +- **工作分支:** 从该 Commit 创建 `harmony` 分支。POC 不直接向主干回灌鸿蒙改造。 +- **运行环境:** DevEco Studio 的 OpenHarmony 模拟器;设备型号、系统镜像、API 级别和 Build 均须记录。 +- **H5 验证对象:** POC 自带的可控测试页,而不是 F6 正式页面;因此验证的是 App 容器与桥接契约,不代表真实 F6 已完成联调。 +- **后端数据:** 如需调用真实接口,只能使用开发/测试环境及测试账号,不使用生产数据。 + +### 1.2 本轮范围 + +1. Flutter_OH 工具链、OHOS 工程、依赖解析、编译、安装、启动、调试和热重载可行性。 +2. 一个代表性业务闭环:登录/已有会话 → 首页 → 一个真实业务页面,覆盖路由、状态管理、网络、加载态、空态和错误态。 +3. 现有 WebView 容器及 JSBridge:可控 H5 页完成握手、H5→App 调用、App→H5 回调、成功/失败回包、未知方法和来源校验。 +4. OHOS 原生宿主桥接路径:Dart 公共 API → `native_*` 内部 MethodChannel → `app/ohos/entry` ArkTS 实现 → 成功结果与标准错误回传。 +5. 当前依赖与原生能力的 OHOS 兼容矩阵、实际代码改动分类和维护成本评估。 +6. Android / iOS 共享代码的回归检查,确认鸿蒙分支没有破坏既有行为。 + +### 1.3 明确不在本轮结论内 + +| 能力 | 本轮处理方式 | 原因与后续 Gate | +| --- | --- | --- | +| 相机实拍、二维码/条码实体扫码、车牌/VIN 识别 | 仅验证编译、注册、调用及错误语义 | 模拟器不能替代真实镜头、权限和硬件 SDK;必须真机验证 | +| 相册、文件选择、真实文件上传、运行时权限 | 可记录模拟器观察,但不关闭验收 | 与真实设备系统服务、路径和权限行为有关 | +| 定位、蓝牙、推送、后台任务、埋点/崩溃 SDK | 登记兼容性与实现路径 | 未纳入代表性最小闭环,留待真机专项验证 | +| 真实 F6 页面、票据、账号与业务联调 | 仅验证共同的 JSBridge 契约 | 依赖外部环境、账号和排期 | +| 性能、功耗、包体、机型兼容、商店上架 | 不评估 | 需要真机、正式签名和稳定性测试 | +| 全部业务模块 | 不评估 | 本 POC 只证明一条代表性链路,不能外推为全量适配完成 | + +## 2. Flutter_OH 技术现状与调研方法 + +### 2.1 术语与上游边界 + +本文中的 **Flutter_OH** 指 OpenHarmony-SIG 维护的 Flutter OpenHarmony 适配分支及其工具链,不是 Google Flutter 主线内置的平台。安装前不得把“`flutter_harmony`”作为既定的工具或包名;应以实际选定的上游仓库、Tag/Commit、安装说明和命令输出为准。 + +当前调研以 OpenHarmony-SIG 的 `flutter_flutter` 仓库和其环境搭建指南作为一手资料。官方资料说明该仓库是 OpenHarmony Flutter SDK 的来源,并以 `dev` / `master` 等分支说明安装与开发环境;POC 必须锁定实际使用的 Tag 或 Commit,避免“使用最新版”这种不可复现的描述。[Flutter_OH 上游 README](https://gitee.com/openharmony-sig/flutter_flutter/blob/master/README.md?force_mobile=true) · [OpenHarmony Flutter 环境搭建指南](https://gitee.com/openharmony-sig/flutter_samples/blob/master/ohos/docs/03_environment/%E9%B8%BF%E8%92%99%E7%89%88Flutter%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E6%8C%87%E5%AF%BC.md) + +### 2.2 调研记录表(实施前先补齐) + +| 维度 | 需要记录的事实 | 证据来源 | +| --- | --- | --- | +| 上游治理 | 维护组织、仓库、许可证、分支策略、发布机制 | 上游仓库 README、LICENSE、Release、治理页面 | +| 版本匹配 | App 当前 Flutter/Dart 与 Flutter_OH Tag/Commit 的对应关系和版本滞后 | `flutter --version`、Git Tag/Commit、构建日志 | +| 社区健康度 | 最近 12 个月提交、Release、Issue/PR 活跃度及关键问题响应 | 上游仓库公开记录,注明采集日期 | +| 构建链路 | Windows、DevEco Studio、OpenHarmony SDK、ohpm/hvigor、Node/Java 的实际要求 | 官方环境文档 + 本地命令输出 | +| 插件生态 | 项目实际依赖的 OHOS 状态与替代方案 | 插件官方仓库/包说明 + 本 POC 构建结果 | +| 可维护性 | 项目团队需自维护的 ArkTS、fork、版本升级和 CI 工作 | POC 改动清单、Issue、风险登记 | + +### 2.3 首个硬门禁:SDK 匹配 + +现有工程文档把 Flutter `3.44.9` 作为未来 OHOS 的兼容窗口,但这个假设不能替代实际验证。POC 首先执行以下判断: + +1. 选定 Flutter_OH 的可复现 Tag/Commit;不直接使用会变化的“最新 `dev`”。 +2. 记录该 SDK 的 Flutter/Dart 版本,并与 Android/iOS 基线、`pubspec.lock`、插件约束逐项比较。 +3. 用未改业务的 App 基线完成依赖解析和 OHOS 编译。 +4. 若版本无法兼容,立即记录为阻塞:是需要升级/降级 Flutter、替换依赖,还是当前无可行版本;不得通过私自改动业务代码或跳过插件来宣称“原代码可复用”。 + +只有该门禁通过,才能进入业务和原生能力验证。 + +## 3. 基线、分支与环境冻结 + +### 3.1 分支策略 + +1. 在实际 App 仓库确认 Android/iOS 基线已构建和测试通过。 +2. 记录基线 Commit、当前 Flutter/Dart/FVM 版本、`pubspec.lock`、Android/iOS 构建结果。 +3. 由该 Commit 创建 `harmony` 分支;所有 OHOS 改动仅在该分支提交。 +4. 不改变既有 Android/iOS 对外业务 API;平台差异收敛在构建配置、`native_*` 内部 transport 与 App 宿主 `ohos/entry` ArkTS 层。Feature、H5 和 Dart entrypoint 不直接调用 OHOS channel。 +5. 每次关键里程碑提交均在本文附录登记 Commit、变更摘要、构建命令和结果。 + +### 3.2 环境锁定表(实施时填写) + +| 项目 | 固定值 | 证据 | +| --- | --- | --- | +| Windows 版本 / 架构 | 待填写 | `winver` / 系统信息 | +| DevEco Studio | 待填写 | About 截图 / 版本命令 | +| OpenHarmony SDK / API | 待填写 | SDK Manager 截图 / 配置 | +| 模拟器镜像与 Build | 待填写 | Device Manager / 系统设置截图 | +| Node / Java / ohpm / hvigor | 待填写 | 版本命令输出 | +| Flutter_OH 来源、Tag、Commit | 待填写 | `git remote -v`、`git rev-parse HEAD` | +| Flutter / Dart 版本 | 待填写 | `flutter --version` | +| App 基线 Commit | 待填写 | `git rev-parse HEAD` | +| Pub 缓存、镜像与代理 | 待填写 | 环境变量与配置,脱敏后归档 | + +### 3.3 证据归档规则 + +- 每条验证结论至少附一个可复现命令日志和一个可观察证据(截图、录屏、构建产物或测试输出)。 +- 截图、录屏和日志放入 `tech-selection/assets/flutter-oh-poc//`;正文只引用相对路径和简短说明。 +- 日志中出现 Token、Cookie、账号、内网地址、签名或密钥时,归档前必须脱敏。 +- 失败项保留完整报错、最小复现命令、尝试过的版本/方案和最终阻塞判断,不能只写“暂不支持”。 + +## 4. 可执行教程:从现有 App 跑到鸿蒙模拟器 + +本章是 POC 的操作手册。请严格按顺序执行:每一步先记录实际命令和输出,再进入下一步。遇到失败时,不要通过删除依赖、注释业务代码或改用空白 Demo 来“跑通”;先把失败作为兼容矩阵的一条证据记录下来。 + +### 4.1 我们如何分工 + +| 阶段 | 我可协助完成的工作 | 需要你在本机 / GUI 中完成的工作 | 你需要回传的最小信息 | +| --- | --- | --- | --- | +| 基线确认 | 检查 Git、Flutter、依赖、现有测试与改造差异 | 打开实际 App 源码仓库 | 仓库路径、基线分支/Commit、`flutter --version` | +| Flutter_OH 安装 | 给出命令、检查版本和环境变量、解释报错 | 下载/克隆 SDK,配置本机工具 | Flutter_OH 路径、Tag/Commit、版本输出 | +| DevEco 与模拟器 | 根据截图判断配置与设备识别问题 | 安装 DevEco Studio/SDK,在 Device Manager 创建并启动模拟器 | DevEco 版本、模拟器截图、系统/API Build | +| 项目迁移与构建 | 分析依赖、代码和构建报错,给出最小修复建议 | 在真实 App 仓库执行命令、打开/运行 OHOS 工程 | 完整命令、报错文本、相关文件片段 | +| 运行效果验证 | 制定逐页检查单,核查截图/录屏和日志 | 在模拟器中登录、点击页面、观察 Flutter UI 与调试输出 | 截图/录屏、用例编号、实际/预期差异 | +| 原生能力与 H5 | 审查 ArkTS/Flutter 接口、JSBridge 协议和错误语义 | 触发可在模拟器中操作的调用,保存日志 | 请求/响应、插件日志、模拟器表现 | + +### 4.2 开始前:确认 App 基线没有问题 + +**目标:** 证明后续问题来自 OHOS 接入,而不是原 Android/iOS 基线本身。 + +在实际 Flutter App 仓库根目录执行。以下命令中的 `<...>` 是你需要替换的占位符;输出不要包含账号、Token 或内网地址。 + +```powershell +git status --short +git branch --show-current +git rev-parse HEAD +flutter --version +flutter doctor -v +flutter pub get +``` + +然后执行该仓库既有的静态检查和测试命令;若项目使用 Melos、FVM 或 CI 脚本,优先用项目已有脚本,不能自行换一套命令。记录: + +- 当前分支和 Commit;必须是 Android/iOS 已可运行、可复现的基线。 +- Flutter、Dart、FVM(如有)和依赖锁文件版本。 +- 已通过的检查及失败项;失败项先在原平台澄清,不带入鸿蒙 POC。 + +**检查点 G-00:** 只有基线可复现时,才创建 `harmony` 分支。 + +```powershell +git switch -c harmony +git status --short +``` + +预期结果是当前分支为 `harmony`,工作区没有与本 POC 无关的未提交改动。将基线 Commit 和创建分支后的 Commit 写入“3.2 环境锁定表”。 + +### 4.3 安装 Flutter_OH:先锁版本,再配置 PATH + +**目标:** 不使用模糊的“安装鸿蒙 Flutter”,而是得到一个能追溯到上游 Commit 的 SDK。 + +1. 阅读上游 README 和环境搭建指南,选择一个候选 Tag 或 Commit。不要直接把当前 Android/iOS Flutter 版本假定为已有对应 OHOS 版本。 +2. 在 Windows 上将 Flutter_OH、实际 App 工程及其本地插件放在**同一个磁盘分区**;这是上游 Windows 环境说明中的约束。建议使用空间充足的开发盘,例如 `D:\dev\`。 +3. 克隆上游后固定 Commit,再把该 SDK 的 `bin` 临时加入当前 PowerShell 会话的 PATH。示例: + +```powershell +$flutterOhRoot = 'D:\dev\flutter_flutter' +git clone https://gitee.com/openharmony-sig/flutter_flutter.git $flutterOhRoot +git -C $flutterOhRoot fetch --tags +git -C $flutterOhRoot checkout <已确认的Tag或Commit> +git -C $flutterOhRoot rev-parse HEAD + +$env:Path = "$flutterOhRoot\bin;$env:Path" +flutter --version +flutter doctor -v +``` + +4. 把 `git remote -v`、最终 Commit、`flutter --version` 和 `flutter doctor -v` 的输出归档到附录 A 的 E-01。只有这些信息完整时,才可以称为“某版本 Flutter_OH 的验证结果”。 + +**检查点 G-01:** `flutter --version` 必须来自 Flutter_OH 路径,且其 Flutter/Dart 版本与 App 基线及 `pubspec.lock` 的约束不存在立即冲突。若 `pub get` 已经失败,停止向后执行,先在 4.7 的故障表登记版本/依赖问题。 + +### 4.4 DevEco Studio 与模拟器:由你操作的 GUI 步骤 + +1. 安装与选定 OpenHarmony SDK 匹配的 DevEco Studio,并通过 SDK Manager 安装目标 API、模拟器镜像、ohpm/hvigor 所需组件。 +2. 打开 DevEco Studio 的 Device Manager,创建一个 Phone 模拟器;启动后进入系统设置,截图记录设备型号、OpenHarmony/HarmonyOS 版本、API 级别和 Build。 +3. 保持模拟器运行,在 PowerShell 中执行: + +```powershell +flutter devices +``` + +4. 从输出中找到 OHOS 模拟器对应的 ``。不要手工猜测设备 ID;将完整输出保存到 E-01。 + +**检查点 G-02:** `flutter devices` 能列出正在运行的 OHOS 模拟器。若只显示 Windows/Chrome/Android 等设备,先不要执行 `flutter run`;检查模拟器是否真的启动、DevEco SDK/环境变量是否与 Flutter_OH 匹配,再保存 `flutter doctor -v` 和 `flutter devices` 输出供排查。 + +### 4.5 使用既有 OHOS 工程首次运行 + +`app/ohos` 已在本轮生成并完成 HAP 构建,**不得重复执行** `flutter create --platforms ohos .`,也不创建新的 Dart `main` 文件。现有环境入口使用 `lib/main_dev.dart`、`lib/main_uat.dart` 和 `lib/main_prod.dart`。 + +只有在一个新的 `harmony` 工作树中确认 `app/ohos` 缺失、并在运行前后人工审查 Git diff 时,才允许在 `app` 目录执行一次 `flutter create --platforms ohos .`。当前工作树的后续运行与构建从仓库根目录执行: + +```powershell +. .\enable-ohos.ps1 +cd app +flutter pub get +flutter devices +flutter run --debug -d -t lib\main_dev.dart +``` + +上游 README 公开了 `flutter create --platforms ohos `、`flutter devices`、`flutter run --debug -d ` 和 `flutter build hap --release` 作为 OHOS 工程的创建、设备发现、调试运行和正式构建入口。本 POC 仅在 OHOS 平台目录缺失时使用一次 `--platforms ohos` 生成;任何生成操作前后都要看 Git diff,防止工具意外改写 Android/iOS 配置。[上游 Flutter_OH README](https://gitee.com/openharmony-sig/flutter_flutter/blob/master/README.md?force_mobile=true) + +首次运行时你的操作是: + +1. 在模拟器中观察 App 是否安装、是否出现启动页、是否白屏/闪退。 +2. 在终端保留完整输出;运行中的 Flutter 工具可用 `r` 触发热重载、`R` 触发热重启、`q` 退出。 +3. 截取首屏和终端成功日志;若失败,复制第一段真正的 `Error` / `Exception` 及其前后上下文,不要只发最后一行。 + +首次可运行后执行一次构建验证(若只需复现本轮已通过的编译证据,也可直接执行本命令): + +```powershell +flutter build hap --debug -t lib\main_dev.dart +git status --short +git diff --stat +``` + +**检查点 G-03:** HAP 调试构建已通过;调试运行和热重载仍待执行。只有三者均成功、OHOS 生成物及必要配置可在 `harmony` 分支中解释,且 Android/iOS 文件没有出现非预期改动时,才关闭本检查点。 + +### 4.6 观察 Flutter 业务代码的实际运行效果 + +工具链启动成功后,不要马上开始大面积改插件。先用现有业务代码跑完以下最小闭环,借此区分“Flutter 共享代码可以直接复用”与“某个插件阻塞启动”。 + +1. 在模拟器进入登录页,或按项目已有方式恢复测试登录态。 +2. 完成登录后确认首页可显示,依次检查文本、图片、列表、底部导航、路由进入/返回和加载态。 +3. 打开一项依赖接口数据的真实业务页面,记录成功、空数据、网络异常或服务端异常时的表现。 +4. 对一个纯 Dart/Flutter 的可见文案做极小修改,执行 `r` 热重载,截图记录修改前后;这证明 Flutter 调试循环正常,不等于全量业务已适配。 +5. 对每个异常记录:页面、操作、预期、实际、终端日志、截图路径、初步归属(Dart/UI、插件、OHOS 工程、服务端)。 + +建议回传给我的单条问题格式如下,我可以据此继续分析并给出下一步代码改动: + +```text +用例编号:B-03 +当前 Commit: +操作:登录后点击“库存”进入列表 +预期:显示列表;网络失败时显示已有重试页 +实际:页面白屏 / 正常 / 报错文案 +终端完整异常:<从第一行 Error 到堆栈结束> +截图或录屏:<相对路径> +是否可复现:每次 / 偶发;复现步骤 +``` + +### 4.7 逐个处理依赖,而不是一次性删掉所有插件 + +首次 `flutter pub get`、`flutter run` 或 `flutter build hap` 很可能暴露不支持 OHOS 的依赖。处理顺序固定如下: + +1. 从**第一个阻塞错误**开始,记录包名、版本、错误、调用方和业务影响。 +2. 查该依赖的官方仓库/包说明及 OpenHarmony 适配实现;把结论写入 5.2 的兼容矩阵。 +3. 判定为“直接复用 / 小幅适配 / OHOS 专项实现 / 替换依赖 / 当前不可行”之一。 +4. 对不影响启动的非核心依赖,可临时显式返回 `Unsupported` 以继续验证业务主链路;该临时降级必须在风险台账中登记,不能删除调用或伪造成功。 +5. 每完成一个依赖的处理,重新执行 `flutter pub get`、`flutter build hap --debug` 和最小业务闭环,确保没有引入回归。 + +建议优先级如下: + +| 优先级 | 依赖/能力类别 | 原因 | +| --- | --- | --- | +| P0 | Flutter SDK、状态管理、路由、网络、认证、基础存储 | 决定 App 能否启动和承载真实业务 | +| P0 | WebView / JSBridge | 该项目的核心业务链路会嵌入 F6 页面 | +| P1 | 扫码、相机、文件、权限的原生注册与桥接 | 验证可维护的 ArkTS 宿主接入路径;真实硬件留待真机 | +| P2 | 定位、蓝牙、推送、埋点、崩溃上报、弱网 | 本轮记录实现路径与风险,不阻塞代表性闭环 | + +### 4.8 验证 WebView 与可控 H5 测试页 + +本轮不等待 F6 环境。先在 App 内加载一个由 POC 管理的测试页,验证容器与 JSBridge 的安全协议。测试页只用于调试,不能替代真实业务 H5。 + +1. 沿用 `core_webview` 中已有的目标白名单、来源校验、请求 ID 和回包格式;不要新建一套“POC 专用协议”。 +2. 测试页依次发起 `ping` / 获取 App 信息、一个纯 Dart 回包、一个需进入原生适配层的调用,以及一个故意错误的调用。 +3. 每个请求在页面上显示 `{ id, method, params }`,并显示来自 App 的成功回包或错误码;App 日志同时记录相同 `id`,以便定位跨端问题。 +4. 验证未知方法、类型错误参数和非白名单来源被拒绝,且不会触发原生能力。 +5. 再由 App 向 H5 回发一个事件或结果,确认 H5 可关联到原请求。 + +当你在模拟器中执行时,请对每条 W-01 至 W-06 用例保存一张“请求 + 回包”的截图,并附同一 `id` 的 Flutter 日志。若 WebView 本身无法编译或加载,这本身是 P0 兼容性结论,不要绕过它改为浏览器打开测试页。 + +### 4.9 验证 Dart → ArkTS 原生宿主桥接 + +模拟器不能证明相机和扫码可用,但可以验证“项目有能力把原生功能接进来”。按以下最小路径实现和验证: + +1. 找到项目当前原生能力的公共 Dart API;架构上始终由 `native_*` 对外暴露,Feature 和 H5 不直接依赖通道实现。 +2. 不给 `native_*` 添加 OHOS plugin 声明,也不创建 package 内 `ohos/` 目录。在 `app/ohos/entry/src/main/ets/` 增加宿主桥接注册和 ArkTS 实现;`EntryAbility.ets` 只保留生命周期、Flutter engine 与 bridge 注册。 +3. 先实现不使用硬件的 `getPlatformInfo` 或 `echo` 探针:`native_*` 内部 MethodChannel 传入固定参数,ArkTS 返回平台信息/同一参数,Dart 映射为类型化结果。 +4. 人为触发一个可预期失败,例如未知操作或硬件不可用;验证 Dart 最终收到标准错误,而不是裸 `PlatformException`、空值或无限等待。 +5. 再接通现有 `native_scan` / `native_media` 的入口,只验证 facade 能进入 OHOS 分支、宿主 bridge 可编译,并正确报告“待真机”的硬件不可用状态。 + +对每一个 Dart ↔ ArkTS 方法,在本文附录或实际宿主实现目录维护一行契约:`channel 名`、`方法名`、`参数`、`返回值`、`错误码`、`Dart 调用点`、`ArkTS 实现文件`。Pigeon 不生成 ArkTS,且不得人工复刻其 `BasicMessageChannel`、自定义 codec 和生成 envelope;这张契约表是手写 MethodChannel 防止接口漂移的最低要求。 + +### 4.10 常见失败的处理顺序 + +| 现象 | 优先检查 | 不应采取的做法 | +| --- | --- | --- | +| `flutter` 仍指向官方 SDK | `Get-Command flutter`、PATH 优先级、`flutter --version` | 混用两个 SDK 后继续构建 | +| `flutter devices` 没有 OHOS 模拟器 | DevEco 中设备是否启动、SDK/环境变量、`flutter doctor -v` | 手工伪造 device-id | +| `flutter create` 或构建报版本/引擎错误 | Flutter_OH Commit、Flutter/Dart 版本、同盘约束、完整错误日志 | 强行升级/降级依赖而不记录 | +| 某个插件没有 OHOS 实现 | 兼容矩阵、插件说明、调用影响范围;区分第三方 plugin 与 App 宿主 bridge | 直接删除依赖或把业务调用注释掉 | +| 启动白屏/闪退 | 第一个异常、`EntryAbility` bridge 注册、OHOS 工程配置、最小业务入口 | 只截最后一行错误 | +| WebView 加载失败 | WebView 依赖 OHOS 支持、白名单、控制台/Flutter 日志 | 改用外部浏览器来宣称 H5 通过 | +| 相机/扫码不可用 | 是否为模拟器硬件限制、插件是否已注册、错误码 | 以 mock 成功结果替代真机测试 | + +### 4.11 每日回填与协作节奏 + +每完成一个 Gate,在“附录 A. POC 证据索引”新增一行,并在对应验证表将状态从“待填写”改为“通过 / 部分通过 / 失败 / 待真机”。建议以以下最小包回传,我可以据此继续带着你推进: + +1. 当前 `harmony` 分支 Commit 与本次执行的命令。 +2. 原始终端输出或脱敏后的完整日志文件。 +3. 模拟器截图/录屏,以及对应的用例编号。 +4. `git diff --stat`;若改了配置或插件,再附相关文件的 diff。 +5. 你对“预期 / 实际”的一句话说明。 + +我会据此判断是环境问题、Flutter_OH 版本问题、第三方插件问题、共享 Dart 代码问题还是必须留待真机的问题,并给出下一条最小可执行操作,而不是让你一次性排查整套鸿蒙工具链。 + +## 5. 实施步骤与记录模板 + +### 5.1 工具链与 OHOS 工程 + +| 步骤 | 实施动作 | 通过标准 | 实际结果 / 证据 | +| --- | --- | --- | --- | +| T-01 | 按官方资料安装 Flutter_OH 与依赖工具 | `flutter --version` 显示锁定版本;环境变量配置可复现 | 待填写 | +| T-02 | 配置 DevEco Studio、OpenHarmony SDK 和模拟器 | 模拟器可启动并被工具识别 | 待填写 | +| T-03 | 在 `harmony` 分支生成/补齐 OHOS 工程 | 工程结构完整,配置不污染 Android/iOS | 待填写 | +| T-04 | 执行依赖解析和调试构建 | 无阻塞性依赖或编译错误 | 待填写 | +| T-05 | 安装并启动 App | 首屏正常显示,无启动崩溃 | 待填写 | +| T-06 | 调试与热重载 | 可附加调试器;关键 Dart 修改生效 | 待填写 | + +### 5.2 代码复用与依赖兼容矩阵 + +对每个实际依赖和代码层做如下分类,禁止使用笼统的“基本兼容”。 + +| 分类 | 定义 | 典型处理 | +| --- | --- | --- | +| 直接复用 | 不改源码或仅改构建声明即可运行 | 纯 Dart 模型、业务规则、通用 Flutter UI | +| 小幅适配 | 局部条件分支、配置或 API 替换后运行 | 平台判断、路径、主题或插件初始化 | +| OHOS 专项实现 | 需要新增 ArkTS 宿主实现或已验证的第三方 OHOS 实现 | App `ohos/entry` bridge、特定系统能力 | +| 替换依赖 | 原依赖不支持 OHOS,需使用功能等价方案 | WebView、存储、设备/媒体 SDK 等 | +| 当前不可行 | 没有可控实现路径或风险不可接受 | 记录最小复现、影响范围和 No-Go 条件 | + +实施后至少填充以下矩阵: + +| 层 / 能力 | 当前实现或依赖 | OHOS 分类 | 改造内容 | 证据 | 风险与责任方 | +| --- | --- | --- | --- | --- | --- | +| Dart 业务模型与 Use Case | 待填写 | 待填写 | 待填写 | 待填写 | 待填写 | +| Flutter UI、主题、路由、Riverpod | 待填写 | 待填写 | 待填写 | 待填写 | 待填写 | +| 网络、认证、错误处理、存储 | 待填写 | 待填写 | 待填写 | 待填写 | 待填写 | +| WebView / JSBridge | `core_webview` | 待填写 | 待填写 | 待填写 | 待填写 | +| 扫码、相机、媒体、文件 | `native_*` 或实际项目实现 | 待填写 | 待填写 | 待填写 | 真机 Gate | +| 权限、定位、推送、蓝牙 | 实际项目实现 | 待填写 | 待填写 | 待填写 | 真机 Gate | +| 日志、埋点、崩溃上报 | 实际项目实现 | 待填写 | 待填写 | 待填写 | 待填写 | + +### 5.3 代表性业务闭环 + +业务闭环选用真实 App 中已经存在的页面和状态流,而不使用新的 Demo 页面伪造成功结果。建议顺序为: + +`已有登录态或测试登录 → 首页 → 一项需要接口数据、路由跳转和状态管理的业务页面 → loading / data / empty / error 状态` + +| 用例 | 前置条件 | 操作与预期 | 状态 | 证据 | +| --- | --- | --- | --- | --- | +| B-01 启动与会话恢复 | 已配置测试环境 | App 启动后按既有逻辑进入登录或首页 | 待填写 | 待填写 | +| B-02 登录 / 测试会话 | 测试账号或可控会话 | 鉴权成功,凭据和门店上下文按预期处理 | 待填写 | 待填写 | +| B-03 首页与路由 | 已登录 | 首页渲染,进入选定业务页并可返回 | 待填写 | 待填写 | +| B-04 业务数据成功态 | 测试接口可用 | 数据正常加载和展示 | 待填写 | 待填写 | +| B-05 空态与错误态 | 可控响应或测试数据 | 提示、重试和错误映射符合既有约定 | 待填写 | 待填写 | + +### 5.4 WebView 与 JSBridge + +当前架构将 Embedded H5 及 JSBridge 收敛在 `core_webview`,并由 `native_*` 暴露原生能力;POC 必须沿用该边界,不能为了临时跑通而让 H5 直接调用 ArkTS。现有设计请参见 [Embedded H5 容器与 JSBridge](../flutter-app/10-webview-h5.md) 和 [原生能力集成方式](../flutter-app/07-native-integration.md)。 + +POC 自带的 H5 测试页必须可显示每次请求的 `id`、`method`、参数、响应及错误码,并覆盖: + +| 用例 | 预期 | +| --- | --- | +| W-01 页面加载与桥接就绪 | 白名单页面加载后可确认 App Bridge 已就绪 | +| W-02 H5 → App 合法调用 | 参数通过校验,App 调用现有能力并回传与协议一致的结果 | +| W-03 App → H5 回调 | H5 正确收到事件/结果,`id` 可关联请求与回包 | +| W-04 未知方法 / 非法参数 | 返回明确错误,不执行任何原生能力 | +| W-05 非白名单来源 | 拒绝调用并记录安全日志,不泄露内部信息 | +| W-06 原生能力不可用 | 返回标准化 `UNSUPPORTED`、`PERMISSION_DENIED` 或 `HARDWARE_UNAVAILABLE`,不静默返回空值 | + +本节通过只能说明 **App 容器和桥接协议** 可行。F6 真页的页面加载、登录态、文件上传、票据和业务流程仍必须在后续联调中单独验收。 + +### 5.5 OHOS 原生宿主桥接与 ArkTS 验证 + +目标是证明项目有可维护的原生接入路径,而不是在没有真机时伪造扫码成功。 + +1. 在既有 `native_*` 的 Dart facade 内增加 OHOS transport,并在 App 宿主 `ohos/entry` 实现 ArkTS bridge;若基线尚未包含目标能力,可新增仅限 POC 的 `native_capability_probe`,但不能把它伪装成正式扫码实现。 +2. 以一个不依赖相机硬件的探针方法验证完整通道:Dart facade 发起调用、`EntryAbility` 注册宿主 bridge、ArkTS 接收参数、返回类型化结果、Dart 映射成功与失败。 +3. 以现有 `native_scan` / `native_media` 对外 API 的调用路径验证 facade 分派、宿主 bridge 编译和错误语义;没有硬件时,结果必须标为“待真机”,不得以模拟值代替扫描结果。 +4. 记录手写 ArkTS MethodChannel 的 channel 名、方法名、参数/返回值、错误码和接口漂移防护方案;不要求、也不尝试为 Pigeon 生成或手写 ArkTS wire protocol。 +5. 不向业务 Feature 暴露 `MethodChannel`、ArkTS 或平台判断;业务和 H5 只能依赖 `native_*` 公共 Dart API。 + +| 用例 | 验收标准 | 模拟器结论 | +| --- | --- | --- | +| N-01 宿主 bridge 编译与注册 | OHOS 工程可编译;启动日志证明 `EntryAbility` 已注册 bridge | 可关闭 | +| N-02 Dart → ArkTS → Dart | 参数、返回值及异常可在两端对应 | 可关闭 | +| N-03 不支持/硬件不可用错误 | 返回明确、可追踪的标准错误 | 可关闭 | +| N-04 相机与实体扫码 | 真实打开相机、完成识别、处理拒绝权限 | **必须待真机** | +| N-05 文件/相册与权限 | 真实系统服务、路径、取消与拒绝场景 | **必须待真机** | + +## 6. 验收、回归与决策 + +### 6.1 验收状态定义 + +| 状态 | 使用条件 | +| --- | --- | +| 通过 | 有完整命令、日志和可观察证据,达到预期结果 | +| 部分通过 | 主链路可行,但存在明确限制、人工步骤或未关闭风险 | +| 失败 | 当前版本或实现无法达到验收标准,附最小复现和阻塞原因 | +| 待真机 | 模拟器不能代表真实设备;不记为失败,也不记为通过 | + +### 6.2 Android / iOS 回归 + +- `harmony` 分支的共享 Dart 改动必须继续通过现有静态检查、单元测试、Widget 测试及既有集成测试。 +- 若 App 当前已有 Android/iOS CI,记录实施前和实施后的流水线链接或关键输出;若尚无 CI,至少记录本地执行的等价命令与结果。 +- 新增 OHOS 条件分支必须覆盖 Android、iOS、OHOS 和未知平台的行为,尤其是不支持能力的显式异常路径。 + +### 6.3 最终判定 + +| 判定 | 条件 | 后续动作 | +| --- | --- | --- | +| Conditional Go | SDK 匹配、构建运行、代表性业务、JSBridge、Dart/ArkTS 桥接均通过或有可控适配;硬件能力保留真机 Gate | 进入真机专项验证和正式适配估算 | +| No-Go | 当前基线没有兼容 SDK,或核心业务/桥接/原生插件有不可接受阻塞且无可控替代 | 停止扩面,给出版本调整或替代技术路线建议 | + +不得使用“模拟器没问题,所以鸿蒙没问题”作为结论。任何 Conditional Go 必须同时给出下列真机关闭条件:相机、实体扫码、运行时权限、文件/相册、WebView 差异、真实 F6、签名安装、性能稳定性和目标机型验证。 + +## 7. 成本与风险登记(实施后填写) + +### 7.1 成本口径 + +成本不只统计首轮代码行数,按以下维度记录: + +- **一次性接入成本:** OHOS 工程、构建环境、依赖替换、ArkTS 插件、测试页和 CI。 +- **业务适配成本:** 共享代码调整、条件分支、UI/渲染差异、接口与存储适配。 +- **原生能力成本:** 每个 `native_*` 的 OHOS 实现、权限、SDK 集成、真实设备测试。 +- **长期维护成本:** Flutter_OH 跟随 Flutter 主线、插件 fork、ArkTS 接口漂移、社区 Issue 跟进、CI 和发布链路。 + +代码复用率只有在统计了确定基线和实际差异后才填写;必须同时给出统计范围,不能用一个无范围的百分比代替兼容矩阵。 + +### 7.2 风险台账 + +| 编号 | 风险 | 当前证据 | 影响 | 缓解措施 | 关闭条件 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | +| R-OH-01 | Flutter_OH 与当前 Flutter/Dart 基线版本不匹配 | 待验证 | 高 | SDK 匹配作为首个硬门禁 | 基线编译、运行、依赖解析通过 | 待验证 | +| R-OH-02 | 社区分支发布滞后或关键问题依赖外部修复 | 待调研 | 高 | 锁定 Commit、跟踪上游、评估 fork 能力 | 有版本升级与问题响应策略 | 待验证 | +| R-OH-03 | Android/iOS plugin 或三方依赖不具备 OHOS 实现 | 待矩阵验证 | 高 | 逐项分类、优先核心插件、明确替代方案 | 核心原生能力真机通过 | 待验证 | +| R-OH-04 | ArkTS 手写 MethodChannel 产生接口漂移 | 已决定不复刻 Pigeon wire protocol | 中 | 固定 channel 契约、契约测试、`native_*` 公共 API 封装 | Dart/ArkTS 契约自动/人工校验通过 | 开放 | +| R-OH-05 | 模拟器结论与真机不一致 | 已知限制 | 高 | 所有硬件项标记待真机 | 目标真机专项验收完成 | 开放 | +| R-OH-06 | F6 WebView 在 OHOS 的内核与行为差异 | 本轮仅验证可控页 | 高 | 后续真实 F6 联调 | F6 核心流程和 JSBridge 通过 | 开放 | + +## 附录 A. POC 证据索引(实施后填写) + +| 编号 | 验证项 | 命令/日志 | 截图/录屏/产物 | 代码 Commit | 状态 | +| --- | --- | --- | --- | --- | --- | +| E-01 | SDK 与环境 | 待填写 | 待填写 | 待填写 | 待填写 | +| E-02 | OHOS 构建与安装 | 待填写 | 待填写 | 待填写 | 待填写 | +| E-03 | 业务闭环 | 待填写 | 待填写 | 待填写 | 待填写 | +| E-04 | WebView / JSBridge | 待填写 | 待填写 | 待填写 | 待填写 | +| E-05 | Dart / ArkTS 原生桥接 | 待填写 | 待填写 | 待填写 | 待填写 | +| E-06 | Android / iOS 回归 | 待填写 | 待填写 | 待填写 | 待填写 | + +## 附录 B. 真机验收 Checklist(下一阶段) + +- [ ] 目标 HarmonyOS / OpenHarmony 真机的签名安装、冷启动、升级与卸载重装。 +- [ ] 相机权限:首次授权、拒绝、永久拒绝后的引导、从设置页恢复。 +- [ ] 二维码/条码扫描、低光、连续扫码、取消、超时与异常恢复。 +- [ ] 车牌/VIN 采集链路及网络异常时的手工降级入口。 +- [ ] 相册、拍照、文件选择、取消、无权限、文件路径、压缩与上传进度。 +- [ ] 定位、蓝牙、通知/推送、后台恢复及弱网场景。 +- [ ] 真实 F6 登录、票据、双向 JSBridge、上传与返回栈。 +- [ ] 多台目标机型上的 UI、WebView、性能、功耗、崩溃和日志脱敏。 +- [ ] 发布签名、包体、合规声明及目标分发渠道的安装验证。 diff --git a/README.md b/README.md index db7dbaf..3d738ce 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Flutter APP 的分包、分层、技术选型等决策记录,按序号阅读 | [04-routing.md](./flutter-app/04-routing.md) | 路由方案(go_router) | | [05-networking.md](./flutter-app/05-networking.md) | 网络层设计(dio) | | [06-local-storage.md](./flutter-app/06-local-storage.md) | 本地存储方案(Drift / secure storage / shared_preferences) | -| [07-native-integration.md](./flutter-app/07-native-integration.md) | 原生能力集成方式(Pigeon) | +| [07-native-integration.md](./flutter-app/07-native-integration.md) | 原生能力集成方式(Android/iOS Pigeon;OHOS 宿主 MethodChannel) | | [08-build-flavors.md](./flutter-app/08-build-flavors.md) | 多环境构建(dev/uat/prod flavor) | | [09-testing.md](./flutter-app/09-testing.md) | 测试策略(单元/Widget/集成测试) | | [10-webview-h5.md](./flutter-app/10-webview-h5.md) | Embedded H5 容器与 JSBridge(PRD 第 7 章核心链路) | @@ -25,7 +25,7 @@ Flutter APP 的分包、分层、技术选型等决策记录,按序号阅读 | [13-observability-analytics.md](./flutter-app/13-observability-analytics.md) | 可观测性与埋点(Bugly 崩溃上报、神策埋点与错误看板、日志脱敏) | | [14-conventions-and-ci-gates.md](./flutter-app/14-conventions-and-ci-gates.md) | 工程规范与 CI 门禁(lint、格式化、分支、流水线卡点) | -首版范围为 **Android / iOS**,鸿蒙 OHOS 不在首版内(但 SDK 基线锁 3.44.9 是为后续 OHOS 适配留窗口,见 01 和 07)。 +首版正式交付范围仍为 **Android / iOS**。`harmony` 分支已用 Flutter_OH 完成 OHOS debug HAP 编译验证,但这不是生产可用结论;运行、Dart/ArkTS 桥接、相机扫码和真机验收仍须按 [07](./flutter-app/07-native-integration.md) 与 POC 的 Gate 完成。 ### Architecture-Diagram/ @@ -107,6 +107,14 @@ V1.1 相对 V1.0 的主要变化:第 4 章拆分到 [`prd/modules/`](./prd/mod | [backend/11-cross-domain-collaboration.md](./backend/11-cross-domain-collaboration.md) | 跨域协作与聚合(契约模块、领域事件、并行 fan-out 与局部降级) | | [backend/12-concurrency-and-scheduling.md](./backend/12-concurrency-and-scheduling.md) | 并发、事务与定时任务(事务边界、幂等、乐观锁、ShedLock、本地缓存) | +### POC/ + +跨平台与工程可行性验证的实施方案、过程证据和最终结论。POC 开始前先冻结范围和验收标准,实施期间持续回写结果: + +| 文档 | 内容 | +| --- | --- | +| [POC/Flutter-OH-POC.md](./POC/Flutter-OH-POC.md) | Flutter_OH(OpenHarmony)适配 POC 的可执行 Runbook 与持续更新型验证报告。已记录 OHOS 工程生成及 debug HAP 构建通过;后续覆盖运行、业务闭环、H5/JSBridge、Dart/ArkTS 宿主桥接、风险台账和真机验收。**本轮无真机,结论最高为 Conditional Go。** | + ### tech-selection/ 技术选型说明材料。**前两份对外**,写给客户方,可直接作为会议材料使用;**第三份是内部讲稿,不外发**: diff --git a/flutter-app/01-project-structure.md b/flutter-app/01-project-structure.md index e64f315..e0c88df 100644 --- a/flutter-app/01-project-structure.md +++ b/flutter-app/01-project-structure.md @@ -30,7 +30,7 @@ conti-app/ feature_analytics/ # 经营分析:对账单、核销收入、返利、报表 feature_profile/ # 个人中心:地址、热线、客服 feature_scan/ # 扫码业务入口(VIN/车牌/二维码/条码 → 分发到对应业务) - native_scan/ # 原生插件包:扫码 + VIN 识别(车牌走云端 OCR,不在这里) + native_scan/ # 原生能力 Dart facade;Android/iOS 是插件,OHOS 实现在 App entry native_media/ # 相机、相册、文件选择/上传 native_device/ # 拨号、设备信息、权限申请 native_crash/ # Bugly 崩溃上报的原生桥(见 13-observability-analytics.md) @@ -43,7 +43,7 @@ conti-app/ - `app` 可以依赖所有 `core_*` 和 `feature_*`。 - `feature_*` **只能**依赖 `core_*` 和 `native_*`,**不能**相互依赖(`feature_purchase` 的 `pubspec.yaml` 里不允许出现 `feature_inventory` 的 path dependency)。 - `core_*` 可以依赖 `native_*`(`core_webview` 的 JSBridge 需要调起扫码/相机/上传)。 -- `native_*` 只依赖 Flutter SDK 和 [Pigeon](https://pub.dev/packages/pigeon) 生成的代码,不依赖任何 `core_*` / `feature_*`——保证原生插件包可以脱离业务单独编译、单独测试(详见 [07-native-integration.md](./07-native-integration.md))。 +- `native_*` 只依赖 Flutter SDK 与自身的跨平台 transport,不依赖任何 `core_*` / `feature_*`。Android/iOS transport 使用 [Pigeon](https://pub.dev/packages/pigeon) 生成代码;OHOS transport 可在 facade 内使用 `MethodChannel`,其 ArkTS 落在 App 宿主 `ohos/entry`,仍不得泄漏给业务层(详见 [07-native-integration.md](./07-native-integration.md))。 `core_*` 之间原则上不互相依赖,允许的例外只有下面三条,多一条都要走评审: @@ -75,16 +75,19 @@ conti-app/ - `core_xxx`:基础设施层,不含具体业务逻辑。 - `feature_xxx`:对应一个业务域(多数是原来的某个小程序,也有全新的,如首页工作台)。 -- `native_xxx`:原生能力插件包,首版含 `android/`、`ios/` 两套原生实现目录(OHOS 不在首版范围,见 [07-native-integration.md](./07-native-integration.md))。 +- `native_xxx`:业务侧唯一可依赖的原生能力 facade。Android/iOS 原生实现位于插件包;`harmony` 分支首期 OHOS ArkTS 实现位于 App 宿主的 `ohos/entry`,见 [07-native-integration.md](./07-native-integration.md)。 ## SDK 版本基线 | 项 | 版本 | 说明 | |---|---|---| | Flutter | **3.44.9** | 用 [FVM](https://fvm.app/) 锁定,仓库根目录提交 `.fvmrc` | -| Dart | 随 Flutter 3.44.9 附带(3.12.x) | 具体号以 `flutter --version` 实测为准;`environment: sdk: ^3.12.0` 对整个 3.12.x 都成立 | +| Dart | 随 Flutter 3.44.9 附带(3.12.x) | Android/iOS 基线具体号以 `flutter --version` 实测为准;包的下限使用 `environment: sdk: ^3.11.0`,以兼容已验证的 OHOS Dart 3.11.5 | +| Flutter_OH(仅 `harmony`) | **3.41.10-ohos-1.0.0 / Dart 3.11.5** | 仅用于 OHOS 构建;由 `enable-ohos.ps1` 临时注入当前 PowerShell PATH,不能替换 Android/iOS 的 FVM SDK | -**为什么不跟最新 stable(3.47.0 / Dart 3.13.0,2026-08-12 发布)**:鸿蒙(OpenHarmony)的 Flutter 分支适配落后于官方 stable 一段时间,虽然 OHOS 不在首版范围(见 [07-native-integration.md](./07-native-integration.md) 的「OHOS 后续演进」),但 SDK 基线要为后续接 OHOS 留出兼容窗口,所以刻意停在 3.44.9 而不是追最新。这条约束在决定升级 Flutter 版本时必须重新评估,不要因为"新版本有新特性"就单方面升。 +**OHOS SDK 边界**:OpenHarmony 的 Flutter 分支与官方 stable 不同步。Android/iOS 仍以 FVM 锁定的 Flutter 3.44.9 为基线;`harmony` 分支已用 Flutter_OH 3.41.10-ohos-1.0.0 / Dart 3.11.5 完成 HAP 编译验证。两套 SDK 不可混用,任一侧升级都必须重新验证依赖解析、生成代码和对应平台构建(见 [07-native-integration.md](./07-native-integration.md))。 + +**未来收敛条件**:当 Flutter_OH 发布并验证可用的 Flutter **3.44.x / Dart 3.12.x** 对齐版本时,可评审将 `harmony` 与 Android/iOS 收敛到同一 SDK 基线。版本号相同不是自动放行条件;必须重新完成依赖解析、Riverpod/Pigeon 生成物核验、HAP 构建及真机原生能力验证后才能切换。 **为什么必须用 FVM 锁**:monorepo 里各人本地 Flutter 版本不一致,会导致同一份代码有人 `flutter analyze` 过、有人不过,生成代码(`build_runner` 产物)也可能不一致——这类问题排查成本远高于装一次 FVM。CI 也用 `.fvmrc` 里的版本,保证本地和流水线一致。 @@ -264,4 +267,3 @@ dart pub global activate melos - [Pigeon | Dart package](https://pub.dev/packages/pigeon) - [Drift | Dart package](https://pub.dev/packages/drift) - [Lerna(JS 生态对标工具)](https://lerna.js.org/) - diff --git a/flutter-app/07-native-integration.md b/flutter-app/07-native-integration.md index cb29f3f..3cafe46 100644 --- a/flutter-app/07-native-integration.md +++ b/flutter-app/07-native-integration.md @@ -2,13 +2,13 @@ ## 决策 -原生能力(扫码、支付、蓝牙等)统一封装成独立的 `native_*` Dart package(结构见 [01-project-structure.md](./01-project-structure.md)),跨语言接口用 **[Pigeon](https://pub.dev/packages/pigeon)**(`^27.3.0`,2026-08 快照)生成,不手写裸 `MethodChannel`/`invokeMethod` 字符串调用。 +原生能力(扫码、支付、蓝牙等)统一由独立的 `native_*` Dart package 暴露稳定公共 API(结构见 [01-project-structure.md](./01-project-structure.md))。**Android/iOS** 跨语言接口使用 [Pigeon](https://pub.dev/packages/pigeon)(锁定 `26.3.1`)生成;`harmony` 分支的首期 **OHOS** 实现是经过约束的例外:`native_*` 内部通过手写 `MethodChannel` 调用 App 宿主 `app/ohos/entry` 中的 ArkTS,而不是将 OHOS 再包装成独立 Flutter plugin。 ## 依赖 ```yaml dev_dependencies: - pigeon: ^27.3.0 + pigeon: 26.3.1 ``` ## 包结构规则 @@ -32,7 +32,28 @@ native_scan/ Classes/NativeScanPlugin.swift # 手写:插件注册入口 ``` -首版只有 `android/` 和 `ios/`(OHOS 不在首版范围,见文末「OHOS 后续演进」)。 +插件包中的原生目录目前只有 `android/` 和 `ios/`;这不是遗漏。OHOS 的首期 ArkTS 实现位于宿主 App 的 `app/ohos/entry`,见下节。 + +### 平台实现归属:Android/iOS 插件,OHOS 宿主桥接 + +``` +feature_* / core_webview(JSBridge) + ↓ 只依赖公共 Dart API + native_scan + ┌─────────┴──────────┐ + │ │ + Android / iOS OHOS(harmony) + Pigeon + plugin 手写 MethodChannel + Kotlin / Swift ↓ + app/ohos/entry ArkTS +``` + +| 平台 | Dart 到原生 transport | 原生代码归属 | 原因 | +| --- | --- | --- | --- | +| Android / iOS | Pigeon 生成的强类型桩代码 | `packages/native_scan/android`、`ios` | 复用成熟的 Flutter plugin 注册和 Kotlin/Swift 生成链路 | +| OHOS(首期) | `native_scan` 内部的手写 `MethodChannel` | `app/ohos/entry/src/main/ets/` | Pigeon 不生成 ArkTS;不手抄其 `BasicMessageChannel` / 自定义 codec 协议,降低漂移风险 | + +这不会增加 Dart `main` 文件,也不会新增 HAP module。`entry` 是已有 OHOS 应用模块;这里只是在其中增加本 App 的原生能力实现。业务代码和 H5 均不得直接调用 channel、ArkTS 或做 OHOS 平台判断。 ### `pubspec.yaml` 必须声明 plugin platforms @@ -250,24 +271,35 @@ pigeon: - Dart 生成物在根 `analysis_options.yaml` 里排除 lint(`analyzer: exclude: - "**/*.g.dart"`)。 - CI 要有一步"重新生成后 `git diff --exit-code`",防止有人改了 schema 但忘了提交生成物。 -## OHOS 后续演进 +## OHOS 当前实现策略(`harmony`) -鸿蒙(OpenHarmony)**不在首版范围**,但基线决策是为它留了口子的,这里记录清楚,避免后面接的时候重新走一遍弯路。 +OHOS 不是 Android 的另一种 plugin platform。当前 Flutter_OH 工具链没有可直接复用的 Pigeon ArkTS 生成链路;而现有 Pigeon API 在 Dart 侧使用 `BasicMessageChannel`、自定义 codec、类型 tag 和生成的错误/结果 envelope。让 ArkTS 人工复刻该私有 wire protocol,维护成本和接口漂移风险都不值得。 -接 OHOS 需要处理三件事: +因此,OHOS 在 `native_scan` 的**内部**新增一条简洁、独立的 `MethodChannel` transport。它接收和返回仅用于该 transport 的基础 Map/List/标量,再映射回既有的 `ScanOptions`、`ScanResult` 与 `NativeScanException`;Android/iOS Pigeon schema、生成物与注册逻辑不因此改变。 -1. **SDK 分支不同**:OHOS 用的是 OpenHarmony 社区维护的 Flutter 分支,版本落后于官方 stable 一段时间。这正是 [01-project-structure.md](./01-project-structure.md) 里 SDK 基线刻意停在 **3.44.9** 而不追 3.47.0 的原因——基线跑太前,OHOS 分支跟不上就接不进来。 -2. **Pigeon 没有 ArkTS 生成器**:Pigeon 官方只生成 Kotlin/Java、Swift/Objective-C、C++、GObject,**没有 ArkTS/OHOS**。所以 OHOS 侧的 channel 代码只能**手写**,需要人工保证方法名、参数结构与 Pigeon 生成的 Dart 端编解码格式一致——这是一份实打实的额外维护成本,接 OHOS 时要预留出来。 -3. **`native_*` 包要加 `ohos:` 平台声明**,并新增 `ohos/` 目录。 +ArkTS 按职责拆分,避免把业务实现写进默认入口: -在此之前,`native_*` 的公共 API 类里遇到不支持的平台,一律抛明确的 `UnsupportedPlatformException`,不静默返回空值或占位假数据——静默返回会让"这个平台其实没实现"的问题一直藏到用户手里。 +``` +app/ohos/entry/src/main/ets/ + entryability/EntryAbility.ets # 生命周期、Flutter engine 与 bridge 注册 + native_scan/NativeScanChannel.ets # 方法分发、参数/结果序列化、错误映射 + native_scan/OhosScanService.ets # 相机/扫码 API 调用 + native_scan/ScanPermissionService.ets # 相机权限检查与申请 +``` + +`NativeScanChannel` 必须集中维护 channel 名、方法名、参数、成功返回值与错误码;Dart facade 捕获 `PlatformException` 并继续转为 `NativeScanException`。取消、拒绝权限、能力不可用、超时和未知方法必须分别有明确错误码,不能返回空值或伪造扫描结果。 + +**延后抽取独立 OHOS plugin。** 只有出现第二个 OHOS App 的复用需求、扫描实现和契约已稳定、Flutter_OH plugin 注册/模板已成熟并经验证,或 SDK 化收益明确超过维护成本时,才评审将 ArkTS 从 `app/ohos/entry` 抽到 `packages/native_scan/ohos`。在此之前,不添加 `ohos:` plugin 声明或额外 `ohos/` 目录。 + +**SDK 收敛条件。** 当前 Android/iOS 使用 Flutter 3.44.9,OHOS 使用 Flutter_OH 3.41.10-ohos-1.0.0;当 Flutter_OH 出现经验证可用的 Flutter 3.44.x / Dart 3.12.x 对齐版本时,可评审统一基线。升级前必须以该候选 SDK 完成依赖解析、Pigeon 与 Riverpod 生成物核验、`flutter build hap --debug -t lib\\main_dev.dart` 和真机原生能力回归;不能仅因版本号相同就替换工具链。 ## 使用规则 -- `pigeons/xxx_api.dart` 是**唯一手写**的接口定义文件,Dart 端和两端原生的桩代码全部由 `dart run pigeon --input pigeons/xxx_api.dart` 生成,生成产物不手动修改,改需求就改 schema 重新生成。 +- Android/iOS 的 `pigeons/xxx_api.dart` 是**唯一手写**的 Pigeon 接口定义文件;Dart 端及 Kotlin/Swift 桩代码全部由 `dart run pigeon --input pigeons/xxx_api.dart` 生成,生成产物不手动修改。OHOS 不手抄 Pigeon wire protocol,而是维护独立、文档化的 `MethodChannel` 契约。 - Dart 调原生用 `@HostApi()`;原生主动推事件给 Dart(比如扫码结果的持续回调)用 `@FlutterApi()`——不允许为了图省事用 `@HostApi()` 硬凑双向通信。 - **调用方只允许依赖 `native_*` 包 `lib/native_xxx.dart` 导出的公共 API 类**,不允许直接 import `src/generated/` 里的生成代码。调用方包括 `feature_*` 和 `core_webview`(JSBridge)。 +- `native_*` 是平台分派和异常收敛的唯一位置;Feature、`core_webview`、H5 与 Dart entrypoint 均不得直接创建 OHOS `MethodChannel` 或 import ArkTS 对应实现。 - 原生侧异常需要在生成的 host API 实现里捕获并转换成 Pigeon schema 里声明的错误类型,Dart 侧统一映射成 [05-networking.md](./05-networking.md) 里同一套 `AppException` 体系,不让原生异常类型(如 `PlatformException`)直接抛到业务代码里。 - 某一端暂未实现的能力,公共 API 类里对应平台分支抛明确的 `UnsupportedPlatformException`,不允许静默返回空值或占位假数据。