From c91af1682574d1e7a24de1060b50f9a7e2e2e25d Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Tue, 8 Sep 2026 22:14:33 +0800 Subject: [PATCH] fix: route WeatherColor opacity through typed API --- ...P-060_RNTestHost与WeatherRuntime薄桥接_v2.md | 33 +++++++++++++++++++ ...P-060_RNTestHost_Android人工编译与验收_v1.md | 10 +++--- .../MapLibreParticleRNTestHost/README.md | 8 +++-- .../android/build.gradle | 2 +- .../plugins/withParticleNativeAndroid.js | 2 +- .../scripts/05-install-and-run.ps1 | 18 ++++++++++ .../src/cpp/native_map_view.cpp | 12 +++++++ .../src/cpp/native_map_view.hpp | 1 + .../maplibre/android/maps/MapLibreMap.java | 5 +++ .../org/maplibre/android/maps/NativeMap.java | 2 ++ .../maplibre/android/maps/NativeMapView.java | 7 ++++ .../maplibre/android/maps/WeatherRuntime.java | 2 +- platform/android/VERSION | 2 +- 粒子开发记录.md | 7 ++++ 14 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 docs/50_Step记录/STEP-060_RNTestHost与WeatherRuntime薄桥接_v2.md create mode 100644 integration/react-native/MapLibreParticleRNTestHost/scripts/05-install-and-run.ps1 diff --git a/docs/50_Step记录/STEP-060_RNTestHost与WeatherRuntime薄桥接_v2.md b/docs/50_Step记录/STEP-060_RNTestHost与WeatherRuntime薄桥接_v2.md new file mode 100644 index 000000000..a26b28892 --- /dev/null +++ b/docs/50_Step记录/STEP-060_RNTestHost与WeatherRuntime薄桥接_v2.md @@ -0,0 +1,33 @@ +# STEP-060 RN Test Host 与 WeatherRuntime 薄桥接 + +状态:`IMPLEMENTED / WAITING_ANDROID_VALIDATION` + +## 目标与基线 + +本记录在 v1 基础上追加 STEP-060F 收尾:修正 Android WeatherColor opacity 的 typed 路径,固定 Test Host 的 Metro reverse 兼容与横屏交接;仍属于 STEP-060,不进入 STEP-061 Binary U/V Field Transport。 + +## 已完成项 + +- [x] STEP-060E Android attach 已人工 PASS;CoreOnly source/layer 真值查询使 `WEATHER_OBJECTS_NOT_READY` 消失。 +- [x] `WeatherRuntime.setWeatherColorOpacity()` 不再误走仅适用于 `RasterParticleLayer` 的 float property setter。 +- [x] 新增 `MapLibreMap.setWeatherColorOpacity(String, float)`,经 NativeMap、NativeMapView、JNI 直达 Core `WeatherColorLayer::setOpacity()`;不存在、类型不符或非 finite 输入均返回 false,未创建 Java Layer peer。 +- [x] RasterParticle 的 float-property whitelist、`RasterParticleLayer` 类型语义及 Timeline/Playback 均未扩大或修改。 +- [x] 纳入受控 `scripts/05-install-and-run.ps1`:保留 `8091 -> 8091`,并在安装前增加 `8081 -> 8091`。 +- [x] 保持 `app.json` 的 `orientation: landscape`;下次 Android prebuild/build 应生成 `MainActivity android:screenOrientation="landscape"`。 +- [x] 临时 Maven 坐标切换为 `org.maplibre.gl:android-sdk-opengl:13.4.1-step060f`。 + +## 验证边界与当前结果 + +- [x] 已作 JNI Java/C++ 声明、实现与 registration 静态一致性检查;WeatherColor opacity 唯一路径直达 `WeatherColorLayer::setOpacity()`。 +- [x] 已检查双 reverse、版本接线、landscape JSON 与源码 diff。 +- [ ] Android AAR、Maven Local、APK、Gradle、ADB/设备与 Jest:本轮未执行,等待用户按人工验收文档验证。 + +无 Binary Field 时 `WAITING_FOR_FIELDS / PAUSE` 下的 Timeline 命令仍可返回 `TIMELINE_NOT_READY`;这是预期 fail-closed 行为。最终 Android hard gate 尚需确认 `weather opacity: ACCEPTED` 且不再有 `STYLE_PROPERTY_SET result=UNSUPPORTED_PROPERTY`。 + +## 禁止范围确认 + +未改 `RasterParticleLayerFactory` / `WeatherColorLayerFactory` CoreOnly 注册、NavSea、Bridge JS state、Timeline 语义或 STEP-061 内容。 + +## 下一步 + +用户手工构建并发布 `13.4.1-step060f` OpenGL AAR,核对 Linux/Win11 SHA-256 与两条 dependencyInsight,随后 Android clean prebuild、APK build、双 reverse 安装和设备验收。只有所有 Android hard gate 通过后,STEP-060 才可标记 CLOSED / PASS。 diff --git a/docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md b/docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md index 4906e6a89..f0ef2e3fe 100644 --- a/docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md +++ b/docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md @@ -4,13 +4,13 @@ 1. 确认当前为 `particle/main`,并记录 `git rev-parse HEAD`。Gate C 封存 Linux 环境是 custom MapLibre Native AAR 的构建环境;不要为 Test Host 生成工程的版本修改它。 2. 移走或清理 `~/.m2/repository/org/maplibre/gl/android-sdk-opengl/13.4.1/` 的旧 artifact,避免同坐标 provenance 混淆。2026-08-29 旧 AAR 的 SHA-256 是 `5c67d2751fafe211a0df4b82deded09ab1c07cf6ca0f4a12a880283287f85e5c`,只能作为 Gate C 历史证据。 -3. STEP-060D attach 精确诊断当前使用唯一坐标 `org.maplibre.gl:android-sdk-opengl:13.4.1-step060d`。Linux 已完成 OpenGL Release 四 ABI build 与 Maven Local publication;Maven Local 的同版本 AAR、POM、module metadata 均存在,且没有 `.asc`。Maven Central 正式 publication 仍要求签名。 -4. 此诊断 AAR 与 Linux build output AAR SHA-256 均为 `7391440f02e976f295caa265bc15e895a7c0183883a0e2cb08deef4cf42b0096`,并含 `WeatherRuntime.class`、`MapLibreMap.class` 与四 ABI。Windows 必须先以此版本和 SHA 更新 Maven Local,再运行 dependencyInsight / APK 流程;不得混用先前 `13.4.1` artifact(其 SHA `2e73e…`)。 +3. 本轮唯一坐标是 `org.maplibre.gl:android-sdk-opengl:13.4.1-step060f`。必须先在 Linux 手工构建并 publish 这个新 AAR,记录 build output 与 Maven Local AAR SHA-256 且两者一致;不得复用 `step060e` 或先前 `13.4.1` artifact。 +4. 将该 AAR 按发布流程复制到 `/mnt/nas/pbf/`,Win11 用每次不同的 `?v=` 下载,核对 SHA-256 后安装 Maven Local。 5. `cd integration/react-native/MapLibreParticleRNTestHost && npm ci && npx expo prebuild --platform android --clean`。`package-lock.json` 已在无 `--legacy-peer-deps` 的 npm 安装下通过;不要改用 Yarn 或生成 `yarn.lock`。本次 plugin 变更后必须 clean prebuild。 -6. 检查生成 root Gradle 有 `MapLibreParticleRNTestHost custom OpenGL SDK`、`nativeVersion=13.4.1`、`nativeVariant=opengl`;Maven Central 必须排除精确 custom module `org.maplibre.gl:android-sdk-opengl`,使该 AAR 缺失时失败而非 fallback。MLRN 的 turf/annotation/scalebar 不是 custom SDK,不应被这个模块级排除误伤。 +6. 检查生成 root Gradle 有 `MapLibreParticleRNTestHost custom OpenGL SDK`、`nativeVersion=13.4.1-step060f`、`nativeVariant=opengl`;MLRN 与 Bridge 两条 `dependencyInsight` 都必须解析到 `13.4.1-step060f`。Maven Central 必须排除精确 custom module `org.maplibre.gl:android-sdk-opengl`,使该 AAR 缺失时失败而非 fallback。 7. 首次 prebuild 后实际记录 Test Host 的 Gradle wrapper、AGP、Kotlin plugin、min/compile/targetSdk、NDK、JDK、Hermes 与 New Architecture。当前观察到的 `9.3.1/8.12.0/2.1.20/24/36/36/27.1.12297006` 属于 Test Host 生成工程,不等于 Gate C 环境。 -8. 再按实际生成工程编译/安装 Test Host。启动后确认单一地图正常加载;style ready 后应显示 reactTag 和 `WAITING_FOR_FIELDS`,不提交 field 时粒子/色场为空是预期。 +8. 再按实际生成工程编译。`app.json` 的 landscape 配置在本次 clean prebuild 后应使 `MainActivity` 生成 `android:screenOrientation="landscape"`;核对后以 `scripts/05-install-and-run.ps1` 安装启动。该脚本必须同时保持 `adb -s 192.168.1.146 reverse tcp:8091 tcp:8091` 与 `adb -s 192.168.1.146 reverse tcp:8081 tcp:8091`。 9. 对同一 reactTag 依次验证 Phase A:getState、enable、WeatherColor visible、particle visible、FPS 30 均得到结构化 Native result。 -10. 验证 Phase B:PLAY/PAUSE、HALF/NORMAL/DOUBLE、epoch-ms seek、stops、独立 particle/trail RGBA、count/line/length/opacity/fade/WeatherColor opacity。不得出现 JS `PLAYING/PAUSED` 第二状态机。 +10. 验证 Phase B:stops、独立 particle/trail RGBA、count/line/length/opacity/fade 与 WeatherColor opacity。`weather opacity` 必须为 `ACCEPTED`,且不再出现 `ParticleGPU: event=STYLE_PROPERTY_SET result=UNSUPPORTED_PROPERTY`。无 Binary Field 时 PLAY/PAUSE、HALF/NORMAL/DOUBLE 与 epoch-ms seek 仍可因 `TIMELINE_NOT_READY` 返回 `REJECTED`;不得改变这个 fail-closed 行为,也不得出现 JS `PLAYING/PAUSED` 第二状态机。 11. 重载 style:旧 Runtime 必须 disposed;style ready attach 的新 Runtime 正常工作。remount Map 后,用旧 reactTag 调用必须返回 `MAP_VIEW_NOT_FOUND`,不得命中新 Map。 12. 卸载 Host:确认 view detach dispose;无持续 Handler wake、无全局 current map。通过上述 Android 验收后才进入 STEP-061;此前不要尝试 number[]、JSON/base64 大 field。 diff --git a/integration/react-native/MapLibreParticleRNTestHost/README.md b/integration/react-native/MapLibreParticleRNTestHost/README.md index af20f90d8..cf3cf00cf 100644 --- a/integration/react-native/MapLibreParticleRNTestHost/README.md +++ b/integration/react-native/MapLibreParticleRNTestHost/README.md @@ -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-step060e` 与 `nativeVariant=opengl`;这是 STEP-060E CoreOnly layer 存在性检查修复 的唯一临时版本,避免与先前 `13.4.1` Maven Local artifact 缓存混淆。 +- MLRN 的 root Gradle extras 固定 `org.maplibre.reactnative.nativeVersion=13.4.1-step060f` 与 `nativeVariant=opengl`;这是 STEP-060F WeatherColor opacity 修复的唯一临时版本,避免与先前 Maven Local artifact 缓存混淆。 ## Custom SDK 来源(手工执行) @@ -39,4 +39,8 @@ Style JSON 明确创建 background、host-field `RasterArraySource`、`WeatherCo 当前**不包含 Binary Field**,不传 `number[]`、JSON 数组或 base64 field。3.01 MiB canonical field ingress 留给 STEP-061。 -启动入口是 `App.tsx`。Android build、安装及设备操作必须由用户手工执行,详见 `docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md`。 +启动入口是 `App.tsx`。`app.json` 已固定 `orientation: landscape`;下一次 Android prebuild/build 应生成 `MainActivity android:screenOrientation="landscape"`。Android build、安装及设备操作必须由用户手工执行,详见 `docs/60_测试/STEP-060_RNTestHost_Android人工编译与验收_v1.md`。 + +## 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。 diff --git a/integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/build.gradle b/integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/build.gradle index 42cfc147b..24d21e98d 100644 --- a/integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/build.gradle +++ b/integration/react-native/MapLibreParticleRNTestHost/modules/weather-runtime-bridge/android/build.gradle @@ -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-step060e" + implementation "org.maplibre.gl:android-sdk-opengl:13.4.1-step060f" compileOnly project(":maplibre_maplibre-react-native") } diff --git a/integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js b/integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js index 6a4ff2ad7..4f67da07d 100644 --- a/integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js +++ b/integration/react-native/MapLibreParticleRNTestHost/plugins/withParticleNativeAndroid.js @@ -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-step060e\")\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-step060f\")\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVariant\", \"opengl\")\n`; return project; }); }; diff --git a/integration/react-native/MapLibreParticleRNTestHost/scripts/05-install-and-run.ps1 b/integration/react-native/MapLibreParticleRNTestHost/scripts/05-install-and-run.ps1 new file mode 100644 index 000000000..55923b38d --- /dev/null +++ b/integration/react-native/MapLibreParticleRNTestHost/scripts/05-install-and-run.ps1 @@ -0,0 +1,18 @@ +$ErrorActionPreference = 'Stop' +Write-Host '=== 安装并启动 RN Test Host ===' +$root = Split-Path $PSScriptRoot -Parent +$apk = Join-Path $root 'android\app\build\outputs\apk\debug\app-debug.apk' +if (-not (Test-Path $apk)) { throw '请先执行 03-build-debug.ps1' } + +$device = '192.168.1.146' +adb -s $device get-state +adb -s $device reverse tcp:8091 tcp:8091 +adb -s $device reverse tcp:8081 tcp:8091 +adb -s $device install -r $apk +if ($LASTEXITCODE -ne 0) { throw 'APK 安装失败' } + +$pkg = 'org.maplibre.particle.rntesthost' +adb -s $device shell am force-stop $pkg +adb -s $device shell am start -n "$pkg/.MainActivity" +Write-Host '已启动。Metro 应在另一个窗口监听 8091。' +Write-Host '若开发客户端显示服务器列表,请选择本机 8091 的 development server。' diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp index d76bb4083..d4eba269d 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp @@ -1176,6 +1176,17 @@ jni::jboolean NativeMapView::setStyleLayerFloatProperty(JNIEnv& env, return true; } +jni::jboolean NativeMapView::setWeatherColorOpacity(JNIEnv& env, + const jni::String& layerId, + const jni::jfloat opacity) { + if (!std::isfinite(opacity)) return false; + auto* layer = dynamic_cast( + map->getStyle().getLayer(jni::Make(env, layerId))); + if (!layer) return false; + layer->setOpacity(opacity); + return true; +} + jni::jboolean NativeMapView::setStyleLayerVisibility(JNIEnv& env, const jni::String& layerId, const jni::jboolean visible) { auto* layer = map->getStyle().getLayer(jni::Make(env, layerId)); if (!layer) return false; @@ -1738,6 +1749,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { METHOD(&NativeMapView::getLayer, "nativeGetLayer"), METHOD(&NativeMapView::hasStyleLayer, "nativeHasStyleLayer"), METHOD(&NativeMapView::setStyleLayerFloatProperty, "nativeSetStyleLayerFloatProperty"), + METHOD(&NativeMapView::setWeatherColorOpacity, "nativeSetWeatherColorOpacity"), METHOD(&NativeMapView::setStyleLayerVisibility, "nativeSetStyleLayerVisibility"), METHOD(&NativeMapView::setRasterParticleColors, "nativeSetRasterParticleColors"), METHOD(&NativeMapView::setRasterParticleColor, "nativeSetRasterParticleColor"), diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp index 057984632..6f4a3437d 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp @@ -283,6 +283,7 @@ public: jni::Local> 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 setWeatherColorOpacity(JNIEnv&, const jni::String&, jni::jfloat); jni::jboolean setStyleLayerVisibility(JNIEnv&, const jni::String&, jni::jboolean); jni::jboolean setRasterParticleColors(JNIEnv&, const jni::String&, const jni::Array&, const jni::Array&); jni::jboolean setRasterParticleColor(JNIEnv&, const jni::String&, const jni::Array&); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java index 28f629457..72d2acb63 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java @@ -342,6 +342,11 @@ public final class MapLibreMap { return nativeMapView.setStyleLayerFloatProperty(layerId, propertyName, value); } + /** Updates the opacity of an existing Core-owned WeatherColor layer without a Java Layer peer. */ + public boolean setWeatherColorOpacity(String layerId, float opacity) { + return nativeMapView.setWeatherColorOpacity(layerId, opacity); + } + /** Low-frequency style visibility used by the typed WeatherRuntime facade. */ public boolean setStyleLayerVisibility(String layerId, boolean visible) { return nativeMapView.setStyleLayerVisibility(layerId, visible); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java index d4163f24a..d295df1c5 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java @@ -143,6 +143,8 @@ interface NativeMap { boolean setStyleLayerFloatProperty(String layerId, String propertyName, float value); + boolean setWeatherColorOpacity(String layerId, float opacity); + boolean setStyleLayerVisibility(String layerId, boolean visible); boolean setRasterParticleColors(String layerId, float[] particleColor, float[] trailColor); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java index 790bed333..41edd33aa 100755 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java @@ -961,6 +961,11 @@ final class NativeMapView implements NativeMap { && nativeSetStyleLayerFloatProperty(layerId, propertyName, value); } + @Override + public boolean setWeatherColorOpacity(String layerId, float opacity) { + return !checkState("setWeatherColorOpacity") && nativeSetWeatherColorOpacity(layerId, opacity); + } + public boolean setStyleLayerVisibility(String layerId, boolean visible) { return !checkState("setStyleLayerVisibility") && nativeSetStyleLayerVisibility(layerId, visible); } @@ -1774,6 +1779,8 @@ final class NativeMapView implements NativeMap { @Keep private native boolean nativeSetStyleLayerFloatProperty(String layerId, String propertyName, float value); + @Keep private native boolean nativeSetWeatherColorOpacity(String layerId, float opacity); + @Keep private native boolean nativeSetStyleLayerVisibility(String layerId, boolean visible); @Keep private native boolean nativeSetRasterParticleColors(String layerId, float[] particleColor, float[] trailColor); @Keep private native boolean nativeSetRasterParticleColor(String layerId, float[] particleColor); diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/WeatherRuntime.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/WeatherRuntime.java index 9d7213e4e..893d951b0 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/WeatherRuntime.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/WeatherRuntime.java @@ -101,7 +101,7 @@ public final class WeatherRuntime { public CommandResult setForecastTime(long timestampMs) { requireEnabled(); return result(timestampMs >= 0 && map.seekRasterArraySourceTimelineToTimestamp(config.sourceId, timestampMs)); } public CommandResult setPlaybackState(@NonNull PlaybackState playback) { requireEnabled(); CommandResult result = result(map.controlRasterArraySourceTimeline(config.sourceId, playback == PlaybackState.PLAY ? 0 : 1, 0f)); if (result == CommandResult.ACCEPTED) { playbackState = playback; cancelCadenceWake(); scheduleCadenceWake(); } return result; } public CommandResult setPlaybackSpeed(@NonNull PlaybackSpeed speed) { requireEnabled(); return result(map.controlRasterArraySourceTimeline(config.sourceId, 2, speed.value)); } - public CommandResult setWeatherColorOpacity(float opacity) { return disposed ? CommandResult.REJECTED : result(Float.isFinite(opacity) && map.setStyleLayerFloatProperty(config.weatherColorLayerId, "weather-color-opacity", opacity)); } + public CommandResult setWeatherColorOpacity(float opacity) { return disposed ? CommandResult.REJECTED : result(Float.isFinite(opacity) && map.setWeatherColorOpacity(config.weatherColorLayerId, opacity)); } public CommandResult setParticleCount(int count) { return setParticleFloat("raster-particle-particle-count", count); } public CommandResult setParticleLineWidth(float width) { return setParticleFloat("raster-particle-line-width", width); } public CommandResult setParticleLength(float length) { return setParticleFloat("raster-particle-particle-length", length); } diff --git a/platform/android/VERSION b/platform/android/VERSION index 6437a5894..1626bb6e4 100644 --- a/platform/android/VERSION +++ b/platform/android/VERSION @@ -1 +1 @@ -13.4.1-step060e +13.4.1-step060f diff --git a/粒子开发记录.md b/粒子开发记录.md index e9d26cdae..916c27ba3 100644 --- a/粒子开发记录.md +++ b/粒子开发记录.md @@ -539,3 +539,10 @@ WeatherColorLayer 的 `ParticleGpuValidationUBO` designated initializer 补齐 ` - 新增 MapLibreMap.hasStyleSource/hasStyleLayer,经 Android JNI 直接查询 Core Style;bridge attach 三项 weather object 判断统一使用该真值,保留既有成功路径与 WeatherRuntime 生命周期,不增 Java peer、重试或私有 registry。 - WEATHER_OBJECTS_NOT_READY 改用 styleUri(JSON style 为 )并移除不可靠的 Java layer/source 枚举;临时 Maven version 升为 13.4.1-step060e。 - 本轮不构建 AAR、不发布 Maven Local,APK/ADB/设备验收待人工构建该版本后进行;仍属于 STEP-060,未进入 STEP-061。 + +# 2026-09-08 — STEP-060F WeatherColor Opacity 与 Android 收尾修复 + +- Android 已实测 attach PASS,`WEATHER_OBJECTS_NOT_READY` 已由 STEP-060E CoreOnly 真值链解决;无 Binary Field 的 `TIMELINE_NOT_READY` 仍是预期 fail-closed 行为。 +- 修正 WeatherColor opacity 错走 particle-only setter:新增独立 Java/JNI/Core typed 路径,直达 `WeatherColorLayer::setOpacity()`,不扩大 RasterParticle whitelist 或新增 Java Layer peer。 +- Test Host 将 `8091 -> 8091` 与 Android debug probe 所需 `8081 -> 8091` 固化到 Git 受控启动脚本,保留 `app.json` landscape;临时坐标升为 `13.4.1-step060f`。 +- 状态为 `IMPLEMENTED / WAITING_ANDROID_VALIDATION`;AAR/APK/ADB/设备最终复验等待用户,本轮未进入 STEP-061。