# MapLibreParticleRNTestHost 这是 MapLibreParticleLab 内的独立 React Native 开发宿主,不是 NavSea 业务应用。它只有一个 `MLRNMapView` 与 WeatherRuntime 控制页,用于证明低频控制面:React 的 `reactTag` 经薄 Android 模块定位该 View,再定位该 View 的 `MapLibreMap` 与 map-owned `WeatherRuntime`。 ## 当前 V3-08 版本与首次 prebuild 边界 - 当前验收目标是 RN/TS `13.4.1-particle.3` 配合 Native `cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.2`。`.2` 是 STEP-069 v2 multi-plane 新 artifact;不得复用或覆盖 `.1`。 - 本地 legacy `@maplibre-particle/weather-runtime-bridge` 已移除;`@navsea/maplibre-particle-rn@13.4.1-particle.3` 是唯一的 `WeatherRuntimeBridge` 提供者。 - 必须先由用户手工构建并 Maven Local publish Native `.2`,再对 Test Host 执行 clean prebuild、build、install 与启动。当前仅完成坐标准备,AAR 尚未构建、发布或验收。 - Metro 当前 binary asset extension 为 `.f32` 与 `.u8`。 - package manager 为 npm(`packageManager: npm@10.9.4`),锁文件为 `package-lock.json`;当前环境的 `npm ci --dry-run --ignore-scripts` 无须 `--legacy-peer-deps` 即可解析。 - package 明确固定 React Native `0.85.2`、React `19.2.3`、Expo `56.0.4`、`expo-file-system` `56.0.11`、TypeScript `5.9.3`、MLRN `11.3.6`;`app.json` 明确请求 New Architecture。Hermes 的最终启用状态必须在首次 Android prebuild 后检查生成工程。 - AGP `8.5.0`、Gradle `8.14.3`、Kotlin `2.1.20`、NDK `27.1.12297006`、JDK 17、minSdk 24、compile/targetSdk 36 是本 Test Host 的**人工验收配置目标**,不是尚未生成 Android 工程的已验证结果。首次 prebuild 后必须以实际 Gradle wrapper、AGP/Kotlin plugin、SDK/NDK 与 Hermes/New Architecture 配置为准核对。 ## 历史:STEP-061/062 Custom SDK 来源(手工执行) Gate C 封存环境负责生成 custom AAR;Test Host 只负责 Maven Local handoff。Expo plugin 对唯一 custom 坐标 `org.maplibre.gl:android-sdk-opengl` 排除 Maven Central,而将 Maven Local 排在首位。因此未先发布本仓库 custom SDK 时 dependency resolution 必须失败,不能悄悄使用官方 SDK;MLRN 的独立 turf/annotation/scalebar 依赖不被这个 SDK-only 排除误伤。 ```bash cd /mnt/sda1/MapLibreParticleLab/platform/android # 仅当 checkout 已变化,或下方已核对 AAR 的 SHA-256 不一致时才需要: RENDERER=opengl BUILDTYPE=Release make apackage # STEP-061 必须先按当前 checkout 重建,且只能发布新的 `13.4.1-step061` 坐标: ./gradlew :MapLibreAndroid:publishOpenglreleasePublicationToMavenLocal --console=plain cd /mnt/sda1/MapLibreParticleLab/integration/react-native/MapLibreParticleRNTestHost npm ci npx expo prebuild --platform android --clean npx expo run:android ``` 上述 Android 命令必须在 Gate C 封存 Linux 环境由用户手工执行;本 Step 的 Codex 没有执行。STEP-060C 的 Maven Local publication 已于 2026-09-07 人工通过:`signOpenglreleasePublication SKIPPED`,没有 `no configured signatory`,发布 AAR、POM、module metadata 均存在,且没有 `.asc`。当前 Gate C build output 与 Maven Local AAR 的共同 SHA-256 是 `2e73e25cfd31bb181f75ba2d84974afb949640f72de46bc0234d4579abe3ba38`,含 `WeatherRuntime`/`MapLibreMap` classes 和四 ABI。`47646fb…` 只是 publication 前中间 AAR SHA,不再是当前 artifact。后续只有 checkout 或 AAR 变化时,才重新 build/publish 并核对 provenance;不得以 `-x sign` 绕过签名,Maven Central 正式 publication 仍要求签名。2026-08-29 的旧 AAR(SHA-256 `5c67…f85e5c`)只可作 Gate C 历史证据,不能用于 STEP-060。 ## Bridge 与生命周期 `WeatherRuntimeBridge` 每个命令通过 `UIManagerHelper.getUIManager(...FABRIC).resolveView(reactTag)` 解析 View,并只接受 `MLRNMapView`。它直接读取公开的 `MLRNMapView.mapLibreMap`,不复制 MLRN 的私有 `mViews`,不保存 current map,也没有第二套 timeline/playback state。`MapLibreMap` 持有每个 map 的唯一 `WeatherRuntime`:style replacement、View detach 和 React unmount 都会 dispose 旧 facade;style ready 后 `attach` 创建新的 facade。 Style JSON 明确创建 background、host-field `RasterArraySource`、`WeatherColorLayer` 与 `RasterParticleLayer`。Bridge 仅在 source/layers 都存在且 style 已加载时 attach;它不会创建私有 Style registry。错误为结构化 reject:`MAP_VIEW_NOT_FOUND`、`MAP_NOT_READY`、`STYLE_NOT_READY`、`WEATHER_OBJECTS_NOT_READY`、`RUNTIME_DISPOSED`、`INVALID_ARGUMENT` 或 Native `REJECTED`。 ## Phase A / B 操作 页面 style ready 后显示 reactTag/runtime;Phase A 按钮为 `getState`、enable、WeatherColor visible、particle visible、FPS 30。Phase B 还通过 bridge 暴露 epoch-ms forecast seek、PLAY/PAUSE、速度、stops、独立 particle/trail RGBA、粒子视觉参数和 WeatherColor opacity。JS 只校验小参数,并不保存另一套 runtime 状态;snapshot 来自 Native。 ## STEP-061 Binary U/V Field transport 正式 Binary ingress 为 `metadataJson + payloadFileUri/path`。Test Host 使用 Expo FileSystem `File.write(Uint8Array)` 将 raw bytes 写入 app cache;TurboModule 只接收 metadata 和本地 `file://` URI(也接受绝对本地路径),Kotlin 对可读性与 64 MiB 上限 fail-closed 后读取原始 `byte[]`,并且只调用既有 `WeatherRuntime.submitWindField(metadataJson, byte[])`。没有 `number[]`/`Array`、payload JSON、base64、hex 或网络下载层。 `Submit binary WIND T0/T1` 固定生产 4×3 的两帧 `WIND/GLOBAL` canonical field:north-west origin、row-major、`interleaved-uv`、`float32-le`,并以 `DataView.setFloat32(..., true)` 显式写入 U=eastward、V=northward。初始状态与每轮开始均为 `PENDING`,绝不预先显示 READY。按钮先通过既有 `clearWindFields()` 清空 Source-owned Timeline,再依序提交一个声明字节数与文件实际字节数不一致的 invalid probe、T0、T1,并严格断言 Core 结果依次为 `REJECTED_ADAPTER`、`ACCEPTED_PENDING_INITIAL_WINDOW`、`INITIAL_WINDOW_READY`,最后 Native `WeatherRuntime.state` 必须为 `READY`;任意不符均显示 `ERROR`。 界面严格区分 `Core evidence: INITIAL_WINDOW_READY + runtime READY` 与 producer 已提交的 T0/T1 generation/time identity;后者不是 Native/Core runtime window。MIX 明确为 `Core-owned / not exposed`。Android 最终 T0/T1 真值由既有 logcat `HOST_FIELD_SNAPSHOT_READY` 与 `HOST_FIELD_INITIAL_WINDOW_READY` 验证,本 Step 不新增 Core getter。 启动入口是 `App.tsx`。`app.json` 已固定 `orientation: landscape`;下一次 Android prebuild/build 应生成 `MainActivity android:screenOrientation="landscape"`。Android build、安装及设备操作必须由用户手工执行,详见 `docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md`。 ## STEP-062 真实 WeatherV2 综合地图 Test Host 固定消费已验收的 `org.maplibre.gl:android-sdk-opengl:13.4.1-step061`,本阶段不构建或发布 AAR。页面 style 顺序是 `background → GSI raster → WeatherColorLayer → RasterParticleLayer`;GSI 使用国土地理院标准地图 `https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png`(256、maxzoom 18、含 attribution),相机初始聚焦日本及周边 WeatherV2 bounds。 受控 assets `assets/weather/ecmwf-hres-wind-20260807/` 原样复制 Android Validation 的 `dataset.json` 与四个 `metadata.json`/`field.f32`。`expo-asset` 是明确直接依赖,`metro.config.js` 当前增加 `.f32` 与 `.u8` binary asset extension。点击 `LOAD REAL WEATHER T0-T3` 会先 clear,然后通过 `Asset.fromModule(...).downloadAsync()` 取得四个 Expo cache `file://` URI,按 producer validTime 提交;JS 只传小型 metadata JSON 和文件引用,不 materialize 3.01 MiB payload 为数组、JSON、base64 或 hex。 硬断言依次为 T0=`ACCEPTED_PENDING_INITIAL_WINDOW`、T1=`INITIAL_WINDOW_READY`、T2/T3=`ACCEPTED_NEXT_SNAPSHOT`,并在最后要求 Native state=`READY`;任何偏差均显示 `ERROR`。界面提供 PLAY/PAUSE、HALF/NORMAL/DOUBLE、四个 epoch-ms forecast seek、AUTO/30/60 FPS、两层可见性、冻结 WeatherColor stops、独立 particle/trail 色彩,以及粒子/轨迹视觉参数。Expo/系统管理 asset cache;本页不自建 `.f32` 临时文件。 ## Windows 安装与 Metro reverse Test Host 的 Metro 固定在 8091,但 Debug APK 的 RN dev-server 探测仍从设备 `localhost:8081` 发起。手工安装前以受控脚本 `scripts/05-install-and-run.ps1` 保留两条 reverse:`tcp:8091 -> tcp:8091` 与 `tcp:8081 -> tcp:8091`。脚本固定设备 `192.168.1.146`、package `org.maplibre.particle.rntesthost`、activity `.MainActivity`,并在安装前完成 reverse。