feat: diagnose WeatherRuntime bridge attach state
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user