Resupply fork: Mapbox Navigation SDK v3 (vendored binaries) + customization & truck-routing props#50
Open
stefanpavlovic-tech wants to merge 36 commits into
Open
Conversation
Migrates the iOS module from Nav SDK v2 → v3 so it can coexist with @rnmapbox/maps' MapboxMaps v11 (v2 pinned MapboxMaps v10 → CocoaPods conflict). ios/MapboxNavigationView.swift — v2 → v3 API: - import MapboxNavigationCore + MapboxNavigationUIKit (was MapboxNavigation/MapboxCoreNavigation) - MapboxNavigationProvider(coreConfig:) replaces Directions.shared + NavigationSettings.shared - routingProvider().calculateRoutes(options:) (async, await .result) replaces the v2 closure - NavigationViewController(navigationRoutes:navigationOptions:); NavigationOptions now requires mapboxNavigation:/voiceController:/eventsManager: - mute via provider.routeVoiceController.speechSynthesizer.muted (NavigationSettings removed) - simulation via CoreConfig.locationSource (.simulation/.live) - didArriveAt delegate returns Void (v3 breaking change); fixed lng/lat swap in onArrive - travelMode → ProfileIdentifier; heading now from location.course react-native-mapbox-navigation.podspec — SPM injection (mirrors @rnmapbox/maps $RNMapboxMaps): - drop `s.dependency 'MapboxNavigation' ~> 2.18.1` (no v3 CocoaPods pod exists) - add $RNMapboxNavigation pre_install/post_install hooks for the host Podfile to call; default SPM version exactVersion 3.20.1 (pins MapboxMaps 11.20.2 — matches @rnmapbox/maps 10.3.1) - post_install adds the SPM package + MapboxNavigationCore/UIKit products to BOTH the pod target (so the pod's Swift compiles) AND the user app target (so they link) Paper RCTViewManager structure kept (works under New Arch via interop). Based on the v3 migration verified against mapbox/navigation-ios; SPM-injection pattern adapted from upstream's unreleased v0.6 branch (whose iOS Swift was never completed). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… consumption Consuming this fork as a git dependency requires the built lib/ (the package `main`/`module` point at lib/commonjs + lib/module). pnpm's git-dep prepare sandbox didn't reliably run bob build, so commit the prebuilt output and rename the `prepare` script to `build` — installs now use the committed lib/ deterministically instead of a clean-and-rebuild that can fail in CI/sandboxes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v3's MapboxDirections.Waypoint is a value type (was a class in v2), so a 'let' binding can't have separatesLegs mutated. Verified by headless compile against Nav SDK 3.20.1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…(Path C) Replaces the SPM-injection podspec with direct vendoring of Mapbox's prebuilt binary xcframeworks (mapbox-navigation-ios-build-artifacts @ 3.20.1). The SPM "duplicate symbol" wall was a misdiagnosis: MapboxNavigationCore/UIKit/Helpers are distributed as binaries, not source. Vendoring them + sharing the CocoaPods MapboxMaps pod (deduped by name with @rnmapbox/maps) dissolves the trilemma, needs no use_frameworks!, and removes the headless-SPM-resolution hang. - podspec: vendored_frameworks ios/Frameworks/*.xcframework, static_framework, s.dependency MapboxMaps 11.20.2, non-recursive source_files (an exclude_files pattern would also strip the vendored frameworks → "no such module"). - Binaries are NOT committed (Mapbox ToS / size / token-gated) — the host app fetches them on demand into ios/Frameworks/ (gitignored). Verified: headless xcodebuild link BUILD SUCCEEDED, zero duplicate symbols, all 10 Mapbox/nav frameworks embedded exactly once. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…5 codegen - build.gradle: bump com.mapbox.navigationcore 3.0.2 → 3.20.1 and mirror @rnmapbox/maps' NDK 27 variant selection (targetSdk >= 35 → -ndk27 artifacts). 3.0.2 pulled maps 11.3.1 / common 24.3.1 (non-ndk27), which duplicated classes against rnmapbox's android-ndk27 11.20.2 world; 3.20.1 ndk27 resolves to the same maps 11.20.2 / common-ndk27 24.20.2 artifacts — and matches the iOS vendored binaries' versions. - ViewManager: New Arch codegen requires set<PropName> method names from the TS spec — rename setDirectionUnit→setDistanceUnit, setLocal→setLanguage, and add the missing overrides (setSeparateLegs, setShouldSimulateRoute, setShowsEndOfRouteFeedback, setHideStatusView) as documented no-ops (per-waypoint separatesLegs covers legs; the rest are iOS-only). - oldarch spec: mirror the renamed/new abstract methods so both architectures compile against the same concrete manager. Verified: app assembleDebug BUILD SUCCESSFUL; dependencyInsight shows a single com.mapbox.common:common-ndk27:24.20.2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…onent spec The exports map sent Metro to the prebuilt lib/module .mjs, where babel-plugin-codegen intercepts *NativeComponent.mjs but the type-stripped build has no parsable spec → "Could not find component config for native component" at bundle time. Drop the exports map and add the classic react-native main field pointing at src/ (Metro resolverMainFields: ['react-native', 'browser', 'main']) — Metro bundles the typed TS source (codegen succeeds); Node tooling keeps main → lib/commonjs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Events (onCancelNavigation, onArrive, onError, onLocationChange,
onRouteProgressChange) were declared only via an
`as HostComponent<NativeProps & NativeEventsProps>` cast — under the New
Architecture the Fabric view config is generated from the codegen spec, so
ZERO events were registered and every callback was silently dropped (the
cancel ✕ did nothing). Declare them as DirectEventHandler fields inside
NativeProps.
theme prop ('day' | 'night' | 'auto', default auto):
- iOS: explicit themes pin StandardDayStyle/StandardNightStyle via
NavigationOptions(styles:) and re-apply live on prop change through the
VC's StyleManager; auto keeps the SDK's time-of-day switching.
- Android: loads NAVIGATION_NIGHT_STYLE for 'night' (day otherwise), live
reload on prop change; manager + oldarch spec updated.
- lib/ rebuilt (bob) so the committed typescript defs include the new prop.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…down Navigation init was triggered from the distanceUnit prop setter — props apply in alphabetical order, so `distanceUnit` landed before `startOrigin` and initNavigation() bailed with "origin and destination are required" on every mount; JS reacted to the error by unmounting, and onDestroy() then crashed on the never-initialized lateinit nav APIs (kotlin.UninitializedPropertyAccessException: maneuverApi). - Manager: onAfterUpdateTransaction → view.initIfReady() — runs after ALL props of the batch are applied; starts navigation exactly once when both endpoints are present. - setDirectionUnit: stores the unit only, no init. - onDestroy: tear down only what was initialized (::isInitialized guards for the lateinit APIs, navigationInitialized for the session-bound ones). - setTheme live-reload now keys off navigationInitialized (mapboxNavigation is created in onCreate, so the old null-check was always true). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… report button) Add four opt-in props so a host app can match the nav UI to its own design without baking anything app-specific into the fork. All default to current SDK behavior when unset. - styleUrl: load a custom Mapbox style URI. iOS uses ResupplyDay/NightStyle (subclass DayStyle/NightStyle, which inherit Style.applyMapStyle so mapStyleURL is honored — Standard styles force the SDK style). Android styleForTheme() returns it. Falls back to the SDK navigation style. - fontFamily: nav-label font family. iOS Style.fontFamily; Android no-op (maneuver banner uses a build-time textAppearance, no runtime font-by-name). - bottomInset: extra bottom camera padding so the route/puck clear an app overlay. iOS overrides only the bottom edge of viewportPadding; Android adds to the base overview/following padding. - showsReportFeedback: toggle the iOS report-issue floating button (default true = SDK default); keeps overview/recenter/mute. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The published package resolves types from the prebuilt lib/typescript; rebuild it (bob build) so styleUrl / fontFamily / bottomInset / showsReportFeedback are present for consumers. Pairs with the previous source commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire Mapbox Directions vehicle-dimension constraints end-to-end so callers can request truck-aware routes (avoid low bridges / narrow / weight-restricted roads). Previously vehicleMaxHeight/Width were declared on iOS but dead (unregistered in the ViewManager, never applied to RouteOptions) and Android had no support at all. - iOS: declare vehicleMaxWeight; apply all three to NavigationRouteOptions via the typed maximumHeight/Width/Weight (Measurement, .meters/.metricTons), only when provided; register the three props in the ObjC ViewManager. - Android: store the three as Double fields + setters; chain maxHeight()/maxWidth()/maxWeight() onto RouteOptions.builder() only when > 0; add @ReactProp overrides. - JS: add props to the codegen spec (New-Arch Fabric registration) and the public MapboxNavigationProps; rebuild lib/. Units match the Directions API: height/width in meters, weight in metric tons. Omitted / 0 = the API's car-sized defaults (1.6 m / 1.9 m / 2.5 t). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The README props section was upstream's and listed none of the props this fork added. Add a "Resupply fork additions" subsection covering theme, styleUrl, fontFamily, bottomInset, showsReportFeedback, and the truck-routing trio (vehicleMaxHeight/Width/Weight — meters / metric tons, with their car-sized defaults when unset). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
showCancelButton was declared + exported to JS but never applied — the setup wired showsReportFeedback/showsEndOfRouteFeedback/hideStatusView/ theme and silently dropped it, so the SDK's bottom-banner cancel (X) always showed. Apply it: when showCancelButton is false (the default), pass a BottomBannerViewController subclass that hides its cancelButton in viewDidLoad, keeping the ETA / distance / arrival banner. Host apps that provide their own exit control no longer get a duplicate cancel button. Subclassing is the timing-safe way to hide it — cancelButton is an IUO that only exists post-viewDidLoad — and the SDK still wires the subclass for progress (onRouteProgressUpdated) the same as the default banner. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anner Hiding only the cancel button left its empty layout slot plus the vertical divider line, so the arrival-time label sat mid-banner with dead space on the right. Also hide the vertical divider and zero both views' self-width constants so the arrival-time label (chained to divider → cancel) slides to the trailing edge. Constraint-safe — no constraints added/removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapsing widths didn't move the arrival-time label — the cancel button has no width constraint (intrinsic size) and the label isn't chained to it. Instead, deactivate the arrival-time label's horizontal constraints and re-pin its trailing edge to the banner trailing (centerY kept), so it fills the space the hidden cancel button left. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a `vehicleType` prop ('van'|'truck'|'box_truck'|'cargo_van') that
swaps the location puck for a bundled per-vehicle icon (silhouette as the
bearing image so it rotates to the travel course); empty/unknown keeps the
SDK default puck. Also replaces the SDK's default destination marker with
the app's donor pin via the didAdd finalDestinationAnnotation delegate, so
the embedded nav matches the donation pins on the app's other maps.
Assets are placeholder PNGs (designer-replaceable — same filenames in
ios/Assets/ = drop-in swap) bundled via a new resource_bundle; the donor
pin is rasterized from the app's en-route donation pin. SVG sources kept
under ios/Assets/src/. iOS only — Android Drop-In UI puck/marker is a
follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move icon ownership out of the SDK and into the host app. Drop the
bundled placeholder PNGs + resource_bundle + the hardcoded vehicleType→
image switch. Replace with two host-supplied image-source props,
`puckImage` and `destinationImage` (RCTConvert→UIImage): puckImage is
applied as the location puck's bearing image; destinationImage replaces
the SDK's destination marker via the didAdd finalDestinationAnnotation
delegate. Either omitted = the SDK default.
The app now owns the {vehicleType: image} catalog and the donor pin, so
designers iterate on art in the app without a fork rebuild. ImageSource is
imported from a local module so RN codegen name-matches it to the reserved
image primitive (a local alias would resolve to a plain object) while
staying typecheck-safe against the pinned RN. iOS only — Android follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The puckImage/destinationImage UIImage props arrived nil in dev: RCTConvert can't load Metro's http asset URIs into a UIImage, so the puck/destination fell back to SDK defaults (only a release build would have worked). Switch to puckImageUri/destinationImageUri string props and load them natively — URLSession for http (dev), filesystem for file:// (release), bundle for a bare name — caching the UIImage and (re)applying the puck + destination annotation whenever the async load lands. Drops the codegen ImageSource type (and its local shim) entirely. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Android parity for the puckImageUri / destinationImageUri props. Load each URI to a Bitmap via Fresco (RN's pipeline — handles Metro-dev http and release res:// / file://), then: swap the location puck's bearing image (LocationPuck2D + ImageHolder.from(bitmap)), and drop a PointAnnotation at the destination with the donor pin (created in the loadStyle callback so the style is ready). Default puck/marker kept when no URI / load fails. Setters re-apply live once nav is up. oldarch spec left as-is (stale; app is New Arch — manager overrides the codegen interface). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two fix attempts (UIImage prop, then URI loader) still show default pins; codegen is confirmed current (props are in the generated Fabric spec), so the break is downstream. Log each step (prop arrival, image load result, puck apply, destination delegate fire + apply) under the 🧭RSPLNav tag to localize it from one run. To be reverted once diagnosed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Force an obvious red-car system image onto the puck (incl. a delayed re-apply to rule out the SDK overriding it on start) and the destination annotation, bypassing host-image loading — so we can tell ON-SCREEN whether the apply path works without needing native logs. Red car = apply works (bug is image loading); still-default = the apply API/timing is the problem. Bump the package version so CocoaPods detects the change and recompiles the pod on `expo run:ios` — the commit SHA alone doesn't change the pod version string, so incremental builds were silently keeping stale fork binaries. Temporary diagnostic; to be reverted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…agnostic Replace the 2D puck-image approach with a 3D model puck. New puckModelUri prop (a .glb/.gltf URI, local or remote) renders via Puck3DConfiguration (iOS) / LocationPuck3D (Android); the SDK fetches the model directly so there's no host-side image loading. puckBearing=.course turns it with travel. Empty URI keeps the SDK default 2D puck. Model scale is a tunable constant (80) — model-dependent. The diagnostic red-car probe confirmed the puck APPLY path works (it changed the puck), so the prior failure was the 2D image never loading; the 3D model URI sidesteps that. Diagnostic logging/code removed. The donor destination pin (destinationImageUri, 2D) is unchanged. Bump 0.5.5. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The custom location puck / donor destination pin never rendered reliably across five approaches (2D UIImage prop, 2D URI loader, Android Fresco, and 3D model) — each hit a different native loading/rendering wall, and it's polish nobody requested. Revert the icon source files to the banner-fix baseline (e5b9a69): the embedded nav uses the SDK's default puck + marker. Keeps the cancel-button + arrival-time banner work. Bump 0.5.6 so the pod recompiles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Day-mode maneuver banner: white bg + dark text + dark turn-arrow (theme-aware;
night keeps the SDK dark banner). Full-width banner; fill top corners white.
- Lane guidance: active lane renders dark (matches iOS), inactive stay faded.
- Puck above the route line: place route below "road-label-simple" — the actual
road-label layer id in the app's light-v11/dark-v11 styles ("road-label" and
the nav-only "road-label-navigation" don't exist there, so the route fell to
the top of the stack over the puck).
- Route arrow above the route-line top layer (withAboveLayerId).
- Start in follow mode instead of route overview, like iOS.
- Hide the compass ornament during guidance.
- Keep Mapbox logo + attribution visible (ToS): logo bottom-left, info
bottom-right, lifted above the bottom sheet.
- Add explicit maps-logo / maps-attribution plugin deps (not reliably on the
module compile classpath otherwise).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add MapboxSpeedInfoView (top-left, mirrors iOS placement) driven by MapboxSpeedInfoApi from the existing LocationObserver; MUTCD sign style; visibility wired to route start/teardown. - Codegen: numeric props (vehicleMax*/bottomInset) Double -> WithDefault<Double,0> so the generated delegate param matches the non-null `value: Double` manager overrides (a bare optional Double generated a nullable param that would not compile against the overrides — never built because node_modules was stale). - iOS: treat 0 as unset on truck dims (> 0 guard) so a WithDefault 0 can't set maximumHeight = 0 m and reject every road. - Rebuild lib/ (bob build). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…imental options) Caught by a local Android build of the previous commit: - updatePostedAndCurrentSpeed() returns SpeedInfoValue? (nullable) — null-guard before render() (which takes non-null). - Drop setSpeedInfoOptions(...) — the symbol is unresolved on MapboxSpeedInfoView and MapboxSpeedInfoOptions.Builder needs @ExperimentalPreviewMapboxNavigationAPI opt-in. The view auto-selects the sign convention from road data (MUTCD for the US fleet), so the default is correct without forcing it. - Remove now-unused SpeedLimitSign / MapboxSpeedInfoOptions imports. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
iOS shows the built-in SpeedLimitView (posted limit + current-speed overspeed warning, showsSpeedLimits defaults true) but HIDES the sign when the posted limit is unknown — so on sparse/simulated routes it appears blank/absent. Add an `alwaysShowSpeedLimit` prop: iOS sets speedLimitView.shouldShowUnknownSpeedLimit (and showsSpeedLimits = true explicitly). The app passes true outside production (visible during testing) and false in production (no blank signs on rural roads). Android no-op — its speed-info badge is already shown and data-driven. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NavigationViewController has no `speedLimitView`; it's on the root NavigationView (NavigationViewController.navigationView.speedLimitView). Caught by an iOS build of the previous commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T2 of the offline-nav milestone — the offline-reroute foundation. iOS: state the CoreConfig routing/tilestore config explicitly in embed() (routingProviderSource .hybrid + detectsReroute + tilestoreConfig .default + predictiveCacheConfig). These are the v3 defaults, made explicit so the offline intent is pinned across SDK bumps. .default shares TileStore.default with @rnmapbox/maps automatically. Android: default NavigationOptions uses a private nav-tiles path, so set RoutingTilesOptions.tileStore(TileStore.create()) on the first provider create() to share the same default store @rnmapbox/maps uses. With this, once a corridor region is downloaded into the default store (T4), the on-board router reroutes locally with no connectivity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T3 of the offline-nav milestone — the codegen + TS half (native impls follow). - codegenConfig.type "components" -> "all" so codegen emits a TurboModule spec alongside the existing MapboxNavigationView component spec. - src/NativeMapboxNavigationOffline.ts: TurboModule spec (downloadRegion / listRegions / removeRegion / clearAllRegions + addListener/removeListeners). Codegen-legal types only (Object across the bridge). - src/types.ts: OfflineRegionOptions / OfflineRegion / OfflineRegionDownloadProgressEvent + OfflineRegionStatus — the typed shapes the facade exposes. - src/index.tsx: MapboxOffline typed facade over the Object-based spec + a lazy NativeEventEmitter for onRegionDownloadProgress. View default export unchanged. tsc --noEmit clean. lib/ rebuild + native modules land in the follow-up commits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… wiring T4/T5 (Android) of the offline-nav milestone. JS: revert codegenConfig to "components" and make MapboxNavigationOffline a classic NativeModules accessor (linking-error proxy) instead of a codegen TurboModule. The fork's view manager already relies on the host app's New-Arch legacy interop, so a classic module resolves identically at runtime while avoiding the iOS generated-protocol conformance (the fiddliest blind-build risk). The MapboxOffline facade + NativeEventEmitter in index.tsx are unchanged. Android: MapboxNavigationOfflineModule (ReactContextBaseJavaModule, registered in MapboxNavigationPackage). downloadRegion does a Directions request, decodes the route line, buffers it into a corridor (MultiPolygon of Turf circles sampled along the route — robust vs self-intersection), then downloads maps + nav tileset descriptors + a style pack via loadStylePack -> loadTileRegion into the shared default TileStore, streaming onRegionDownloadProgress. Plus listRegions / removeRegion / clearAllRegions and the NativeEventEmitter stubs. API signatures verified via javap against the resolved 3.20.1 / 11.20.2 AARs. iOS module + lib rebuild + version bump follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T4/T5 (iOS) of the offline-nav milestone — parity with the Android module. MapboxNavigationOffline.swift (@objc RCTEventEmitter) + .m (RCT_EXTERN_MODULE), resolved via the host app's New-Arch legacy interop like the fork's view manager. downloadRegion computes a route via NavigationRouteOptions(coordinates:) -> routingProvider().calculateRoutes, reads routes.mainRoute.route.shape.coordinates, buffers it into a corridor (MultiPolygon of circles via Turf coordinate(at:facing:)), then downloads maps + nav tileset descriptors + a style pack via loadStylePack -> loadTileRegion into the TileStore obtained through the provider's tilestoreConfig.navigatorLocation (so nav + maps share one store). Streams onRegionDownloadProgress; plus listRegions / removeRegion / clearAllRegions. All Swift signatures pinned against mapbox-navigation-ios v3.20.1 / mapbox-maps-ios v11.20.2 / turf-swift v4.0.0 source, mirroring the official Offline-Regions.swift example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T7 — regenerate the committed lib/ build output (bob) so the offline JS surface (NativeMapboxNavigationOffline accessor + MapboxOffline facade + types) is in the package the app consumes, and bump the version (per fork-iteration rule: bump version, not just the SHA, so podspec/Android caches invalidate). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
iOS Nav SDK allows only ONE active MapboxNavigationProvider — the offline module allocated its own while the embedded view had one, tripping the SDK's "Two simultaneous active navigation cores" [BUG] abort the moment the en-route screen fired the corridor pre-download (crash on entering en-route). Add SharedNavigationProvider (a single app-wide provider, created on first use) and route BOTH the view's embed() and the offline module through it — mirroring Android's MapboxNavigationProvider process singleton (which is why Android never hit this). The view still holds/niles its ref per session; the singleton retains the core. Offline-reroute config (.hybrid + tilestoreConfig .default) lives in the singleton. Native-only (Swift) — no lib change. Bump 0.6.0 -> 0.6.1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-dim corridors Audit vs official Nav SDK v3.20.1 offline patterns found two functional gaps and two hardening issues: 1. styleUrls: string[] — the style pack + maps tiles must match the style the nav view actually renders (the app passes light/dark-v11 to the view, but downloads defaulted to streets/Standard → blank basemap offline). Multiple styles per region: one maps descriptor per style, sequential style packs; light+dark share sources so tiles dedupe. Android default aligned to Streets (was Standard) to match iOS. 2. vehicleMaxHeight/Width/Weight on downloadRegion — the corridor route is now computed with the same truck dimensions the nav view applies (same >0 guard, meters/metric tons), so a dimension-forced detour stays inside the downloaded corridor. 3. Android emitProgress now guards hasActiveReactInstance() — downloads outlive React instances (foreground OTA force-reload) and emitting into a dead instance throws. iOS already guarded via hasListeners. 4. Android removeRegion no longer evicts the style pack — packs are style-keyed, shared across every corridor, and small; evicting forced a pointless re-download each head-out (and targeted the wrong style after a custom styleUrl download). Matches iOS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Re-platforms this module onto Mapbox Navigation SDK v3 (3.20.1) on both iOS and Android, fixes the New-Architecture (Fabric) integration, and adds the customization and truck-routing props the Resupply driver app needs. Upstream targets Nav SDK v2
(iOS CocoaPods
MapboxNavigation ~> 2.18.1) and v3.0.2 on Android; this branch brings both platforms to a single, interlocked v3.20.1 that coexists with@rnmapbox/maps.iOS — Nav SDK v3 via vendored binary xcframeworks
v3 has no CocoaPods pod, and consuming the SPM package from a CocoaPods host hits duplicate-symbol walls. Mapbox publishes prebuilt binary
.xcframeworks(mapbox-navigation-ios-build-artifacts), so the podspec vendors them instead:MapboxNavigationProvider, asynccalculateRoutes(options:),NavigationOptionswithmapboxNavigation:/voiceController:/eventsManager:,CoreConfig.locationSourcefor simulation, per-VCStyleManager— v2'sDirections.shared/NavigationSettings.sharedare gone).ios/Frameworks/*.xcframework(static_framework, non-recursivesource_filesso CocoaPods doesn't strip the frameworks), depends on the sharedMapboxMaps11.20.2 pod (same one@rnmapbox/mapsconsumes → deduped by name, nouse_frameworks!).ios/Frameworks/on demand beforepod install(checksum-pinnedscripts/fetch-mapbox-nav-binaries.sh, auth via aMapbox
DOWNLOADS:READtoken).Version interlock: nav
3.20.1/MapboxNavigationNative324.20.2/MapboxCommon24.20.2/MapboxMaps11.20.2(aligned with@rnmapbox/maps@10.3.1). When bumping, lift versions + checksums from the matching build-artifacts tag.Android —
com.mapbox.navigationcore3.20.1navigation/ui-componentsfrom3.0.2→3.20.1to match iOS (shared transitive maps/common dedupe with@rnmapbox/maps).-ndk27artifacts whentargetSdk >= 35(mirrors rnmapbox's selection for the 16 KB page-size requirement; mixing ndk27 / non-ndk27 Mapbox artifacts duplicates classes).New Architecture (Fabric) fixes
as HostComponent<… & NativeEventsProps>cast, so Fabric registered zero events and every callback (onArrive,onCancelNavigation,onError,onLocationChange,onRouteProgressChange) was silently dropped on New-Arch apps. They now live inNativeProps."react-native": "./src/index.tsx") so codegen can parse the native-component spec.onAfterUpdateTransaction) instead of from a prop setter racing alphabetical prop order, with guarded teardown.New props
theme'day' | 'night' | 'auto'StyleManager, AndroidNAVIGATION_DAY/NIGHT_STYLE)styleUrlstringfontFamilystringbottomInsetnumbershowsReportFeedbackbooleanvehicleMaxHeightnumber(meters)vehicleMaxWidthnumber(meters)vehicleMaxWeightnumber(metric tons)Truck routing (
vehicleMaxHeight/vehicleMaxWidth/vehicleMaxWeight)Wires Mapbox's vehicle-dimension routing constraints end-to-end so callers can request truck-aware routes that avoid low bridges, narrow roads, and weight-restricted roads (where Mapbox has the restriction data). Mapbox has no dedicated truck
profile — these are dimension parameters on the
driving/driving-trafficprofiles.Previously
vehicleMaxHeight/vehicleMaxWidthwere declared on iOS but dead (not registered in the ViewManager, never applied toRouteOptions), and Android had no support at all.RouteOptions.maximumHeight/maximumWidth/maximumWeight(Measurement,.meters/.metricTons), only when provided; registers all three props in the ObjC ViewManager.RouteOptions.builder().maxHeight()/.maxWidth()/.maxWeight()(applied only when> 0); adds@ReactPropoverrides.MapboxNavigationProps.Units match the Directions API: height/width in meters, weight in metric tons (1000 kg). Omitted /
0= the API's car-sized defaults (1.6 m / 1.9 m / 2.5 t), so existing callers are unaffected. Best-effort: coverage of road restriction datavaries by region.
Build & packaging
lib/(CommonJS / ESM / TypeScript viareact-native-builder-bob) for git-dependency consumption; renamesprepare→build(no auto-build on install of a git dep), drops theexportsmap and adds thereact-nativesourcefield.
.gitignoreforios/Frameworks/; version0.5.2→0.5.3.Consumer requirements
DOWNLOADS:READtoken (~/.netrcorMAPBOX_DOWNLOADS_TOKEN) — for iOS binary fetch and the Android maven repo.fetch-mapbox-nav-binaries.sh(checksum-pinned) beforepod install.Testing
MapboxDirectionsinterface (maximumHeight/Width/Weight: Measurement<UnitLength/Mass>?) and the AndroidRouteOptionsbuilder methods; inert until a caller passes values.