feat: diagnose WeatherRuntime bridge attach state

This commit is contained in:
OpenAI Codex
2026-09-08 17:46:20 +08:00
parent d1b1e890ac
commit c8030581b5
4 changed files with 74 additions and 7 deletions

View File

@@ -12,7 +12,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"
implementation "org.maplibre.gl:android-sdk-opengl:13.4.1-step060d"
// RN autolinking names the scoped MLRN Android project deterministically. The app owns the
// runtime dependency; this module only needs its public MLRNMapView type at compile time.
compileOnly project(":maplibre_maplibre-react-native")

View File

@@ -12,6 +12,7 @@ import com.facebook.react.uimanager.IllegalViewOperationException
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.common.UIManagerType
import org.maplibre.android.maps.MapLibreMap
import org.maplibre.android.maps.Style
import org.maplibre.android.maps.WeatherRuntime
import org.maplibre.reactnative.components.mapview.MLRNMapView
@@ -24,8 +25,21 @@ 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")
if (style.getSource(WeatherIds.SOURCE) == null || style.getLayer(WeatherIds.COLOR_LAYER) == null || style.getLayer(WeatherIds.PARTICLE_LAYER) == null) {
return@withMapView reject(promise, "WEATHER_OBJECTS_NOT_READY", "The Test Host weather source/layers are absent from the current style")
val sourceExists = style.getSource(WeatherIds.SOURCE) != null
val weatherColorLayerExists = style.getLayer(WeatherIds.COLOR_LAYER) != null
val particleLayerExists = style.getLayer(WeatherIds.PARTICLE_LAYER) != null
if (!sourceExists || !weatherColorLayerExists || !particleLayerExists) {
return@withMapView reject(
promise,
"WEATHER_OBJECTS_NOT_READY",
weatherObjectsNotReadyDiagnostic(
reactTag.toInt(),
style,
sourceExists,
weatherColorLayerExists,
particleLayerExists,
),
)
}
val runtime = map.replaceWeatherRuntime(WeatherRuntime.Config(WeatherIds.SOURCE, WeatherIds.COLOR_LAYER, WeatherIds.PARTICLE_LAYER))
// MLRN drops its MapView by detaching it. This listener captures only that concrete map,
@@ -126,7 +140,60 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
private fun snapshot(runtime: WeatherRuntime) = Arguments.createMap().apply {
putString("state", runtime.state.name); putString("playbackState", runtime.playbackState.name); putString("targetFps", runtime.targetFps.name); putBoolean("disposed", runtime.isDisposed)
}
/**
* 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.
*/
private fun weatherObjectsNotReadyDiagnostic(
reactTag: Int,
style: Style,
sourceExists: Boolean,
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(" 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" }
companion object { const val NAME = "WeatherRuntimeBridge" }
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
}
}

View File

@@ -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.clear()\n p.repositories.mavenLocal()\n p.repositories.google()\n p.repositories.mavenCentral { content { excludeModule(\"org.maplibre.gl\", \"android-sdk-opengl\") } }\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.clear()\n p.repositories.mavenLocal()\n p.repositories.google()\n p.repositories.mavenCentral { content { excludeModule(\"org.maplibre.gl\", \"android-sdk-opengl\") } }\n }\n}\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVersion\", \"13.4.1-step060d\")\nrootProject.ext.set(\"org.maplibre.reactnative.nativeVariant\", \"opengl\")\n`;
return project;
});
};

View File

@@ -1 +1 @@
13.4.1
13.4.1-step060d