fix: query CoreOnly weather layer presence
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
255
docs/40_任务/STEP-060E_CoreOnlyLayer存在性检查修复_Codex任务_v1.md
Normal file
255
docs/40_任务/STEP-060E_CoreOnlyLayer存在性检查修复_Codex任务_v1.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# STEP-060E CoreOnly Layer 存在性检查修复 — Codex任务 v1
|
||||
|
||||
## 1. 任务定位
|
||||
|
||||
当前仍为 **STEP-060**,不得进入 STEP-061。
|
||||
|
||||
本轮修复 STEP-060D 代码审查确认的 Android 根因:
|
||||
|
||||
- `raster-particle` 与 `weather-color` layer 在 Android `LayerManagerAndroid` 中通过 `addLayerTypeCoreOnly(...)` 注册;
|
||||
- Core 可以正常解析、持有和渲染这些 layer;
|
||||
- 但 CoreOnly layer 没有 Java `Layer` peer;
|
||||
- `Style.getLayer(id)` 最终依赖 `LayerManagerAndroid::createJavaLayerPeer(...)`;
|
||||
- 对 CoreOnly layer,该函数返回 null;
|
||||
- 因此 Bridge 用 `Style.getLayer()` 判断 layer 是否存在,必然产生假阴性。
|
||||
|
||||
这与当前现象一致:原生 Particle validation 成功,但 RN `WeatherRuntimeBridge.attach()` 报 weather layer 缺失。
|
||||
|
||||
本任务只修复这一 Android Java/JNI/Core 存在性检查链,并保持现有 CoreOnly 设计。
|
||||
## 2. 开工基线
|
||||
|
||||
正式仓库:
|
||||
|
||||
`/mnt/sda1/MapLibreParticleLab`
|
||||
|
||||
分支:`particle/main`
|
||||
|
||||
本任务开工目标基线:
|
||||
|
||||
`2d2375cd532468821c6e3c158ee1a275f4522044`
|
||||
|
||||
该提交已包含 Win11 已验证的 RN Test Host 修复:
|
||||
|
||||
- React `19.2.3`
|
||||
- RN 0.85.2 codegen 配置
|
||||
- `NativeWeatherRuntimeBridge.ts` 同文件 type aliases
|
||||
- 保留 Expo/RN repositories 的 Maven Local plugin 逻辑
|
||||
- STEP-060D `13.4.1-step060d` 版本接线
|
||||
|
||||
开工前执行 `git pull --ff-only origin particle/main`,确认基线没有落后。
|
||||
不得回退上述 Win11 已验证修复。
|
||||
## 3. 已确认源码证据
|
||||
|
||||
以下证据已经由 ChatGPT 直接审查当前源码确认,不要用 Codex 完成报告替代:
|
||||
|
||||
1. `platform/android/MapLibreAndroid/src/cpp/style/layers/layer_manager.cpp`
|
||||
- `RasterParticleLayerFactory` 使用 `addLayerTypeCoreOnly(...)`
|
||||
- `WeatherColorLayerFactory` 使用 `addLayerTypeCoreOnly(...)`
|
||||
- `createJavaLayerPeer(...)` 找不到 Java peer factory 时返回 null
|
||||
2. `platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp`
|
||||
- `NativeMapView::getLayer(...)` 取得 Core layer 后调用 `createJavaLayerPeer(...)`
|
||||
- 因而 CoreOnly layer 即使真实存在,Java `Style.getLayer()` 仍可得到 null
|
||||
3. 当前 Bridge `WeatherRuntimeBridgeModule.attach()` 使用 `style.getLayer(...)` 做存在性判断,因此判断机制本身错误。
|
||||
4. STEP-060D 新增 `style.getLayers().map { it.id }` 也不安全:CoreOnly layer 没有 Java peer,不能用 Java Layer peer 枚举作为 Core layer 真值来源。
|
||||
5. `MapLibreMap.getStyle()` 只在 Style fully loaded 时返回非 null,所以本轮不是普通 style-ready 时机修复。
|
||||
|
||||
不得重新把问题归因于 React、MLRN mapStyle JSON 传递、AAR 混用或简单 attach 重试时机。
|
||||
## 4. 必做实现:Core 直接存在性查询
|
||||
|
||||
新增通用、窄范围的 Android MapLibre API,用来查询 **Core Style 真值**,不得依赖 Java Source/Layer peer。
|
||||
|
||||
公开语义固定为:
|
||||
|
||||
- `MapLibreMap.hasStyleSource(String sourceId): boolean`
|
||||
- `MapLibreMap.hasStyleLayer(String layerId): boolean`
|
||||
|
||||
具体落点至少覆盖:
|
||||
|
||||
- `NativeMap.java`
|
||||
- `NativeMapView.java`
|
||||
- `MapLibreMap.java`
|
||||
- `native_map_view.hpp`
|
||||
- `native_map_view.cpp`
|
||||
- JNI method registration
|
||||
|
||||
C++ 最终判断必须直接基于:
|
||||
|
||||
- `map->getStyle().getSource(id) != nullptr`
|
||||
- `map->getStyle().getLayer(id) != nullptr`
|
||||
|
||||
不得通过 `createJavaLayerPeer()`、`Style.getLayer()` 或其他 Java peer 路径间接判断。
|
||||
## 5. Bridge attach 修正
|
||||
|
||||
修改正式:
|
||||
|
||||
`integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/src/main/java/org/maplibre/particle/rntesthost/weather/WeatherRuntimeBridgeModule.kt`
|
||||
|
||||
attach 在取得 fully-loaded `style` 后,改为:
|
||||
|
||||
- source:使用 `map.hasStyleSource(WeatherIds.SOURCE)`
|
||||
- weather color layer:使用 `map.hasStyleLayer(WeatherIds.COLOR_LAYER)`
|
||||
- particle layer:使用 `map.hasStyleLayer(WeatherIds.PARTICLE_LAYER)`
|
||||
|
||||
三个结果继续独立输出。
|
||||
|
||||
必须删除/停止使用以下方式作为存在性真值:
|
||||
|
||||
- `style.getLayer(...)`
|
||||
- `style.getLayers().map { it.id }`
|
||||
- Java Layer peer 数量作为 Core layer 数量
|
||||
|
||||
source 也统一改用 Core 直接查询,不再让 Source/Layer 使用两套存在性语义。
|
||||
## 6. STEP-060D 诊断修正
|
||||
|
||||
保留稳定错误码:
|
||||
|
||||
`WEATHER_OBJECTS_NOT_READY`
|
||||
|
||||
失败信息至少包含:
|
||||
|
||||
- `reactTag`
|
||||
- `mapView=present|missing`
|
||||
- `mapLibreMap=present|missing`
|
||||
- `style=present|missing`
|
||||
- `source[rn-weather-fields]=present|missing`
|
||||
- `layer[rn-weather-color]=present|missing`
|
||||
- `layer[rn-weather-particles]=present|missing`
|
||||
|
||||
另外使用公开 `Style.getUri()` / Kotlin 对应属性输出 `styleUri`;JSON style URI 为空时明确写 `<empty>` 或等价稳定表示。
|
||||
|
||||
不要再调用 `style.getLayers()` 构造诊断列表。
|
||||
如果确实需要 ID 列表,只允许使用直接 Core ID 查询;本任务默认不要求新增列表 API,避免扩大修改面。
|
||||
|
||||
成功路径仍必须保持现有 `replaceWeatherRuntime(...)`、snapshot、listener 和 Phase A/B 控制语义不变。
|
||||
## 7. 明确禁止
|
||||
|
||||
本任务不得:
|
||||
|
||||
- 将 `RasterParticleLayerFactory` 或 `WeatherColorLayerFactory` 从 `addLayerTypeCoreOnly(...)` 改成普通 Java layer registration
|
||||
- 为了让 `Style.getLayer()` 非 null 而新建 WeatherColor/RasterParticle Java peer 类
|
||||
- 改变 CoreOnly layer 的产品边界
|
||||
- 用解析完整 Style JSON 作为正式存在性判断
|
||||
- 增加 attach 定时重试或无限重试
|
||||
- 修改 MLRN mapStyle 传递链来掩盖问题
|
||||
- 修改 WeatherRuntime 控制状态机
|
||||
- 实现 binary U/V field transport
|
||||
- 进入 STEP-061
|
||||
- 在 Win11 临时修改 Native 正式源码
|
||||
- 执行 Win11 APK build/install、ADB 或设备测试
|
||||
|
||||
本轮目标是让 Java/RN Host 能以一个窄 API 查询 Core Style 真值,而不是把 CoreOnly 类型暴露成完整 Android Java Layer API。
|
||||
## 8. Maven / AAR 版本
|
||||
|
||||
本轮必须使用新的临时版本,禁止复用 STEP-060D 内容不同但版本相同的 artifact:
|
||||
|
||||
`org.maplibre.gl:android-sdk-opengl:13.4.1-step060e`
|
||||
|
||||
同步更新至少包括:
|
||||
|
||||
- `platform/android/VERSION`
|
||||
- RN Test Host `modules/weather-runtime-bridge/android/build.gradle`
|
||||
- `plugins/withParticleNativeAndroid.js`
|
||||
|
||||
Codex **不得构建 AAR,也不得执行 Android/Gradle AAR 打包或 Maven Local 发布**。
|
||||
|
||||
Codex 本轮只负责把源码与版本接线准备到可由用户手工构建的状态,并在完成 Linux 静态检查/精确编译后 commit + push。
|
||||
|
||||
用户在 Codex 停止后手工执行 OpenGL Release custom AAR 构建与 Maven Local 发布。用户构建完成后再记录:
|
||||
|
||||
- Maven coordinate
|
||||
- AAR build output 路径
|
||||
- Maven Local AAR 路径
|
||||
- AAR SHA256
|
||||
- 四 ABI 是否存在
|
||||
|
||||
Codex 完成报告中必须明确写:`AAR_BUILD_NOT_EXECUTED_BY_CODEX`,不得把“源码已准备”表述成“AAR 已生成”。
|
||||
|
||||
不得建立新的正式 Maven pipeline;本轮仍为 STEP-060 临时可追溯版本。
|
||||
## 9. Linux 验证要求
|
||||
|
||||
Codex 只执行与本轮源码相关的轻量、精确验证,不执行 AAR 打包。
|
||||
|
||||
至少完成:
|
||||
|
||||
- Android JNI/C++ 相关源码的精确编译或现有等价最小验证;
|
||||
- Android Java/Kotlin 受影响源码的可行精确编译;若因当前生成工程/codegen 缺失无法完成,必须明确记录限制,不得通过扩大修改范围绕过;
|
||||
- 检查新增 JNI 方法声明、实现、注册签名一致;
|
||||
- 检查 `MapLibreMap.hasStyleSource/hasStyleLayer` 最终确实直达 Core Style;
|
||||
- 检查 Bridge 已完全停止用 Java `Style.getLayer()` / `Style.getLayers()` 判断 CoreOnly layer 存在性;
|
||||
- `git diff --check`;
|
||||
- 检查最终 diff,不得混入无关文件。
|
||||
|
||||
编译输出遵循全局 `$build-output-throttle`。
|
||||
|
||||
本任务不执行 Jest,也不得新增 Jest 要求。
|
||||
## 10. 文档要求
|
||||
|
||||
完成后更新 STEP-060E 对应中文 Step 记录与中文 Codex 完成报告。
|
||||
|
||||
同主题已有文档时优先更新或使用递增版本号,不得无意义创建多个不同文件名。
|
||||
|
||||
文档必须明确:
|
||||
|
||||
- 根因为 CoreOnly layer 无 Java peer,导致 Java `Style.getLayer()` 假阴性;
|
||||
- 本轮采用 Core 直接存在性查询,不改变 CoreOnly 架构;
|
||||
- Win11 已验证 RN Test Host 基线来自 `2d2375cd532468821c6e3c158ee1a275f4522044`;
|
||||
- Maven 临时版本已切到 `13.4.1-step060e`;
|
||||
- `AAR_BUILD_NOT_EXECUTED_BY_CODEX`;
|
||||
- Android APK/ADB/设备验证尚未执行;
|
||||
- STEP-060 尚未 CLOSED,未进入 STEP-061。
|
||||
## 11. Git 收尾
|
||||
|
||||
完成规定源码、验证和文档后,只提交本任务相关变更到当前主线 `particle/main`。
|
||||
|
||||
必须:
|
||||
|
||||
- commit 本任务相关源码、版本接线、任务文件及文档;
|
||||
- push 到 `origin/particle/main`;
|
||||
- push 失败时不得声称任务完成;
|
||||
- 不得提交与本任务无关的本地改动。
|
||||
|
||||
完成报告必须记录:
|
||||
|
||||
- source commit SHA;
|
||||
- final HEAD;
|
||||
- commit message;
|
||||
- push 结果;
|
||||
- remote branch;
|
||||
- 预期 Maven coordinate:`org.maplibre.gl:android-sdk-opengl:13.4.1-step060e`;
|
||||
- `AAR_BUILD_NOT_EXECUTED_BY_CODEX`。
|
||||
## 12. 完成报告格式
|
||||
|
||||
结束时按以下必做项逐项报告:`已完成 / 未完成 / 无法验证`,并说明未完成或无法验证原因:
|
||||
|
||||
- Core `hasStyleSource` 查询链;
|
||||
- Core `hasStyleLayer` 查询链;
|
||||
- Bridge attach 改用 Core 真值;
|
||||
- 移除危险的 `style.getLayers()` 诊断枚举;
|
||||
- 增加 `styleUri` 诊断;
|
||||
- 成功路径与 WeatherRuntime 控制语义保持不变;
|
||||
- `13.4.1-step060e` 版本接线;
|
||||
- Linux 精确验证;
|
||||
- 文档更新;
|
||||
- Git commit/push;
|
||||
- AAR 未由 Codex 构建;
|
||||
- 未进入 STEP-061。
|
||||
|
||||
不得用“基本完成”“应该可以”等模糊表述替代状态。
|
||||
## 13. 停止条件与后续人工链路
|
||||
|
||||
Codex 成功 push 后立即停止,不得自行构建 AAR,不得进入 Win11 或 Android 运行验证。
|
||||
|
||||
后续固定人工/ChatGPT 链路:
|
||||
|
||||
1. ChatGPT 审核远端实际代码;
|
||||
2. 用户在 Linux 手工构建 `13.4.1-step060e` OpenGL Release AAR并发布 Maven Local;
|
||||
3. 记录 Linux AAR SHA256;
|
||||
4. Win11 从 Git pull 最新 RN Test Host 源码;
|
||||
5. Win11 通过 SCP 从 `root@192.168.200.184` 拉取 AAR;
|
||||
6. Win11 计算 SHA256,必须与 Linux 完全一致;
|
||||
7. 更新 Win11 Maven Local;
|
||||
8. 执行 Bridge 与 MLRN 两条 `dependencyInsight`,必须共同解析到 `13.4.1-step060e`;
|
||||
9. 用户手工构建 APK;
|
||||
10. 再进行 Android attach/runtime 验证。
|
||||
|
||||
在上述 Android 结果出来前,不得宣布 STEP-060 CLOSED,也不得进入 STEP-061。
|
||||
37
docs/50_Step记录/STEP-060E_CoreOnlyLayer存在性检查修复_v1.md
Normal file
37
docs/50_Step记录/STEP-060E_CoreOnlyLayer存在性检查修复_v1.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# STEP-060E CoreOnly Layer 存在性检查修复
|
||||
|
||||
状态:`IMPLEMENTED / WAITING_CODE_REVIEW`
|
||||
|
||||
## 目标与基线
|
||||
|
||||
在 `particle/main` 的 Win11 已验证 RN Test Host 基线
|
||||
NaN2d2375cd532468821c6e3c158ee1a275f4522044` 上,修正 STEP-060D 的 attach
|
||||
存在性检查假阴性。本轮仍属于 STEP-060,未进入 STEP-061。
|
||||
|
||||
## 根因与修正
|
||||
|
||||
- `raster-particle` 与 `weather-color` 在 Android `LayerManagerAndroid` 中以
|
||||
`addLayerTypeCoreOnly(...)` 注册。Core 可以解析、持有和渲染它们,但不创建 Java
|
||||
`Layer` peer。
|
||||
- 因此 `Style.getLayer(id)` 经 `createJavaLayerPeer(...)` 后会对真实存在的 CoreOnly
|
||||
layer 返回 null;`Style.getLayers()` 也不能作为 Core layer 真值。
|
||||
- 新增窄范围公开 API `MapLibreMap.hasStyleSource(String)` 与
|
||||
`MapLibreMap.hasStyleLayer(String)`,经 `NativeMap`、`NativeMapView`、JNI 到
|
||||
`NativeMapView`,分别直接调用 Core `Style::getSource/getLayer`。
|
||||
- RN `WeatherRuntimeBridge.attach()` 保持 fully-loaded `Style` 前置条件,但三项存在性
|
||||
判断统一改走上述 Core 真值;成功时原有 `replaceWeatherRuntime()`、snapshot 与 detach
|
||||
listener 不变。
|
||||
- `WEATHER_OBJECTS_NOT_READY` 仍给出三个固定对象的独立状态,诊断改为输出
|
||||
`Style.getUri()`(JSON style 为 `<empty>`),不再枚举 Java source/layer peer。
|
||||
|
||||
## 版本与验证边界
|
||||
|
||||
- Maven 临时坐标已同步为
|
||||
`org.maplibre.gl:android-sdk-opengl:13.4.1-step060e`。
|
||||
- `AAR_BUILD_NOT_EXECUTED_BY_CODEX`:本轮不构建 AAR、不发布 Maven Local。
|
||||
- Android APK、ADB、设备/模拟器验证尚未执行;必须在人工构建并发布该新版本 AAR 后进行。
|
||||
|
||||
## 结果
|
||||
|
||||
CoreOnly 架构未改变、未新增 Java weather layer peer、未引入 attach retry,且没有修改
|
||||
WeatherRuntime 状态机、binary field transport 或 STEP-061 范围。
|
||||
44
docs/报告/STEP-060E_CoreOnlyLayer存在性检查修复_Codex完成报告_v1.md
Normal file
44
docs/报告/STEP-060E_CoreOnlyLayer存在性检查修复_Codex完成报告_v1.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# STEP-060E CoreOnly Layer 存在性检查修复 — Codex 完成报告
|
||||
|
||||
## 结论
|
||||
|
||||
状态:IMPLEMENTED / WAITING_CODE_REVIEW。本轮完成 Android Host 到 JNI/Core 的 Style 存在性窄查询,修复 RN bridge 对 CoreOnly weather layer 的假阴性;STEP-060 未 CLOSED,未进入 STEP-061。
|
||||
|
||||
## 实际完成内容
|
||||
|
||||
- 根因:RasterParticleLayer 与 WeatherColorLayer 是 CoreOnly layer,Core 可正常渲染,但 Style.getLayer() 需要 Java peer,故会错误返回 null。
|
||||
- 新增公开 MapLibreMap.hasStyleSource(String)、hasStyleLayer(String);实现穿过 NativeMap/NativeMapView 和 JNI,C++ 直接以 map->getStyle().getSource(id) 与 getLayer(id) 判断。
|
||||
- WeatherRuntimeBridge.attach() 在 style fully loaded 后,使用三个独立 Core 查询检查 rn-weather-fields、rn-weather-color、rn-weather-particles;没有改变 attach 成功路径、replaceWeatherRuntime()、snapshot 或 View detach listener。
|
||||
- WEATHER_OBJECTS_NOT_READY 保留固定错误码和三个独立 present/missing 字段,新增 styleUri(JSON style 为空时 <empty>),移除 style.getLayers()/getSources() 的 Java peer 枚举。
|
||||
- Maven 临时版本同步为 13.4.1-step060e。
|
||||
|
||||
## 修改文件
|
||||
|
||||
- platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/{NativeMap.java,NativeMapView.java,MapLibreMap.java}
|
||||
- platform/android/MapLibreAndroid/src/cpp/{native_map_view.hpp,native_map_view.cpp}
|
||||
- integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/src/main/java/org/maplibre/particle/rntesthost/weather/WeatherRuntimeBridgeModule.kt
|
||||
- platform/android/VERSION、bridge android/build.gradle、plugins/withParticleNativeAndroid.js、Test Host README、本 Step 记录、本文档及 粒子开发记录.md。
|
||||
|
||||
## 验证
|
||||
|
||||
- ./gradlew :MapLibreAndroid:tasks --all --console=plain:PASS。
|
||||
- ./gradlew :MapLibreAndroid:compileOpenglReleaseJavaWithJavac --console=plain:PASS。
|
||||
- ./gradlew :MapLibreAndroid:externalNativeBuildOpenglRelease --console=plain:PASS(x86_64 等价精确 CMake/Ninja target);该任务仅编译 JNI/OpenGL 原生目标,不打包 AAR。
|
||||
- 静态检查:JNI Java 声明、C++ 声明/实现/注册名称一致;Bridge 不再调用 Style.getLayer()、Style.getLayers()、Style.getSource() 或 Style.getSources() 作为 weather object 真值。
|
||||
- git diff --check:PASS。
|
||||
|
||||
所有可能产生大量输出的 Gradle 编译均通过 build-output-throttle 执行;未执行 Jest。
|
||||
|
||||
## 未执行与风险
|
||||
|
||||
- AAR_BUILD_NOT_EXECUTED_BY_CODEX。
|
||||
- 未执行 Maven Local publication、Android APK build/install、ADB、设备或模拟器验证。
|
||||
- 本地 Expo 生成工程先前缺少 NativeWeatherRuntimeBridgeSpec;未为本轮新增大型 codegen 或 mocking 方案。后续人工构建新 AAR 并在 Win11 更新 Maven Local 后,仍需执行两条 dependencyInsight、APK build 与 attach/runtime 人工验收。
|
||||
- 运行期新 JNI 方法的真值行为需要上述 Android 人工验收;本轮未改变 CoreOnly 注册或 WeatherRuntime 控制状态机。
|
||||
|
||||
## Git
|
||||
|
||||
- source baseline:2d2375cd532468821c6e3c158ee1a275f4522044
|
||||
- 功能 commit / Final HEAD / push 结果:将在本次受限验证、提交并推送后回填。
|
||||
- remote branch:origin/particle/main
|
||||
- 预期 Maven 坐标:org.maplibre.gl:android-sdk-opengl:13.4.1-step060e
|
||||
@@ -7,7 +7,7 @@
|
||||
- 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`、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 配置为准核对。
|
||||
- MLRN 的 root Gradle extras 固定 `org.maplibre.reactnative.nativeVersion=13.4.1-step060d` 与 `nativeVariant=opengl`;这是 STEP-060D attach 诊断 AAR 的唯一临时版本,避免与先前 `13.4.1` Maven Local artifact 缓存混淆。
|
||||
- MLRN 的 root Gradle extras 固定 `org.maplibre.reactnative.nativeVersion=13.4.1-step060e` 与 `nativeVariant=opengl`;这是 STEP-060E CoreOnly layer 存在性检查修复 的唯一临时版本,避免与先前 `13.4.1` Maven Local artifact 缓存混淆。
|
||||
|
||||
## Custom SDK 来源(手工执行)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ android {
|
||||
dependencies {
|
||||
implementation "com.facebook.react:react-android"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.20"
|
||||
implementation "org.maplibre.gl:android-sdk-opengl:13.4.1-step060d"
|
||||
implementation "org.maplibre.gl:android-sdk-opengl:13.4.1-step060e"
|
||||
compileOnly project(":maplibre_maplibre-react-native")
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
|
||||
@ReactMethod
|
||||
override fun attach(reactTag: Double, promise: Promise) = withMapView(reactTag, promise) { view, map ->
|
||||
val style = map.style ?: return@withMapView reject(promise, "STYLE_NOT_READY", "The MapLibre style is not loaded")
|
||||
val sourceExists = style.getSource(WeatherIds.SOURCE) != null
|
||||
val weatherColorLayerExists = style.getLayer(WeatherIds.COLOR_LAYER) != null
|
||||
val particleLayerExists = style.getLayer(WeatherIds.PARTICLE_LAYER) != null
|
||||
val sourceExists = map.hasStyleSource(WeatherIds.SOURCE)
|
||||
val weatherColorLayerExists = map.hasStyleLayer(WeatherIds.COLOR_LAYER)
|
||||
val particleLayerExists = map.hasStyleLayer(WeatherIds.PARTICLE_LAYER)
|
||||
if (!sourceExists || !weatherColorLayerExists || !particleLayerExists) {
|
||||
return@withMapView reject(
|
||||
promise,
|
||||
@@ -142,9 +142,9 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep the attach rejection searchable and bounded: MLRN lifecycle investigation needs the
|
||||
* exact absent weather object plus enough final-style context, but never an unbounded dump.
|
||||
* This executes on the UI queue together with the Style lookup above.
|
||||
* Core-only layer types do not have a Java Layer peer. Presence is checked directly in Core
|
||||
* before this diagnostic is built; the style URI distinguishes a JSON style (empty URI) from
|
||||
* a URI-backed style without materialising all sources or layers.
|
||||
*/
|
||||
private fun weatherObjectsNotReadyDiagnostic(
|
||||
reactTag: Int,
|
||||
@@ -153,47 +153,28 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
|
||||
weatherColorLayerExists: Boolean,
|
||||
particleLayerExists: Boolean,
|
||||
): String {
|
||||
val sourceIds = style.getSources().map { it.id }
|
||||
val layerIds = style.getLayers().map { it.id }
|
||||
return buildString {
|
||||
append("WEATHER_OBJECTS_NOT_READY reactTag=").append(reactTag)
|
||||
append(" mapView=present mapLibreMap=present style=present")
|
||||
append(" styleUri=").append(style.getUri().ifEmpty { "<empty>" })
|
||||
append(" source[").append(WeatherIds.SOURCE).append("]=")
|
||||
.append(presence(sourceExists))
|
||||
append(" layer[").append(WeatherIds.COLOR_LAYER).append("]=")
|
||||
.append(presence(weatherColorLayerExists))
|
||||
append(" layer[").append(WeatherIds.PARTICLE_LAYER).append("]=")
|
||||
.append(presence(particleLayerExists))
|
||||
append(" styleSourceCount=").append(sourceIds.size)
|
||||
append(" styleLayerCount=").append(layerIds.size)
|
||||
append(" styleSourceIds=").append(boundedIds(sourceIds))
|
||||
append(" styleLayerIds=").append(boundedIds(layerIds))
|
||||
}
|
||||
}
|
||||
|
||||
private fun presence(exists: Boolean) = if (exists) "present" else "missing"
|
||||
|
||||
private fun boundedIds(ids: List<String>): String {
|
||||
val weatherIds = ids.filter { it in WeatherIds.ALL }.distinct()
|
||||
val otherIds = ids.filterNot { it in WeatherIds.ALL }.take(MAX_STYLE_IDS - weatherIds.size)
|
||||
val shown = weatherIds + otherIds
|
||||
val omitted = ids.size - shown.size
|
||||
return buildString {
|
||||
append('[').append(shown.joinToString(","))
|
||||
if (omitted > 0) append(",…+").append(omitted)
|
||||
append(']')
|
||||
}
|
||||
}
|
||||
|
||||
private fun reject(promise: Promise, code: String, message: String) = promise.reject(code, message)
|
||||
private object WeatherIds {
|
||||
const val SOURCE = "rn-weather-fields"
|
||||
const val COLOR_LAYER = "rn-weather-color"
|
||||
const val PARTICLE_LAYER = "rn-weather-particles"
|
||||
val ALL = setOf(SOURCE, COLOR_LAYER, PARTICLE_LAYER)
|
||||
}
|
||||
companion object {
|
||||
const val NAME = "WeatherRuntimeBridge"
|
||||
const val MAX_STYLE_IDS = 24
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const marker = "// MapLibreParticleRNTestHost custom OpenGL SDK";
|
||||
module.exports = function withParticleNativeAndroid(config) {
|
||||
return withProjectBuildGradle(config, (project) => {
|
||||
if (project.modResults.contents.includes(marker)) return project;
|
||||
project.modResults.contents += `\n${marker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.mavenLocal()\n p.repositories.withType(org.gradle.api.artifacts.repositories.MavenArtifactRepository).configureEach { repo ->\n def repoUrl = repo.url.toString()\n if (repoUrl.contains(\"repo.maven.apache.org/maven2\") || repoUrl.contains(\"repo1.maven.org/maven2\")) {\n repo.content { excludeModule(\"org.maplibre.gl\", \"android-sdk-opengl\") }\n }\n }\n }\n}\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVersion\", \"13.4.1-step060d\")\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVariant\", \"opengl\")\n`;
|
||||
project.modResults.contents += `\n${marker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.mavenLocal()\n p.repositories.withType(org.gradle.api.artifacts.repositories.MavenArtifactRepository).configureEach { repo ->\n def repoUrl = repo.url.toString()\n if (repoUrl.contains(\"repo.maven.apache.org/maven2\") || repoUrl.contains(\"repo1.maven.org/maven2\")) {\n repo.content { excludeModule(\"org.maplibre.gl\", \"android-sdk-opengl\") }\n }\n }\n }\n}\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVersion\", \"13.4.1-step060e\")\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVariant\", \"opengl\")\n`;
|
||||
return project;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1113,6 +1113,10 @@ jni::Local<jni::Object<Layer>> NativeMapView::getLayer(JNIEnv& env, const jni::S
|
||||
return LayerManagerAndroid::get()->createJavaLayerPeer(env, *coreLayer);
|
||||
}
|
||||
|
||||
jni::jboolean NativeMapView::hasStyleLayer(JNIEnv& env, const jni::String& layerId) {
|
||||
return map->getStyle().getLayer(jni::Make<std::string>(env, layerId)) != nullptr;
|
||||
}
|
||||
|
||||
jni::jboolean NativeMapView::setStyleLayerFloatProperty(JNIEnv& env,
|
||||
const jni::String& layerId,
|
||||
const jni::String& propertyName,
|
||||
@@ -1496,6 +1500,10 @@ jni::Local<jni::Object<Source>> NativeMapView::getSource(JNIEnv& env, const jni:
|
||||
return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend, *map));
|
||||
}
|
||||
|
||||
jni::jboolean NativeMapView::hasStyleSource(JNIEnv& env, const jni::String& sourceId) {
|
||||
return map->getStyle().getSource(jni::Make<std::string>(env, sourceId)) != nullptr;
|
||||
}
|
||||
|
||||
void NativeMapView::addSource(JNIEnv& env, const jni::Object<Source>& obj, jlong sourcePtr) {
|
||||
assert(sourcePtr != 0);
|
||||
|
||||
@@ -1728,6 +1736,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::getLight, "nativeGetLight"),
|
||||
METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
|
||||
METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
|
||||
METHOD(&NativeMapView::hasStyleLayer, "nativeHasStyleLayer"),
|
||||
METHOD(&NativeMapView::setStyleLayerFloatProperty, "nativeSetStyleLayerFloatProperty"),
|
||||
METHOD(&NativeMapView::setStyleLayerVisibility, "nativeSetStyleLayerVisibility"),
|
||||
METHOD(&NativeMapView::setRasterParticleColors, "nativeSetRasterParticleColors"),
|
||||
@@ -1750,6 +1759,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"),
|
||||
METHOD(&NativeMapView::getSources, "nativeGetSources"),
|
||||
METHOD(&NativeMapView::getSource, "nativeGetSource"),
|
||||
METHOD(&NativeMapView::hasStyleSource, "nativeHasStyleSource"),
|
||||
METHOD(&NativeMapView::addSource, "nativeAddSource"),
|
||||
METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
|
||||
METHOD(&NativeMapView::addImage, "nativeAddImage"),
|
||||
|
||||
@@ -281,6 +281,7 @@ public:
|
||||
jni::Local<jni::Array<jni::Object<Layer>>> getLayers(JNIEnv&);
|
||||
|
||||
jni::Local<jni::Object<Layer>> getLayer(JNIEnv&, const jni::String&);
|
||||
jni::jboolean hasStyleLayer(JNIEnv&, const jni::String&);
|
||||
jni::jboolean setStyleLayerFloatProperty(JNIEnv&, const jni::String&, const jni::String&, jni::jfloat);
|
||||
jni::jboolean setStyleLayerVisibility(JNIEnv&, const jni::String&, jni::jboolean);
|
||||
jni::jboolean setRasterParticleColors(JNIEnv&, const jni::String&, const jni::Array<jni::jfloat>&, const jni::Array<jni::jfloat>&);
|
||||
@@ -313,6 +314,7 @@ public:
|
||||
jni::Local<jni::Array<jni::Object<Source>>> getSources(JNIEnv&);
|
||||
|
||||
jni::Local<jni::Object<Source>> getSource(JNIEnv&, const jni::String&);
|
||||
jni::jboolean hasStyleSource(JNIEnv&, const jni::String&);
|
||||
|
||||
void addSource(JNIEnv&, const jni::Object<Source>&, jlong nativePtr);
|
||||
|
||||
|
||||
@@ -179,6 +179,24 @@ public final class MapLibreMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the fully loaded Core style contains {@code layerId}.
|
||||
*
|
||||
* This intentionally queries Core by id instead of materialising a Java {@link
|
||||
* org.maplibre.android.style.layers.Layer} peer. It therefore also supports layer types that
|
||||
* are registered Core-only.
|
||||
*/
|
||||
public boolean hasStyleLayer(@NonNull String layerId) {
|
||||
return nativeMapView.hasStyleLayer(layerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the fully loaded Core style contains {@code sourceId}.
|
||||
*/
|
||||
public boolean hasStyleSource(@NonNull String sourceId) {
|
||||
return nativeMapView.hasStyleSource(sourceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this map's style-scoped weather facade. The caller must have already verified the
|
||||
* configured source and layers in the currently loaded style.
|
||||
|
||||
@@ -139,6 +139,8 @@ interface NativeMap {
|
||||
|
||||
Layer getLayer(String layerId);
|
||||
|
||||
boolean hasStyleLayer(@NonNull String layerId);
|
||||
|
||||
boolean setStyleLayerFloatProperty(String layerId, String propertyName, float value);
|
||||
|
||||
boolean setStyleLayerVisibility(String layerId, boolean visible);
|
||||
@@ -182,6 +184,8 @@ interface NativeMap {
|
||||
|
||||
Source getSource(@NonNull String sourceId);
|
||||
|
||||
boolean hasStyleSource(@NonNull String sourceId);
|
||||
|
||||
boolean removeSource(@NonNull String sourceId);
|
||||
|
||||
boolean removeSource(@NonNull Source source);
|
||||
|
||||
@@ -950,6 +950,11 @@ final class NativeMapView implements NativeMap {
|
||||
return nativeGetLayer(layerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStyleLayer(@NonNull String layerId) {
|
||||
return !checkState("hasStyleLayer") && nativeHasStyleLayer(layerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setStyleLayerFloatProperty(String layerId, String propertyName, float value) {
|
||||
return !checkState("setStyleLayerFloatProperty")
|
||||
@@ -1116,6 +1121,11 @@ final class NativeMapView implements NativeMap {
|
||||
return nativeGetSource(sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStyleSource(@NonNull String sourceId) {
|
||||
return !checkState("hasStyleSource") && nativeHasStyleSource(sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSource(@NonNull Source source) {
|
||||
if (checkState("addSource")) {
|
||||
@@ -1758,6 +1768,9 @@ final class NativeMapView implements NativeMap {
|
||||
@Keep
|
||||
private native Layer nativeGetLayer(String layerId);
|
||||
|
||||
@Keep
|
||||
private native boolean nativeHasStyleLayer(String layerId);
|
||||
|
||||
@Keep
|
||||
private native boolean nativeSetStyleLayerFloatProperty(String layerId, String propertyName, float value);
|
||||
|
||||
@@ -1811,6 +1824,9 @@ final class NativeMapView implements NativeMap {
|
||||
@Keep
|
||||
private native Source nativeGetSource(String sourceId);
|
||||
|
||||
@Keep
|
||||
private native boolean nativeHasStyleSource(String sourceId);
|
||||
|
||||
@Keep
|
||||
private native void nativeAddSource(Source source, long sourcePtr) throws CannotAddSourceException;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
13.4.1-step060d
|
||||
13.4.1-step060e
|
||||
|
||||
@@ -532,3 +532,10 @@ WeatherColorLayer 的 `ParticleGpuValidationUBO` designated initializer 补齐 `
|
||||
- attach 现独立报告 `rn-weather-fields`、`rn-weather-color`、`rn-weather-particles` 状态;`WEATHER_OBJECTS_NOT_READY` 包含 reactTag、MapView/MapLibreMap/Style 状态、三个 ID 的 present/missing、Style source/layer count 和 weather-first 的有界 ID 摘要。
|
||||
- Linux 生成并发布唯一诊断 AAR:`org.maplibre.gl:android-sdk-opengl:13.4.1-step060d`,build output 与 Maven Local AAR SHA-256 均为 `7391440f02e976f295caa265bc15e895a7c0183883a0e2cb08deef4cf42b0096`,含四 ABI。
|
||||
- 当前 Expo 生成工程缺失 `NativeWeatherRuntimeBridgeSpec`,标准 codegen task 为 SKIPPED,故 bridge Kotlin compile 不能独立验证;未改生成工程绕过。后续由 CARBON7i 用此唯一 AAR 收集 Android attach 诊断,仍不进入 STEP-061。
|
||||
|
||||
# 2026-09-08 — STEP-060E CoreOnly Layer 存在性检查修复
|
||||
|
||||
- 根因确认:WeatherColorLayer 与 RasterParticleLayer 属于 CoreOnly layer,Core 能渲染但没有 Java Layer peer;故 STEP-060D bridge 用 Style.getLayer() 会对真实 layer 产生假阴性。
|
||||
- 新增 MapLibreMap.hasStyleSource/hasStyleLayer,经 Android JNI 直接查询 Core Style;bridge attach 三项 weather object 判断统一使用该真值,保留既有成功路径与 WeatherRuntime 生命周期,不增 Java peer、重试或私有 registry。
|
||||
- WEATHER_OBJECTS_NOT_READY 改用 styleUri(JSON style 为 <empty>)并移除不可靠的 Java layer/source 枚举;临时 Maven version 升为 13.4.1-step060e。
|
||||
- 本轮不构建 AAR、不发布 Maven Local,APK/ADB/设备验收待人工构建该版本后进行;仍属于 STEP-060,未进入 STEP-061。
|
||||
|
||||
Reference in New Issue
Block a user