From e0088a5f0873ed95a902a9402683ffdd0dcc155c Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Sun, 13 Sep 2026 15:25:34 +0800 Subject: [PATCH] docs: complete STEP-077 V4 bridge investigation --- ...77_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md | 117 ++++++++++++ ...4_Android_JNI_RN桥接只读调查_Codex任务_v1.md | 170 ++++++++++++++++++ ...77_QBIN2_V4_Android_JNI_RN桥接只读调查_v1.md | 29 +++ 粒子开发记录.md | 6 + 4 files changed, 322 insertions(+) create mode 100644 docs/20_调查/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md create mode 100644 docs/40_任务/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_Codex任务_v1.md create mode 100644 docs/50_Step记录/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_v1.md diff --git a/docs/20_调查/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md b/docs/20_调查/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md new file mode 100644 index 000000000..fd311b8bf --- /dev/null +++ b/docs/20_调查/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md @@ -0,0 +1,117 @@ +# STEP-077 QBIN2 V4 Android / JNI / RN 桥接调查报告 v1 + +状态:完成(只读调查) + +日期:2026-09-13 +基线:`0759a06104e1fb30f036db2efb6ef34ca5859759`(`particle/main` = `origin/particle/main` 于调查开始时) + +## 结论 + +V4 应新增一条与 V3 完全平行的、低频的 `WeatherRuntime` / `MapLibreMap` / `NativeMapView` 通道;不得接到现有 `submitField`、`clearFields`、`setForecastTime`、`setPlaybackState` 或 `setPlaybackSpeed`。这些现有命令分别写入 V3 Host field、`clearHostFields()`、`seekRuntimeTimelineToTimestamp()` 和 `controlRuntimeTimeline()`,会操作 V3 timeline,不能承载 V4 的 `EncodedFieldStore` / `ForecastClock`。 + +推荐 RN 只传绝对本地 `qbinFileUri`(或 `file://` URI)及小型、typed primitive ABI 元数据;Kotlin 有界读取为 Java `byte[]`,JNI 复制为 C++ `std::vector`,再调用 `RasterArraySource::submitEncodedField(...)`。不传 Base64,不由 JS 构造 `number[]` / 大型 `ReadableArray`。V4 Core 独占每个 field 的 T0/T1/MIX 选择;桥接只传 requested time、play/pause 与速度,绝不传 endpoint、mix 或 renderer snapshot。 + +## 实际当前链路 + +```text +FieldRuntime.ts public facade + -> NativeWeatherRuntimeBridge.ts TurboModule Spec (primitive arguments / Promise) + -> WeatherRuntimeBridgeModule.kt + runOnUiQueueThread -> Fabric reactTag + UIManagerHelper(FABRIC).resolveView -> MLRNMapView.mapLibreMap + local file bounded read -> WeatherRuntime + -> MapLibreMap (map-owned WeatherRuntime facade) + -> NativeMapView Java (checkState) -> registered NativeMapView JNI + -> native_map_view.cpp: style.getSource(id), dynamic_cast + -> RasterArraySource V3 Host API OR isolated V4 Host API +``` + +源码事实如下。 + +- `FieldRuntime.submitField` 仍是 V3 public API,封装 `FieldPayloadRefs` 为 validity/scalar/vector 三个 URI;`submitLegacyVectorField` 保留 v1 兼容入口。`NativeWeatherRuntimeBridge.ts` 的 codegen Spec 已刻意使用 primitive 参数,空 string 仅表达 V3 optional plane。 +- Kotlin 对 V3 已验证本地绝对路径或 `file://`、单文件和 aggregate 64 MiB、读中长度变化;再形成 `ByteArray`。它不保存 reactTag、map 或 timeline,而是每次在 UI queue 解析当前 Fabric view。 +- `WeatherRuntime.submitField` 把 V3 bytes 重新 pack 后调用 `submitRasterArraySourceHostFieldV2`;`NativeMapView` 用 `GetArrayRegion` 复制到 C++,然后拆 planes 并调用 `submitHostField`。这是可复用的“file -> Java byte[] -> JNI copy -> vector” seam,而不是可复用的 V4 API。 +- V4 `RasterArraySource` 已有独立 `EncodedFieldStore`、`ForecastClock`、binding intent 和 `submitEncodedField` / `set*Binding` / `setRequestedForecastTime` / `setForecastPlayback*` / `clear*EncodedFields`;注释和 STEP-076 public-path 测试都证明它不写 V3 T0/T1/MIX 或 renderer snapshot。 + +## QBIN 传输形态 + +| 方案 | 当前支持与成本 | 结论 | +| --- | --- | --- | +| A:RN `qbinFileUri`,Kotlin 读取 | 已有 `readLocalPayload` / `resolveLocalFile` 精确先例;仅接受本地文件、1..64 MiB,16 KiB buffer,有 read-time size guard;Java/JNI 仍各有一次受控 copy | 推荐。新增 V4 方法复用读取 helper,但不复用 V3 submit/timeline API。 | +| B:RN `byte[]` / `number[]` | 当前 TurboModule Spec 无 binary array ABI;`ReadableArray` 是现有 color stops 的小对象集合,不适合 QBIN。JS number array 造成 JS/native 转换、对象/number 开销与额外 copy;Base64 更扩大内容且无现有 ABI | 拒绝。不得为了方便绕过 64 MiB file guard。 | +| C:直接复用 Java/JNI `byte[]` seam | Kotlin -> `WeatherRuntime` -> Map -> `NativeMapView` 的 `byte[]` 和 `GetArrayRegion` 已存在,适合作为 A 的下半段 | 复用实现模式;新增命名为 V4-specific JNI 方法,不复用 V3 方法。 | + +64 MiB 是现有 Kotlin `MAX_PAYLOAD_BYTES` 与 Java `MAX_FIELD_PAYLOAD_BYTES` 的边界;V4 要在 Kotlin、Java、JNI 均检查 raw QBIN 长度 `1..64 MiB`,随后 Core Decoder 继续执行其自身 QBIN 全文件/decoded-raw 限制。该限制不授权桥接解析 QBIN。 + +## 推荐 V4 API 与跨层 ABI + +所有 String 以 UTF-8 byte length 做小型上限校验;`reactTag`、generation、dataVersion、time 使用 JS 安全整数检查(当前 bridge 对 timestamp 已采用 finite/nonnegative/integral guard)。枚举使用固定 string;所有 enum numeric 值只在 Kotlin/Java/C++ 边界转换。 + +| RN public / Turbo Spec | Kotlin / Java facade | JNI / Core | 参数形态及责任 | +| --- | --- | --- | --- | +| `submitEncodedField(tag, fieldKey, fieldID, generation, dataVersion, contractJson, qbinFileUri)` | `submitEncodedField(...)` | `submitRasterArraySourceEncodedField(sourceId, fieldKey, fieldID, long generation, long dataVersion, contractJson, byte[] raw)` | URI 为文件;metadata 用 primitive;contractJson 是唯一结构化小协议,Kotlin/Java 各只作长度、空值、range;JNI 解析为 Core structs 并调用 V4 API。 | +| `setColorBinding(tag, fieldKey, semanticID, groupID, expectedValueClass, expectedUnitID)` | 同名 | `setRasterArraySourceEncodedColorBinding(...)` | 完全 primitive;JNI 构造 `ColorBinding`,Core resolver 仍做最终 plane assertion。 | +| `setParticleBinding(tag, mode, fieldKey, firstSemanticID, firstGroupID, secondSemanticID, secondGroupID, expectedUnitID)` | 同名 | `setRasterArraySourceEncodedParticleBinding(...)` | mode-dependent selector 仍占固定 primitive slots;Direction 使用 first selector,second 传 0/0。Kotlin/Java 检查 mode 和 uint16 range,不引入 `ReadableMap`。 | +| `setRequestedForecastTime(tag, timestampMs)` | `setEncodedForecastTime` | `setRasterArraySourceEncodedForecastTime` | 独立 V4 名称,`long`;Core ForecastClock 选择各 field window/mix。 | +| `setForecastPlaybackState(tag, "PLAY"|"PAUSE")` | `setEncodedForecastPlaybackState` | `setRasterArraySourceEncodedForecastPlaybackState` | V4 enum,绝不调用 V3 `controlRasterArraySourceTimeline`。 | +| `setForecastPlaybackSpeed(tag, "HALF"|"NORMAL"|"DOUBLE")` | `setEncodedForecastPlaybackSpeed` | `setRasterArraySourceEncodedForecastPlaybackSpeed` | Kotlin/Java 映射为 0.5/1/2;Core 保留 speed validity。 | +| `clearEncodedField(tag, fieldKey)` / `clearAllEncodedFields(tag)` | 同名 | 同名 V4-only JNI | 不清 V3 Host fields、不改变 V3 cadence/timeline。single-clear 返回 `CLEARED` / `FIELD_NOT_FOUND`;all-clear 返回 accepted command。 | + +`ResolvedFieldProfileContract` 需要 `contractSchemaVersion, profileID, profileVersion, allowAdditionalPlanes, sharedValidityRequired, timeRelation, requiredPlanes[]`,每个 plane 为 `semanticID, valueClass, unitID, groupID, component, requiredFlag`。它是唯一确实需要 array 的稳定数据;当前 TurboModule codegen 对 public object ABI 已有历史约束,故不建议 `ReadableMap/ReadableArray`,也不应将每个平面拆成无边界的 JS 数组。推荐在 RN/Spec 中传受大小限制的 `contractJson`,在 JNI 的单一 parser 转为 C++ contract;Kotlin/Java 不语义解析。这样 Host/SDK 负责已经 resolved 的 profile contract,Native 不知道 provider/profile 业务;Core `FieldProfileValidator` 仍是 structural/semantic 唯一裁决者。 + +这不是让 JSON 承载 QBIN 或 server manifest:`contractJson` 是受 schema 版本约束的小 control-plane ABI。若 RN codegen 后续稳定支持 readonly typed object + typed array,才可在破坏性 ABI 版本中替换;本 Step 不建议 `ReadableMap`,因为它绕过 generated Spec、会把多层 field parsing 复制进 Kotlin。 + +## 兼容与所有权策略 + +- V3 `FieldRuntime.submitField`、`submitLegacyVectorField` 与现有 `FieldSubmitResult` 保留不变;V4 新增 `submitEncodedField` 与新的 `EncodedFieldSubmitResult` union,不能改名覆盖。 +- `WeatherRuntime.setForecastTime`、`setPlaybackState`、`setPlaybackSpeed` 必须不复用:它们当前调用 V3 `seekRasterArraySourceTimelineToTimestamp` / `controlRasterArraySourceTimeline`。V4 用 `setEncoded...` Java/JNI names;RN public 名可按任务书使用 `setRequestedForecastTime` 等,但需明确是 V4 namespace / facade(例如 `EncodedFieldRuntime`),避免误导。 +- `clearFields` 和 `clearEncodedFields` 必须分离。前者还参与 V3 state/cadence/disable 行为并调用 `clearHostFields()`;后者只清 `EncodedFieldStore`,保留 V4 bindings,正如 STEP-076 证明,且不得触及 V3。 +- `setColorBinding` / `setParticleBinding` 不修改 WeatherColor/RasterParticle renderer properties;它们只存 V4 binding intent。实际 renderer 接线不在本 Step 范围。 + +## 错误模型 + +Promise rejection 仅用于桥接前条件、生命周期或无法执行;已进入 Core 的 `RasterArrayEncodedFieldSubmitResult` 必须 resolve 成可区分的 V4 result string,不能折叠为 `UNKNOWN` 或 `NATIVE_REJECTED`。 + +| Core result | 推荐 RN resolved result | +| --- | --- | +| `AcceptedInserted` | `ACCEPTED_INSERTED` | +| `AcceptedReplacedRevision` | `ACCEPTED_REPLACED_REVISION` | +| `Duplicate` | `DUPLICATE` | +| `RejectedDecode` | `REJECTED_DECODE` | +| `RejectedContract` | `REJECTED_CONTRACT` | +| `RejectedInvalidFieldKey` | `REJECTED_INVALID_FIELD_KEY` | +| `RejectedIdentityConflict` | `REJECTED_IDENTITY_CONFLICT` | +| `RejectedStaleRevision` | `REJECTED_STALE_REVISION` | +| `RejectedIncompatible` | `REJECTED_INCOMPATIBLE` | +| `RejectedCapacity` | `REJECTED_CAPACITY` | + +桥接层 rejection code 应为:`INVALID_ARGUMENT`(tag、enum、整数、UTF-8/control size)、`PAYLOAD_FILE_UNREADABLE`(空/越限/非本地/不可读/读中变更)、`MAP_VIEW_NOT_FOUND`、`MAP_NOT_READY`、`STYLE_NOT_READY`、`WEATHER_OBJECTS_NOT_READY`、`RUNTIME_DISPOSED`,以及 V4 source 获取失败时的 `SOURCE_MISSING`。JNI 在 Source 不存在或类型不符时不得伪装为 Core `RejectedDecode`;应返回明确 native bridge status,再由 Java 映射为 `SOURCE_MISSING`。style 已存在但 source 尚未 ready 与 runtime disposed 同样不能混成 submit result。 + +## 生命周期与线程 + +`WeatherRuntime` 被 `MapLibreMap` 私有拥有,且是 style-scoped;`replaceWeatherRuntime` 先 dispose,`setStyle` 也 dispose,Kotlin 的 MapView detach listener 调用 `map.disposeWeatherRuntime()`。每个 bridge call 在 `runOnUiQueueThread` 通过 Fabric `reactTag -> UIManagerHelper -> MLRNMapView -> mapLibreMap` 当场解析;不允许新增 map registry、缓存 tag、长期保存 `MapLibreMap*` 或 native source pointer。 + +未来 V4 command 应沿用 `withRuntime`,在 Android UI 主线程上从当前 style 查 source。`NativeMapView.checkState` 是 Java 层 native lifetime guard;C++ 必须每次 `style.getSource(sourceId)` 和 `dynamic_cast`,不可缓存指针。style reload/detach/dispose 后,后续命令得到上述 lifecycle error;旧 V4 state 随 Source/style 销毁失效,Host 要在重新 attach、style ready 后按自己的缓存重新提交 raw QBIN 与 binding intent。 + +## 可用验证与后续验收 + +本调查没有执行 Android 编译、APK、ADB 或实体机操作。当前 Linux 可用入口与边界: + +| 层 | 后续可验证项 | 边界 | +| --- | --- | --- | +| TS | `npx tsc -p packages/maplibre-particle-rn/tsconfig.json --noEmit`;Test Host `npm run typecheck` | package 未定义独立 typecheck script;依赖由 Test Host node_modules/paths 提供。 | +| TurboModule | RN codegen 由 package `codegenConfig`(`WeatherRuntimeBridgeSpec`、`src`、Kotlin package)与 Android Gradle/RN integration 驱动 | 没有发现完全脱离 Gradle 的仓库级 codegen 命令;实现 Step 应记录实际 generation task。 | +| C++/JNI | 头文件/`native_map_view.cpp` 的精确 compile 与 Linux Core unit tests;JNI registration list 与 Java native declarations 静态一一审计 | 精确 Android ABI/JNI compile 仍需 Android NDK Gradle/native build;Linux Core build 不证明 Android linkage。 | +| Java/Kotlin | `WeatherRuntimeStateTest` 是 Mockito/JVM facade 状态测试,可新增 V4 mapping/隔离测试 | 它依赖 Android Gradle test classpath;未发现无需 Gradle 的现成 Kotlin/Java standalone validation。 | + +建议实施拆分: + +1. 先冻结 RN Spec/types 与 Kotlin file/control validation,新增 V4 result union,并以 typecheck + codegen 审计验收。 +2. 再新增 Java `WeatherRuntime` V4-only facade、`MapLibreMap` / `NativeMap` / `NativeMapView` Java declarations、C++ JNI registration 与 source lookup;JVM Mockito 覆盖 V3/V4 time-clear 不串线和 error mapping。 +3. 最后才接 renderer consumer(独立 Step),以 C++ Source tests 证明 V4 projection、style reload/detach rejection、JNI exact build、Android Debug OpenGL/Vulkan 与离线 fixture 验收。不得下载真实 QBIN。 + +## 实施文件清单与风险 + +预期修改:`packages/maplibre-particle-rn/src/{types.ts,NativeWeatherRuntimeBridge.ts,FieldRuntime.ts}`、`WeatherRuntimeBridgeModule.kt`、`WeatherRuntime.java`、`MapLibreMap.java`、`NativeMap.java`、`NativeMapView.java`、`native_map_view.hpp/.cpp`,以及相应 JVM/C++ tests。不会改 package version、Test Host、Renderer/GPU。 + +主要风险为 codegen 对 complex object/array 的限制、64 MiB 下 Kotlin/Java/JNI 三份瞬时内存、JS number 精度(所有 uint64 必须限制在 safe integer 或改 decimal string ABI)、source/style 生命周期竞争、以及错接旧 V3 timeline。前四项通过 primitive+small-contract JSON、固定 64 MiB guards、UI queue late lookup 和 typed result 处理;最后一项通过 V4-only 方法命名、独立 NativeMap API 和隔离测试消除。 diff --git a/docs/40_任务/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_Codex任务_v1.md b/docs/40_任务/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_Codex任务_v1.md new file mode 100644 index 000000000..aabcc88e1 --- /dev/null +++ b/docs/40_任务/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_Codex任务_v1.md @@ -0,0 +1,170 @@ +# STEP-077 — QBIN2 V4 Android / JNI / RN 桥接只读调查 Codex 任务 v1 + +状态:完成 +日期:2026-09-13 + +## 1. 任务性质 + +本任务是只读架构调查,不实现桥接,不修改 production code。 + +当前 `particle/main` / `origin/particle/main` 基线: + +`0759a06104e1fb30f036db2efb6ef34ca5859759` + +STEP-073~076 已完成 V4 Core、Decoder/Ingress、Binding/Projection Identity、`RasterArraySource` C++ Host API。 +## 2. 调查目标 + +回答:V4 的以下能力应如何最小、稳定地穿过现有 Android/JNI/RN 链路: + +```text +submitEncodedField +setColorBinding +setParticleBinding +setRequestedForecastTime +setForecastPlaybackState +setForecastPlaybackSpeed +clearEncodedField / clearAllEncodedFields +``` + +Host 仍不得控制 T0/T1/MIX。 +## 3. 固定架构边界 + +必须保护: + +```text +Test Host / NavSea JS/TS:下载、缓存、重试、gzip 解压、Manifest/Time Index +MapLibreParticle:只从 Host 已准备好的 raw QBIN bytes 开始 +Core:选择 per-field T0/T1/MIX +Renderer:不解析 QBIN,不知道 provider/network/profile 业务 +``` + +真实服务器 QBIN 不在本调查中下载或使用。 +## 4. 必查实际链路 + +必须基于当前真实代码逐层记录: + +```text +packages/maplibre-particle-rn/src/FieldRuntime.ts +packages/maplibre-particle-rn/src/NativeWeatherRuntimeBridge.ts +packages/maplibre-particle-rn/src/types.ts +WeatherRuntimeBridgeModule.kt +WeatherRuntime.java +MapLibreMap.java +NativeMapView.java +native_map_view.hpp / native_map_view.cpp +RasterArraySource V4 Host API +``` + +不得只引用旧 STEP 文档替代源码调查。 +## 5. QBIN 传输形态调查 + +重点比较并给出推荐: + +```text +A. RN 传 qbinFileUri,本地 Android 层读取后交给 Java/JNI +B. RN 直接传 byte[] / number[] +C. 其他现有可复用的本地 binary seam +``` + +必须结合当前 TurboModule/codegen、Kotlin 文件读取、Java byte[]、JNI array copy 与 64 MiB 限制分析。 + +默认倾向不得由 JS 构造大 number array / Base64;但最终结论必须以现有代码和成本为依据。 +## 6. RuntimeMetadata / ProfileContract / Binding ABI 调查 + +分别给出跨层最小 ABI 推荐: + +```text +EncodedFieldRuntimeMetadata +ResolvedFieldProfileContract + requiredPlanes[] +ColorBinding +ParticleBinding +Forecast playback state/speed/time +``` + +比较:typed primitive parameters、primitive arrays、JSON string、ReadableMap/ReadableArray 等可行形态。 + +结论必须说明每一层在哪里解析、在哪里只做边界校验、如何避免 Server/SDK/Host/Native 多处重复业务规则。 +## 7. 兼容性与命名调查 + +必须明确: + +```text +现有 V3 FieldRuntime.submitField 是否保留 +V4 是否新增独立 submitEncodedField,而不是替换旧 submitField +WeatherRuntime 现有 setForecastTime / setPlaybackState / setPlaybackSpeed 是否可复用或必须新增 V4 语义 API +clearFields 与 clearEncodedFields 是否必须分离 +旧 Renderer/V3 timeline 是否可能被 V4 命令误操作 +``` + +不得为了表面统一而让 V4 clear/time/playback 复用会修改 V3 timeline 的旧实现。 +## 8. 生命周期与线程模型 + +必须调查并说明: + +```text +WeatherRuntime 与 MapLibreMap / MapView 的所有权 +Fabric reactTag → MLRNMapView → MapLibreMap 的现有解析路径 +Java 主线程约束 +NativeMapView / Style Source 查找与生命周期 +style reload / map detach / runtime dispose 后 V4 状态如何失效 +``` + +不得引入第二套 Map registry 或长期保存 reactTag/map pointer 的新机制。 +## 9. 错误模型调查 + +必须把 C++ `RasterArrayEncodedFieldSubmitResult` 与 RN 可见结果的推荐映射列全: + +```text +AcceptedInserted +AcceptedReplacedRevision +Duplicate +RejectedDecode +RejectedContract +RejectedInvalidFieldKey +RejectedIdentityConflict +RejectedStaleRevision +RejectedIncompatible +RejectedCapacity +``` + +同时说明文件不可读、参数非法、runtime disposed、source missing/style not ready 等桥接层错误与 Core submit result 如何分层,不得混成一个 UNKNOWN。 +## 10. 验证能力调查 + +不执行 Android 编译、APK、ADB 或实体机操作。 + +调查当前可在 Linux 完成的静态验证入口,包括: + +```text +TurboModule codegen schema +TypeScript typecheck +JNI C++ 精确编译或 Linux 可编译部分 +Java/Kotlin 是否有无需 Android Gradle 的现成静态验证入口 +现有 WeatherRuntime JVM tests 的边界 +``` + +给出后续实现 Step 的分层验收清单,不在本任务实际执行大规模 build。 +## 11. 输出文档 + +必须生成: + +```text +docs/20_调查/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查报告_v1.md +docs/报告/STEP-077_QBIN2_V4_Android_JNI_RN桥接调查_Codex完成报告_v1.md +``` + +并追加 `粒子开发记录.md`。 + +调查报告必须包含当前链路图、推荐 V4 API 表、每层参数形态、错误映射、生命周期、兼容策略、实施文件清单、风险与后续实现拆分建议。 +## 12. 禁止项 + +不得修改 production code、不得新增桥接 API、不得修改 package version、不得修改 Test Host、不得进入真实 QBIN 联调、不得修改 Renderer/GPU。 + +任务开始前已有 dirty/untracked 内容必须保持原样,不得清理、覆盖、暂存或提交。 + +## 13. Git 收尾 + +本任务会生成调查文档,因此完成后只提交本任务新增/修改的文档,commit 后 push `origin/particle/main`。 + +完成报告必须记录 commit hash、commit message、push result、remote branch、Final HEAD;push 失败不得声称任务完成。 + +完成后立即停止,不进入 STEP-077 实现。 diff --git a/docs/50_Step记录/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_v1.md b/docs/50_Step记录/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_v1.md new file mode 100644 index 000000000..36f064c8d --- /dev/null +++ b/docs/50_Step记录/STEP-077_QBIN2_V4_Android_JNI_RN桥接只读调查_v1.md @@ -0,0 +1,29 @@ +# STEP-077 QBIN2 V4 Android / JNI / RN 桥接只读调查 v1 + +状态:完成 + +日期:2026-09-13 + +## 目标与结果 + +- [x] 基于实际 RN、Kotlin、Java、JNI、`RasterArraySource` 源码完成 V4 桥接调查。 +- [x] 给出 file URI 传输、small control-plane ABI、V3/V4 timeline/clear 隔离、结果和 lifecycle 映射建议。 +- [x] 生成调查报告、完成报告并追加开发记录。 + +## 范围 + +只读调查;未修改 production code、package version、Test Host、Renderer/GPU,未下载真实 QBIN,未执行 Android 编译、APK、ADB 或实体机操作。 + +## 核心结论 + +V4 必须新增独立 `submitEncodedField` / binding / forecast / clear 命名空间。V3 `submitField`、`clearFields`、forecast/playback API 当前会进入 V3 Host field / timeline,不能复用。RN 传 `qbinFileUri`,Kotlin 以现有 64 MiB local-file guard 读取,再走 Java `byte[]` 和 JNI copy;不要使用 JS number array 或 Base64。 + +## 验证 + +- [x] 对要求的全部实际源码路径、JNI registration、Core public V4 API、package codegen/typecheck config 和 `WeatherRuntimeStateTest` 做静态审计。 +- [x] `git diff --check`(仅本任务文档)将在提交前执行。 +- [ ] Android/Gradle/APK/ADB/实体机:任务明确不执行。 + +## 阻塞与下一步 + +无调查阻塞。后续只能按报告中拆分实现 Step,先做 Spec/ABI 与 V4-only facade/JNI 隔离测试;本 Step 到此停止。 diff --git a/粒子开发记录.md b/粒子开发记录.md index afa1cb532..d0af7bc71 100644 --- a/粒子开发记录.md +++ b/粒子开发记录.md @@ -766,3 +766,9 @@ Android V3-08 单次综合验收已完成并关闭。Native `13.4.1-particle.2` - V4 public-path reject 现在逐项证明 `RejectedDecode`、`RejectedContract`、`RejectedInvalidFieldKey`、`RejectedStaleRevision` 不改变既有可 resolve projection 的 content identity、T0/T1 coordinate、selected U/V plane 与 validity storage identity;未读取 Store 私有状态。 - clear 测试先用公开 `submitInitialRuntimeFieldWindow(...)` 建立 V3 `field/nextField`,对 `clearEncodedField`、`clearAllEncodedFields` 和 V4 re-submit 全程核验 V3 identity/generation/validTime 不变;V4 清空后 fail-closed,binding intent 仍可重解。 - Linux runner 真实重建 PASS;Source V4 4/4、Binding 6/6、Runtime/Profile 11/11、QBIN/Ingress 24/24、Source regression 11/11,全部 0 failure,`git diff --check` PASS。未执行 Android 编译/Gradle/APK/ADB/Jest/iOS-Metal;STEP-062 dirty 与历史 untracked/build 输出未纳入 scoped commit。 + +### 2026-09-13 STEP-077 QBIN2 V4 Android / JNI / RN 桥接只读调查 + +- 已按实际 RN TurboModule、Kotlin、WeatherRuntime、MapLibreMap、NativeMapView JNI 与 RasterArraySource V4 API 完成只读调查;未修改 production code、Test Host、Renderer/GPU,也未下载真实 QBIN 或运行 Android 构建。 +- 结论:V4 必须是独立 encoded-field API。现有 V3 `submitField`、`clearFields`、`setForecastTime`、playback 会操作 V3 Host field/timeline,绝不能复用。RN 应传本地 QBIN URI,Kotlin 使用既有 64 MiB guarded read,Java `byte[]` / JNI copy 是可复用的 binary seam;禁止 JS number[]/Base64。 +- 建议 V4 结果逐项映射 Core `RasterArrayEncodedFieldSubmitResult`,桥接层 file/lifecycle/style/source 错误用独立 rejection code;每次 command 都沿用 Fabric tag -> current MLRNMapView -> MapLibreMap 的 UI queue late lookup,不建立第二 registry 或缓存 native pointer。