Compare commits
4 Commits
maplibre-p
...
6df21dac38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6df21dac38 | ||
|
|
53a844e818 | ||
|
|
a4c6047d70 | ||
|
|
078ba40b76 |
436
docs/20_调查/RenderSegment多Retained段全局Placement门槛_粒子管理员审查说明_v1.md
Normal file
436
docs/20_调查/RenderSegment多Retained段全局Placement门槛_粒子管理员审查说明_v1.md
Normal file
@@ -0,0 +1,436 @@
|
||||
# RenderSegment 多 Retained 段全局 Placement 门槛——粒子管理员审查说明 v1
|
||||
|
||||
日期:2026-10-07
|
||||
性质:调查结论 / 修改目标 / 管理员审查输入,不是直接实施任务书。
|
||||
目标读者:Particle Shared Core / Renderer 维护者。
|
||||
|
||||
## 1. 本文要解决的问题
|
||||
|
||||
NavSea 当前已经能通过公开 `RendererRuntime.setRenderSegmentPlan()` 配置任意连续的 `RETAINED / CONTINUOUS` Segment,且 `.19 / .20` 的 RenderSegment 实现已经具备 source-local revision / readiness / cache diagnostics 等基础。
|
||||
|
||||
但 NavSea 真实运行验证发现:当存在多个 Retained Segment 时,一个与某 Retained Segment 无直接关系的全局 placement/fade 状态,仍可能把所有 Retained Segment 同时打回 fallback,导致多 Segment 不能发挥设计目标。
|
||||
|
||||
本文希望 Particle 管理员审查并决定:怎样把剩余的 placement/global fallback 门槛收敛到正确粒度,同时保持 fail-closed、Style Z-order、跨平台语义和 C-001 边界不变。
|
||||
|
||||
## 2. 正式边界
|
||||
|
||||
跨项目 Contract 仍为 `C-001`。
|
||||
|
||||
本问题属于 Particle Renderer 内部实现优化,目标上不要求新增 NavSea 私有 Native 通道,也不要求 Particle 理解 AIS、Route、Weather、Alarm 等 NavSea 业务语义。
|
||||
|
||||
NavSea 仍只负责:
|
||||
- 按 Style Z-order 选择 Segment 边界;
|
||||
- 通过稳定公开 API 提交 RenderSegmentPlan;
|
||||
- 读取 diagnostics;
|
||||
- 决定天气等业务能力何时显示。
|
||||
|
||||
Particle 仍负责:
|
||||
- Segment resolve / cache / invalidation / renderer execution;
|
||||
- placement / transition / fading / source dependency 的正确性;
|
||||
- GPU resource 和 stale-cache 安全;
|
||||
- Android / iOS 共用的 Shared Core 语义。
|
||||
|
||||
本修改若不改变公共 API、生命周期、错误语义或双方职责,不需要升级 Contract。
|
||||
|
||||
## 3. 当前 Mac 基线需要管理员先确认
|
||||
|
||||
本次只读检查发现:
|
||||
|
||||
- `/Users/tei/dev/MapLibreParticleLab`
|
||||
- branch: `particle/main`
|
||||
- HEAD: `750c14f52708d7dc93d8eb6ec2b21112185afd5c`
|
||||
- `/Users/tei/dev/MapLibreParticleLab-release-v19`
|
||||
- branch: `release/particle.19`
|
||||
- HEAD: `6b48f905d2d17a8271b6ff883e682db7bc45dcd3`
|
||||
- `/Users/tei/dev/MapLibreParticleLab-release-v20`
|
||||
- branch: `release/particle.20`
|
||||
- HEAD: `53a844e81849f254ba2d169c2d875dbd862cc7d5`
|
||||
- `/Users/tei/dev/MapLibreParticleLab-step101`
|
||||
- branch: `step101-render-orchestrator-teardown`
|
||||
|
||||
NavSea 当前实际消费的是 `.19` 行为;本次检查确认 `release/particle.19` 与 `release/particle.20` 在本文相关 placement gate 代码上相同。
|
||||
|
||||
注意:当前 `particle/main` 与 `release/particle.19/.20` 的 RenderSegment 执行细节存在差异,因此管理员开始修改前必须先明确正式修复基线,不要把 main 与 release 分支默认视为完全一致。
|
||||
|
||||
## 4. NavSea 当前为什么需要多 Segment
|
||||
|
||||
NavSea 当前为了避免旧的 retained fallback,采用保守的两段方案:
|
||||
|
||||
```text
|
||||
R0 [0,31) RETAINED
|
||||
C0 [31,114) CONTINUOUS
|
||||
```
|
||||
|
||||
C0 从 `rn-weather-color` 开始一直覆盖到 Style 尾部。
|
||||
|
||||
真实 diagnostics 已确认该 Continuous 尾段包含天气之后的大量运行时对象,包括 AIS / ownship / navigation / alarm 等 source/layer。
|
||||
|
||||
这能保护 R0 底图复用,但代价是:天气粒子需要持续 repaint 时,天气以上整个 Style 尾部都留在 Continuous 区域。
|
||||
|
||||
RenderSegment 的原始设计目标本来就是允许:
|
||||
|
||||
```text
|
||||
R0 → C0 → R1 → C1 → R2 ...
|
||||
```
|
||||
|
||||
并严格保持 Style Z-order,不把业务语义写进 Renderer。
|
||||
|
||||
## 5. NavSea 真实多段实验 A
|
||||
|
||||
第一次临时配置:
|
||||
|
||||
```text
|
||||
R0 [0,31)
|
||||
C0 [31,79)
|
||||
R1 [79,98)
|
||||
C1 [98,114)
|
||||
```
|
||||
|
||||
Native 接受该配置:
|
||||
|
||||
```text
|
||||
configured=true
|
||||
valid=true
|
||||
segmentCount=4
|
||||
retainedSegmentCount=2
|
||||
continuousSegmentCount=2
|
||||
coverageComplete=true
|
||||
fallback=false
|
||||
```
|
||||
|
||||
解析结果:
|
||||
|
||||
- R0: `background` → `place-labels-land-ja`
|
||||
- C0: `rn-weather-color` → `ownshipRangeLabelLayer`
|
||||
- R1: `routeLineActiveShadowLayer` → `planSimBoatLabelLayer`
|
||||
- C1: `crossCursorGotoLineLayer` → `chartDangerScanCenterLineLayer`
|
||||
|
||||
R1 当时依赖:
|
||||
- `navigationSource`
|
||||
- `ownshipTrackSource`
|
||||
- `planSimRouteSource`
|
||||
|
||||
结果 R1 为 `source-fading` fallback,`reuse=0`。
|
||||
|
||||
这个结果本身还不能证明 placement 问题,因为 R1 确实包含活动 source。
|
||||
|
||||
## 6. NavSea 真实多段实验 B:把 R1 收窄到 idle PlanSim
|
||||
|
||||
第二次把 R1 收窄为只有 PlanSim Route 的 10 个 layer:
|
||||
|
||||
```text
|
||||
R0 [0,31)
|
||||
C0 [31,88)
|
||||
R1 [88,98)
|
||||
C1 [98,114)
|
||||
```
|
||||
|
||||
R1:
|
||||
- start: `planSimRouteShadowLayer`
|
||||
- end: `planSimBoatLabelLayer`
|
||||
- dependent source: 仅 `planSimRouteSource`
|
||||
- 当时 PlanSim 为 idle。
|
||||
|
||||
5 秒早期诊断仍有 `source-fading`,所以继续等待到约 20 秒稳定态。
|
||||
|
||||
20 秒稳定态关键结果:
|
||||
|
||||
```text
|
||||
fadingSourceIds = []
|
||||
```
|
||||
|
||||
R0:
|
||||
```text
|
||||
sourceReady=true
|
||||
sourceStable=true
|
||||
cacheState=fallback
|
||||
build=0
|
||||
reuse=0
|
||||
invalidation=306
|
||||
lastInvalidationReason=static-placement
|
||||
finalDecision=fallback
|
||||
```
|
||||
|
||||
R1:
|
||||
```text
|
||||
sourceReady=true
|
||||
sourceStable=true
|
||||
cacheState=fallback
|
||||
build=1
|
||||
reuse=0
|
||||
invalidation=306
|
||||
lastInvalidationReason=static-placement
|
||||
finalDecision=fallback
|
||||
```
|
||||
|
||||
这说明稳定 source 已经不是阻塞因素;两个 Retained Segment 被同一个 `static-placement` 门槛同步打回 fallback。
|
||||
|
||||
## 7. release/particle.19 / .20 当前代码事实
|
||||
|
||||
### 7.1 per-segment source locality 已经存在
|
||||
|
||||
`.19 / .20` 在 `renderer_impl.cpp` 中会对每个 Retained Segment 单独计算:
|
||||
|
||||
- `retainedSegmentSourceState(begin,end)`
|
||||
- source-local revision
|
||||
- source `ready / stable`
|
||||
- `retainedSegmentIsStable(begin,end)`
|
||||
- `segmentSupportsCache[]`
|
||||
- 每个 cache 独立 `evaluate()`
|
||||
- 每段独立 diagnostics / finalDecision
|
||||
|
||||
`render_orchestrator.cpp` 中 `retainedSegmentSourceState()` 已通过 RenderSegment dependency 只检查该 Segment 相关 source 的 loaded / fading 状态。
|
||||
|
||||
这部分方向是正确的,不应回退到全局 source invalidation。
|
||||
|
||||
### 7.2 剩余 placement gate 仍是全局聚合
|
||||
|
||||
`.19 / .20` 的 `renderer_impl.cpp` 仍先对全部 Retained Segment 聚合:
|
||||
|
||||
```cpp
|
||||
bool retainedStaticUsesPlacement = false;
|
||||
...
|
||||
retainedStaticUsesPlacement =
|
||||
retainedStaticUsesPlacement ||
|
||||
orchestrator.retainedRangeUsesPlacement(...);
|
||||
|
||||
const bool retainedPlacementStable =
|
||||
!retainedStaticUsesPlacement ||
|
||||
(!renderTreeParameters.placementChanged &&
|
||||
renderTreeParameters.symbolFadeChange == 0.0f);
|
||||
```
|
||||
|
||||
然后每个 Segment 的 `segmentSupported` 又共同依赖同一个 `retainedPlacementStable`。
|
||||
|
||||
因此只要任一 Retained Segment 使用 placement,并且当前全局 frame 有 `placementChanged / symbolFadeChange`,所有 Retained Segment 都可能失去 cache eligibility。
|
||||
|
||||
### 7.3 full CPU mixed execution 已有基础,但仍有 globalLiveFallback
|
||||
|
||||
`.19 / .20` 已有 `visitRenderSegmentExecution(...)`,理论上可以:
|
||||
|
||||
```text
|
||||
R0 reuse
|
||||
C0 live
|
||||
R1 fallback/live
|
||||
C1 live
|
||||
R2 reuse
|
||||
```
|
||||
|
||||
但是进入该混合执行前仍有:
|
||||
|
||||
```cpp
|
||||
const bool globalLiveFallback =
|
||||
...
|
||||
!retainedPlacementStable ||
|
||||
orchestrator.retainedGlobalLightTransition();
|
||||
```
|
||||
|
||||
`!retainedPlacementStable` 会直接导致:
|
||||
|
||||
```text
|
||||
drawableOpaquePass(0, layerCount)
|
||||
drawableTranslucentPass(0, layerCount)
|
||||
```
|
||||
|
||||
即整帧退回全 live,绕过 per-segment mixed execution。
|
||||
|
||||
这与 NavSea 实验中 R0/R1 同时出现 `static-placement` fallback 的现象一致。
|
||||
|
||||
## 8. 希望管理员审查的核心修改目标
|
||||
|
||||
目标不是简单“关闭 placement 检查”。
|
||||
|
||||
目标是:
|
||||
|
||||
> 当 placement / symbol fade 只影响某些 Segment 时,不应让与其无关、且自身内容/依赖/相机均稳定的 Retained Segment 一起失效。
|
||||
|
||||
期望行为示例:
|
||||
|
||||
```text
|
||||
R0:不含 placement layer,source stable
|
||||
C0:Weather continuous
|
||||
R1:含 placement 或当前 placement unstable
|
||||
C1:AIS / Alarm continuous
|
||||
R2:不含 placement layer,source stable
|
||||
|
||||
期望:
|
||||
R0 = reuse
|
||||
C0 = live
|
||||
R1 = fallback/live
|
||||
C1 = live
|
||||
R2 = reuse
|
||||
```
|
||||
|
||||
而不是:
|
||||
|
||||
```text
|
||||
R1 placement unstable
|
||||
→ global retainedPlacementStable=false
|
||||
→ R0/R1/R2 全部失效
|
||||
→ 整帧 full live
|
||||
```
|
||||
|
||||
## 9. 建议管理员重点评估的实现方向
|
||||
|
||||
以下是审查建议,不是强制实现方案。
|
||||
|
||||
### 9.1 先把 placement eligibility 变成 per-retained-segment
|
||||
|
||||
对于每个 Retained Segment 分别判断:
|
||||
|
||||
- 该 Segment 是否实际 `usesPlacement`;
|
||||
- 该 Segment 的 layer transition / needsRepaint;
|
||||
- 该 Segment 的 source readiness / fading;
|
||||
- placement transition 是否确实会改变该 Segment 的最终像素;
|
||||
- 是否存在必须全局 fail-closed 的 placement 共享状态。
|
||||
|
||||
至少对于 **完全不含 placement layer 的 Retained Segment**,应评估是否有理由继续受全局 `placementChanged / symbolFadeChange` 阻塞。
|
||||
|
||||
### 9.2 审查 `globalLiveFallback` 中的 `!retainedPlacementStable`
|
||||
|
||||
建议确认是否可以:
|
||||
|
||||
- 从 globalLiveFallback 移除纯 placement 条件;
|
||||
- 让 placement 结果进入每段 `segmentSupported / decision`;
|
||||
- 真正使用现有 `visitRenderSegmentExecution()` 做 mixed retained/live。
|
||||
|
||||
真正全局的条件仍可保持全局,例如:
|
||||
- 3D;
|
||||
- Debug 模式;
|
||||
- MapMode 不支持;
|
||||
- sprite/image/global resource 未就绪;
|
||||
- global light transition(若确实会改变所有段);
|
||||
- context/resource 失效;
|
||||
- 无法证明安全的全局状态。
|
||||
|
||||
### 9.3 不要破坏已有 source-local 机制
|
||||
|
||||
`.19/.20` 已有 `retainedSegmentSourceState()` 与 dependency-scoped revision/readiness。
|
||||
|
||||
目标应是在此基础上继续收窄 placement/global gate,而不是重新把 source/tile mutation 退回“所有 Retained 一起 invalidate”。
|
||||
|
||||
### 9.4 placement 本身若无法简单 local 化,应明确分层
|
||||
|
||||
管理员需要判断 MapLibre placement 是否存在以下区别:
|
||||
|
||||
1. Segment 完全不使用 placement:理论上是否可忽略全局 placementChanged?
|
||||
2. Segment 使用 symbol placement,但其相关 source/layer 没变化:是否仍必须 invalidate?
|
||||
3. cross-source collision / shared collision index 是否会让某 Segment 的符号像素受其他 Segment placement 影响?
|
||||
4. `symbolFadeChange` 是全局时间量还是可以按 dependency/range 推导?
|
||||
5. 是否需要一个 per-segment placement revision/fingerprint,而不是 bool?
|
||||
|
||||
如果 2/3 无法安全局部化,也至少应优先解决第 1 类,让“无 placement Retained Segment”不被无关 placement 拖死。
|
||||
|
||||
## 10. 不能牺牲的正确性约束
|
||||
|
||||
任何优化都必须保持:
|
||||
|
||||
- Style Z-order 是唯一顺序事实;
|
||||
- Segment 不重新编号 Layer 的全局 ordinal;
|
||||
- opaque/translucent/depth 语义不变;
|
||||
- retained cache 不得显示 stale 像素;
|
||||
- Camera / viewport / pixelRatio 变化仍正确 invalidation;
|
||||
- Style reload / topology change 正确释放旧 cache;
|
||||
- Android / iOS 使用同一 Shared Core 语义;
|
||||
- 不把 AIS / Route / Weather 等业务名称写进 Renderer;
|
||||
- 不要求 NavSea 手工 invalidate Native cache;
|
||||
- 不新增“只为 NavSea 绕过 Renderer”的私有 API。
|
||||
|
||||
## 11. 建议新增/补强的 Core 测试
|
||||
|
||||
至少建议覆盖:
|
||||
|
||||
### Case A:无 placement 的 R0 + 有 placement 的 R1
|
||||
- R0 stable;
|
||||
- R1 发生 placement transition;
|
||||
- 期望 R0 继续 reuse;
|
||||
- R1 单独 fallback/live;
|
||||
- 最终 Z-order 正确。
|
||||
|
||||
### Case B:两个 Retained 都稳定
|
||||
- R0/R1 均 build 一次;
|
||||
- 后续 reuse 持续增长;
|
||||
- Continuous 段持续 live。
|
||||
|
||||
### Case C:单一 source fading
|
||||
- fading source 只属于 R1;
|
||||
- R1 fallback;
|
||||
- R0 不 invalidation。
|
||||
|
||||
### Case D:Continuous source 高频 mutation
|
||||
- mutation 只属于 C1;
|
||||
- R0/R1 retained revision 不变化;
|
||||
- cache 可继续 reuse。
|
||||
|
||||
### Case E:真正全局状态
|
||||
- global light transition、3D、Debug、context/resource failure 等;
|
||||
- 继续 fail-closed;
|
||||
- 不为追求 reuse 放宽安全边界。
|
||||
|
||||
### Case F:topology 变化
|
||||
- R-C-R-C → R-C;
|
||||
- 旧 retained texture/compositor 正确释放;
|
||||
- 不 composite stale resource。
|
||||
|
||||
## 12. Diagnostics 验收要求
|
||||
|
||||
修复后 diagnostics 必须能证明“局部失败不扩散”。
|
||||
|
||||
NavSea 重新做 R-C-R-C 真机测试时,至少需要看到类似:
|
||||
|
||||
```text
|
||||
R0:
|
||||
sourceReady=true
|
||||
sourceStable=true
|
||||
cacheState=reuse
|
||||
reuse 持续增长
|
||||
|
||||
R1:
|
||||
finalDecision=fallback
|
||||
lastFallbackReason=static-placement
|
||||
|
||||
C0/C1:
|
||||
正常 live
|
||||
```
|
||||
|
||||
关键验收不是 Fast Path hit。
|
||||
|
||||
多 Continuous Segment 本来就可以继续走 full CPU mixed renderer;即使 `fastPathHit=0`,只要稳定 Retained 段能够独立 reuse,优化就是有效的。
|
||||
|
||||
## 13. 与 NavSea 最新 Trace 的关系
|
||||
|
||||
`Trace-20261007T224751.json` 是 UDP + 天气 UI 的 DevTools Trace。
|
||||
|
||||
该 Trace 中约 11–13 秒和 21–23 秒出现两组很高的 JS 峰值;调用栈显示峰值主要落在 React root work 与 `WeatherForecastStrip / WeatherTable`,其中 `WeatherTable` 两次重 render 分别约 0.91s / 1.07s,AIS decoder 并不是这两个峰值的主要执行栈。
|
||||
|
||||
代码同时显示 `WeatherForecastStrip` 会订阅 `smoothGPS`,并用经纬度 `toFixed(2)` 形成天气采样位置 key;但当前尚未完成对这两次具体 WeatherTable render 触发源的一一证明,因此本文不把“约 10 秒”直接归因于 GPS 跨格或任何单一 NavSea 机制。
|
||||
|
||||
这些 JS/UI 峰值属于 NavSea 侧独立调查项,不应作为 Particle RenderSegment 修改的直接证据。
|
||||
|
||||
Particle 本次应以 **RenderSegment diagnostics 的 R0/R1 `static-placement` 同步 fallback** 为主要证据。
|
||||
|
||||
## 14. 管理员需要给出的结论
|
||||
|
||||
请管理员审查后明确回答:
|
||||
|
||||
1. `.19/.20` 当前全局 `retainedPlacementStable` 是否确实过度保守?
|
||||
2. 对“不含 placement layer”的 Retained Segment,是否可以安全解除全局 placementChanged/symbolFadeChange 阻塞?
|
||||
3. `globalLiveFallback` 是否应去掉 placement 条件,转为 per-segment decision?
|
||||
4. 若 placement 必须部分全局,最小安全局部化边界是什么?
|
||||
5. 正式修改应基于 `release/particle.20`、合并回 `particle/main`,还是先在独立工作树完成?
|
||||
6. 是否需要新 ADR/RFC?初步判断:若公共 API/C-001 语义不变,只是 Renderer 内部优化,可不新增跨项目 Contract;若管理员认为会改变 RenderSegment 公共语义,再交回 Integration 决定。
|
||||
|
||||
## 15. 当前 NavSea 状态
|
||||
|
||||
NavSea 临时 R-C-R-C 实验已经撤回。
|
||||
|
||||
当前恢复为原有保守方案:
|
||||
|
||||
```text
|
||||
R0 [0,31) RETAINED
|
||||
C0 [31,114) CONTINUOUS
|
||||
```
|
||||
|
||||
因此管理员可以先只做 Native/Core 审查,不需要 NavSea 同步修改。
|
||||
|
||||
等 Particle 给出明确方案和可验证版本后,再由 NavSea 重新选择真实 Style 边界并做 R-C-R-C / R-C-R-C-R 真机验证。
|
||||
@@ -6,7 +6,7 @@ const marker = "// MapLibreParticleRNTestHost NavSea Particle release 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.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
project.modResults.contents += `\n${marker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
return project;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 13.4.1-particle.20(Android / iOS 统一发行)
|
||||
|
||||
- Mac unified release pipeline 统一生成 Android Native、RN package 与 iOS SwiftPM/XCFramework;共享 Particle revision 20。
|
||||
## 13.4.1-particle.19(Android / iOS 统一发行)
|
||||
|
||||
- Mac unified release pipeline 统一生成 Android Native、RN package 与 iOS SwiftPM/XCFramework;共享 Particle revision 19。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# @navsea/maplibre-particle-rn
|
||||
|
||||
当前版本:`13.4.1-particle.19`。Android Native 必须配套 `cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19`。本包是 React Native 的薄控制面,不负责 Map 组件、provider、HTTP、manifest、下载、缓存或 NavSea 业务策略。
|
||||
当前版本:`13.4.1-particle.20`。Android Native 必须配套 `cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20`。本包是 React Native 的薄控制面,不负责 Map 组件、provider、HTTP、manifest、下载、缓存或 NavSea 业务策略。
|
||||
|
||||
## 当前推荐主链:QBIN V4
|
||||
|
||||
@@ -37,7 +37,7 @@ Podfile 的 `post_install do |installer|` 必须同时调用 `$MLRN.post_install
|
||||
RN tgz:
|
||||
|
||||
```text
|
||||
https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.19.tgz
|
||||
https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.20.tgz
|
||||
```
|
||||
|
||||
Native Maven repository:
|
||||
@@ -49,7 +49,7 @@ https://pbf.jpcn.ccwu.cc/maven
|
||||
Native coordinate:
|
||||
|
||||
```text
|
||||
cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19
|
||||
cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20
|
||||
```
|
||||
|
||||
Expo plugin 与 `android/build.gradle` 必须指向同一 `.19`。正常 Consumer 不复制 AAR、不依赖 MapLibreParticleLab 源码路径,也不以 Maven Local 作为公网验证主路径。完整 Linux 发布与 Win11 验证流程见 `docs/50_Step记录/STEP-080_Android_AAR与RNTestHost标准构建流水线_v2.md`。
|
||||
Expo plugin 与 `android/build.gradle` 必须指向同一 `.20`。正常 Consumer 不复制 AAR、不依赖 MapLibreParticleLab 源码路径,也不以 Maven Local 作为公网验证主路径。完整 Linux 发布与 Win11 验证流程见 `docs/50_Step记录/STEP-080_Android_AAR与RNTestHost标准构建流水线_v2.md`。
|
||||
|
||||
@@ -14,7 +14,7 @@ android {
|
||||
dependencies {
|
||||
implementation "com.facebook.react:react-android"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.20"
|
||||
implementation "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19"
|
||||
implementation "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20"
|
||||
compileOnly project(":maplibre_maplibre-react-native")
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const iosTag = "navsea-maplibre-particle-rn-maplibre-spm";
|
||||
module.exports = function withNavSeaMapLibreParticle(config) {
|
||||
config = withProjectBuildGradle(config, (project) => {
|
||||
if (project.modResults.contents.includes(androidMarker)) return project;
|
||||
project.modResults.contents += `\n${androidMarker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
project.modResults.contents += `\n${androidMarker}\ngradle.projectsEvaluated {\n allprojects { p ->\n p.repositories.maven { repository -> repository.url = p.uri("https://pbf.jpcn.ccwu.cc/maven") }\n p.configurations.configureEach { configuration ->\n configuration.resolutionStrategy.dependencySubstitution {\n substitute module("org.maplibre.gl:android-sdk-opengl") using module("cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20")\n }\n }\n }\n}\nrootProject.ext.set("org.maplibre.reactnative.nativeVersion", "13.4.1")\nrootProject.ext.set("org.maplibre.reactnative.nativeVariant", "opengl")\n`;
|
||||
return project;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navsea/maplibre-particle-rn",
|
||||
"version": "13.4.1-particle.19",
|
||||
"version": "13.4.1-particle.20",
|
||||
"description": "NavSea MapLibre Particle React Native pure Field Renderer API.",
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1 +1 @@
|
||||
13.4.1-particle.19
|
||||
13.4.1-particle.20
|
||||
|
||||
@@ -9,8 +9,8 @@ let package = Package(
|
||||
targets: [
|
||||
.binaryTarget(
|
||||
name: "MapLibre",
|
||||
url: "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.19/MapLibre.dynamic.xcframework.zip",
|
||||
checksum: "221c069b6ca073854716799d8593784310d4f0050be9c9d9a88215b352512efd"
|
||||
url: "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.20/MapLibre.dynamic.xcframework.zip",
|
||||
checksum: "f31468a13356e7a3be10ab5308af65974f4ce2a87573ab7e699c5a1086c78ccd"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# MapLibre Particle iOS 发行
|
||||
|
||||
当前正式发行:6.28.0-particle.19
|
||||
当前正式发行:6.28.0-particle.20
|
||||
|
||||
- Renderer:Metal
|
||||
- Product / Module:MapLibre
|
||||
- Binary:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.19/MapLibre.dynamic.xcframework.zip
|
||||
- SHA-256:221c069b6ca073854716799d8593784310d4f0050be9c9d9a88215b352512efd
|
||||
- Binary:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.20/MapLibre.dynamic.xcframework.zip
|
||||
- SHA-256:f31468a13356e7a3be10ab5308af65974f4ce2a87573ab7e699c5a1086c78ccd
|
||||
- SwiftPM:https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git
|
||||
- Exact Version:6.28.0-particle.19
|
||||
- Source Commit:7c5ed27b0b3ae5fe74ab245cbef9dabf913dde4f
|
||||
- Exact Version:6.28.0-particle.20
|
||||
- Source Commit:a4c6047d7092523ad8aa6c14cb2b2246f4a88b8d
|
||||
|
||||
构建命令固定为:
|
||||
|
||||
bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
|
||||
不得用默认 OpenGL XCFramework 覆盖同版本。新版本必须使用新的 Particle revision。
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"status": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"distributionVersion": "6.28.0-particle.19",
|
||||
"distributionVersion": "6.28.0-particle.20",
|
||||
"moduleName": "MapLibre",
|
||||
"compilationMode": "opt",
|
||||
"artifact": {
|
||||
"fileName": "MapLibre.dynamic.xcframework.zip",
|
||||
"sizeBytes": 8480397,
|
||||
"sha256": "221c069b6ca073854716799d8593784310d4f0050be9c9d9a88215b352512efd",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.19/MapLibre.dynamic.xcframework.zip"
|
||||
"sizeBytes": 4119687,
|
||||
"sha256": "f31468a13356e7a3be10ab5308af65974f4ce2a87573ab7e699c5a1086c78ccd",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.20/MapLibre.dynamic.xcframework.zip"
|
||||
},
|
||||
"sourceCommit": "7c5ed27b0b3ae5fe74ab245cbef9dabf913dde4f",
|
||||
"sourceCommit": "a4c6047d7092523ad8aa6c14cb2b2246f4a88b8d",
|
||||
"swiftPackage": {
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git",
|
||||
"requirement": "exactVersion",
|
||||
"version": "6.28.0-particle.19",
|
||||
"version": "6.28.0-particle.20",
|
||||
"productName": "MapLibre"
|
||||
},
|
||||
"notes": "Metal renderer release built with bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
"notes": "Metal renderer optimized release built with bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
}
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"releaseState": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"particleRevision": 19,
|
||||
"sourceCommit": "7c5ed27b0b3ae5fe74ab245cbef9dabf913dde4f",
|
||||
"generatedAtUtc": "2026-10-07T07:17:04.530231+00:00",
|
||||
"particleRevision": 20,
|
||||
"sourceCommit": "a4c6047d7092523ad8aa6c14cb2b2246f4a88b8d",
|
||||
"generatedAtUtc": "2026-10-07T12:35:15.522160+00:00",
|
||||
"reactNative": {
|
||||
"name": "@navsea/maplibre-particle-rn",
|
||||
"version": "13.4.1-particle.19",
|
||||
"version": "13.4.1-particle.20",
|
||||
"artifact": {
|
||||
"fileName": "navsea-maplibre-particle-rn-13.4.1-particle.19.tgz",
|
||||
"sizeBytes": 28825,
|
||||
"sha256": "c98f1aef868c671a99556dbdd2518cdaa3a88a3d6133e620e5e8a38080d19b1a",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.19.tgz"
|
||||
"fileName": "navsea-maplibre-particle-rn-13.4.1-particle.20.tgz",
|
||||
"sizeBytes": 28827,
|
||||
"sha256": "fdc19f62cc2ab3c5bd521faa202d05ca69b17057c1afb5d8ce5e15722cc13c58",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/npm/navsea-maplibre-particle-rn-13.4.1-particle.20.tgz"
|
||||
},
|
||||
"mapLibreReactNative": "11.3.6"
|
||||
},
|
||||
"android": {
|
||||
"version": "13.4.1-particle.19",
|
||||
"coordinate": "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.19",
|
||||
"version": "13.4.1-particle.20",
|
||||
"coordinate": "cc.navsea.maplibre:android-sdk-particle-opengl:13.4.1-particle.20",
|
||||
"renderer": "opengl",
|
||||
"artifact": {
|
||||
"fileName": "android-sdk-particle-opengl-13.4.1-particle.19.aar",
|
||||
"sizeBytes": 170726451,
|
||||
"sha256": "8ef9de51564aad6d5d8a9678534120cee34d3ee65c41f9f266c29bf057029712",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/13.4.1-particle.19/android-sdk-particle-opengl-13.4.1-particle.19.aar"
|
||||
"fileName": "android-sdk-particle-opengl-13.4.1-particle.20.aar",
|
||||
"sizeBytes": 170731109,
|
||||
"sha256": "213924d5970a83ce953b7a2be908cfb72419127e8d10cb36949681f7dac16844",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/maven/cc/navsea/maplibre/android-sdk-particle-opengl/13.4.1-particle.20/android-sdk-particle-opengl-13.4.1-particle.20.aar"
|
||||
},
|
||||
"ndk": "28.2.13676358",
|
||||
"gradle": "9.5.1",
|
||||
"jdk": "openjdk version \"17.0.20.1\" 2026-08-18"
|
||||
},
|
||||
"ios": {
|
||||
"distributionVersion": "6.28.0-particle.19",
|
||||
"distributionVersion": "6.28.0-particle.20",
|
||||
"renderer": "metal",
|
||||
"compilationMode": "opt",
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": {
|
||||
"fileName": "MapLibre.dynamic.xcframework.zip",
|
||||
"sizeBytes": 8480397,
|
||||
"sha256": "221c069b6ca073854716799d8593784310d4f0050be9c9d9a88215b352512efd",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.19/MapLibre.dynamic.xcframework.zip"
|
||||
"sizeBytes": 4119687,
|
||||
"sha256": "f31468a13356e7a3be10ab5308af65974f4ce2a87573ab7e699c5a1086c78ccd",
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle/6.28.0-particle.20/MapLibre.dynamic.xcframework.zip"
|
||||
},
|
||||
"swiftPackage": {
|
||||
"url": "https://pbf.jpcn.ccwu.cc/swift/maplibre-particle-spm.git",
|
||||
"requirement": "exactVersion",
|
||||
"version": "6.28.0-particle.19",
|
||||
"version": "6.28.0-particle.20",
|
||||
"productName": "MapLibre"
|
||||
},
|
||||
"xcode": "Xcode 26.3 Build version 17C529 ",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
- CMake 3.31.6
|
||||
- Android renderer:OpenGL
|
||||
- iOS renderer:Metal
|
||||
- iOS binary build:bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic(仅真机 ios-arm64,不包含 Simulator slice)
|
||||
- iOS binary build:bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic(正式优化构建;仅真机 ios-arm64,不包含 Simulator slice)
|
||||
|
||||
## 发布目标
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ def main() -> None:
|
||||
"ios": {
|
||||
"distributionVersion": ios_version,
|
||||
"renderer": "metal",
|
||||
"compilationMode": "opt",
|
||||
"moduleName": "MapLibre",
|
||||
"artifact": ios,
|
||||
"swiftPackage": {
|
||||
@@ -116,12 +117,13 @@ def main() -> None:
|
||||
"status": "PUBLISHED_PUBLIC_READBACK_PASS",
|
||||
"distributionVersion": ios_version,
|
||||
"moduleName": "MapLibre",
|
||||
"compilationMode": "opt",
|
||||
"artifact": ios,
|
||||
"sourceCommit": source_commit,
|
||||
"swiftPackage": manifest["ios"]["swiftPackage"],
|
||||
"notes": (
|
||||
"Metal renderer release built with "
|
||||
"bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
"Metal renderer optimized release built with "
|
||||
"bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic"
|
||||
),
|
||||
}
|
||||
(ROOT / "release/maplibre-particle/ios/release-manifest.json").write_text(
|
||||
@@ -163,7 +165,7 @@ let package = Package(
|
||||
|
||||
构建命令固定为:
|
||||
|
||||
bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic
|
||||
|
||||
不得用默认 OpenGL XCFramework 覆盖同版本。新版本必须使用新的 Particle revision。
|
||||
"""
|
||||
|
||||
@@ -98,10 +98,11 @@ build_release() {
|
||||
cp "$M2_DIR/$f" "$ARTIFACT_DIR/"
|
||||
done
|
||||
|
||||
note "building iOS Metal XCFramework"
|
||||
(cd "$ROOT" && bazel build --//:renderer=metal //platform/ios:MapLibre.dynamic)
|
||||
IOS_SOURCE="$ROOT/bazel-out/darwin_x86_64-fastbuild/bin/platform/ios/$IOS_ZIP_NAME"
|
||||
[[ -f "$IOS_SOURCE" ]] || die "iOS XCFramework zip missing"
|
||||
note "building iOS Metal XCFramework (Bazel opt)"
|
||||
(cd "$ROOT" && bazel build -c opt --//:renderer=metal //platform/ios:MapLibre.dynamic)
|
||||
IOS_SOURCE="$ROOT/bazel-out/darwin_x86_64-opt/bin/platform/ios/$IOS_ZIP_NAME"
|
||||
[[ "$IOS_SOURCE" == *"-opt/"* ]] || die "iOS release artifact is not from Bazel opt output: $IOS_SOURCE"
|
||||
[[ -f "$IOS_SOURCE" ]] || die "iOS XCFramework zip missing: $IOS_SOURCE"
|
||||
local ios_listing
|
||||
ios_listing="$(unzip -Z1 "$IOS_SOURCE")"
|
||||
grep -Fq "/ios-arm64/" <<<"$ios_listing" || die "iOS XCFramework missing ios-arm64 device slice"
|
||||
|
||||
Reference in New Issue
Block a user