Problem
MapProviderConfigurationError (package/ios/GoogleMapsAPIKey.swift:28-43) is a
LocalizedError whose errorDescription strings tell the consumer exactly what to
configure:
case .missingGoogleMapsIosApiKey:
return "react-native-better-maps: provider=\"google\" on iOS requires GoogleMapsIosApiKey in the host app Info.plist."
That text reaches the placeholder view correctly, because UnavailableMapProviderAdapter.init
reads error.localizedDescription (package/ios/MapProviderAdapter.swift:101).
It never reaches JS. The same error object goes back through Promise.rejected(withError:)
and throw (package/ios/MapProviderAdapter.swift:117-139), and Nitro converts every Swift
Error with String(describing:) (react-native-nitro-modules/ios/core/RuntimeError.swift:41-44):
extension Error {
public func toCpp() -> std.exception_ptr {
let message = String(describing: self) // <- not localizedDescription
return margelo.nitro.makeException(std.string(message))
}
}
String(describing:) consults CustomStringConvertible first and otherwise falls back to
reflection. LocalizedError provides neither, so the enum reflects to its case name.
Verified by running the enum standalone under swift:
String(describing:) -> missingGoogleMapsIosApiKey
localizedDescription -> react-native-better-maps: provider="google" on iOS requires GoogleMapsIosApiKey in the host app Info.plist.
String(describing:) -> unsupportedIOSProvider("mapbox")
So a consumer whose Info.plist key is missing gets Error: missingGoogleMapsIosApiKey
instead of the sentence that says what to add and where — while the placeholder view on
screen shows the correct sentence at the same moment.
This is specific to MapProviderConfigurationError. The rest of the Swift layer throws
RuntimeError (package/ios/HybridMapView.swift:359), which does conform to
CustomStringConvertible, so "MapView is not mounted" survives intact. Android has no
equivalent problem — it throws IllegalStateException carrying the full sentence
(package/android/src/main/java/com/margelo/nitro/nitromaps/HybridMapView.kt:383).
Affected surfaces
Every MapViewRef method, whenever the iOS provider could not be created:
| Path |
Message JS sees today |
GoogleMapsIosApiKey missing from Info.plist |
missingGoogleMapsIosApiKey |
Google Maps SDK not linked (#if canImport(GoogleMaps) false) |
googleMapsSdkNotLinked |
provider="openstreetmap" / "mapbox" on iOS |
unsupportedIOSProvider(...) |
Reached through getCamera, setCamera, animateCamera, getVisibleRegion and
fitToCoordinates — all five route through UnavailableMapProviderAdapter
(package/ios/HybridMapView.swift:375-396).
Reproduction
- iOS app with the Google Maps SDK linked but no
GoogleMapsIosApiKey in Info.plist.
- Render
<MapView provider="google" ref={mapRef} />.
mapRef.current.getCamera().catch((e) => console.log(e.message)).
- Now:
missingGoogleMapsIosApiKey
- Expected:
react-native-better-maps: provider="google" on iOS requires GoogleMapsIosApiKey in the host app Info.plist.
The on-screen placeholder renders the correct sentence at the same time, which makes the
mismatch easy to confirm side by side.
Fix direction
One conformance, no call-site changes:
enum MapProviderConfigurationError: LocalizedError, CustomStringConvertible {
// ...
var description: String { errorDescription ?? "Map provider configuration failed." }
}
String(describing:) then picks up description, so the placeholder label and the JS error
carry the same text.
The alternative — throwing RuntimeError(...) with the message baked in — also works, but
loses the typed cases and the errorDescription the placeholder view relies on.
Acceptance criteria
Regression tests
XCTest in package/iosTests/ (already wired through the podspec test spec,
package/react-native-better-maps.podspec:70): assert
String(describing: error) == error.localizedDescription for every case. That is exactly
the property Nitro relies on, and it needs no map instance.
Notes
Whether Nitro should prefer localizedDescription for LocalizedError is worth raising
upstream, but that is a margelo/nitro change and this repo should not wait on it.
Problem
MapProviderConfigurationError(package/ios/GoogleMapsAPIKey.swift:28-43) is aLocalizedErrorwhoseerrorDescriptionstrings tell the consumer exactly what toconfigure:
That text reaches the placeholder view correctly, because
UnavailableMapProviderAdapter.initreads
error.localizedDescription(package/ios/MapProviderAdapter.swift:101).It never reaches JS. The same error object goes back through
Promise.rejected(withError:)and
throw(package/ios/MapProviderAdapter.swift:117-139), and Nitro converts every SwiftErrorwithString(describing:)(react-native-nitro-modules/ios/core/RuntimeError.swift:41-44):String(describing:)consultsCustomStringConvertiblefirst and otherwise falls back toreflection.
LocalizedErrorprovides neither, so the enum reflects to its case name.Verified by running the enum standalone under
swift:So a consumer whose
Info.plistkey is missing getsError: missingGoogleMapsIosApiKeyinstead of the sentence that says what to add and where — while the placeholder view on
screen shows the correct sentence at the same moment.
This is specific to
MapProviderConfigurationError. The rest of the Swift layer throwsRuntimeError(package/ios/HybridMapView.swift:359), which does conform toCustomStringConvertible, so"MapView is not mounted"survives intact. Android has noequivalent problem — it throws
IllegalStateExceptioncarrying the full sentence(
package/android/src/main/java/com/margelo/nitro/nitromaps/HybridMapView.kt:383).Affected surfaces
Every
MapViewRefmethod, whenever the iOS provider could not be created:GoogleMapsIosApiKeymissing fromInfo.plistmissingGoogleMapsIosApiKey#if canImport(GoogleMaps)false)googleMapsSdkNotLinkedprovider="openstreetmap"/"mapbox"on iOSunsupportedIOSProvider(...)Reached through
getCamera,setCamera,animateCamera,getVisibleRegionandfitToCoordinates— all five route throughUnavailableMapProviderAdapter(
package/ios/HybridMapView.swift:375-396).Reproduction
GoogleMapsIosApiKeyinInfo.plist.<MapView provider="google" ref={mapRef} />.mapRef.current.getCamera().catch((e) => console.log(e.message)).missingGoogleMapsIosApiKeyreact-native-better-maps: provider="google" on iOS requires GoogleMapsIosApiKey in the host app Info.plist.The on-screen placeholder renders the correct sentence at the same time, which makes the
mismatch easy to confirm side by side.
Fix direction
One conformance, no call-site changes:
String(describing:)then picks updescription, so the placeholder label and the JS errorcarry the same text.
The alternative — throwing
RuntimeError(...)with the message baked in — also works, butloses the typed cases and the
errorDescriptionthe placeholder view relies on.Acceptance criteria
MapViewRefcall on an unavailable iOS provider carries the same sentencethe placeholder view renders
unsupportedIOSProviderRegression tests
XCTest in
package/iosTests/(already wired through the podspec test spec,package/react-native-better-maps.podspec:70): assertString(describing: error) == error.localizedDescriptionfor every case. That is exactlythe property Nitro relies on, and it needs no map instance.
Notes
Whether Nitro should prefer
localizedDescriptionforLocalizedErroris worth raisingupstream, but that is a
margelo/nitrochange and this repo should not wait on it.