@heumes-it/expo-mapbox-navigation - v0.1.0
    Preparing search index...

    @heumes-it/expo-mapbox-navigation - v0.1.0

    @heumes-it/expo-mapbox-navigation

    npm CI license docs

    Turn-by-turn navigation for React Native / Expo, powered by Mapbox Navigation SDK v3 on iOS and Android.

    Provides routing, active guidance with voice/banner instructions, a native map view with route line rendering, lane guidance, speed limits, and a comprehensive Expo config plugin for build automation.

    If you have problems with the code in this repository, please file issues & bug reports at https://github.com/Heumes-IT/expo-mapbox-navigation/issues.

    npx expo install @heumes-it/expo-mapbox-navigation
    

    Two tokens are required from your Mapbox account:

    Public token (pk.*) — passed at runtime via MapboxNavigation.setAccessToken(token).

    Secret download token (sk.*, scope DOWNLOADS:READ) — used at build time to fetch SDK binaries.

    iOS — add to ~/.netrc:

    machine api.mapbox.com
    login mapbox
    password sk.YOUR_SECRET_TOKEN

    Android — add to ~/.gradle/gradle.properties:

    MAPBOX_DOWNLOADS_TOKEN=sk.YOUR_SECRET_TOKEN
    
    [
    "@heumes-it/expo-mapbox-navigation",
    {
    "locationWhenInUseDescription": "We use your location to navigate.",
    "locationAlwaysDescription": "We use your location in the background for turn-by-turn guidance.",
    "enableBackgroundLocation": true
    }
    ]

    Then run:

    npx expo prebuild --clean
    

    string, required. Sets NSLocationWhenInUseUsageDescription in iOS Info.plist.

    string, required when enableBackgroundLocation is true. Sets NSLocationAlwaysAndWhenInUseUsageDescription in iOS Info.plist.

    boolean, defaults to false. When true:

    • iOS: adds location to UIBackgroundModes
    • Android: adds FOREGROUND_SERVICE_LOCATION, ACCESS_BACKGROUND_LOCATION, POST_NOTIFICATIONS permissions and registers NavigationNotificationService with foregroundServiceType: location
    import { useEffect } from 'react';
    import MapboxNavigation, {
    ExpoMapboxNavigationNative,
    MapboxNavigationMapView,
    } from '@heumes-it/expo-mapbox-navigation';
    import { useEvent } from 'expo';

    export default function NavigationScreen() {
    const sessionState = useEvent(ExpoMapboxNavigationNative as any, 'onSessionStateChange') as any;

    useEffect(() => {
    MapboxNavigation.setAccessToken('pk.YOUR_PUBLIC_TOKEN');
    MapboxNavigation.requestLocationPermission().then((status) => {
    if (status === 'granted') MapboxNavigation.startFreeDrive();
    });
    }, []);

    const startNavigation = async () => {
    const response = await MapboxNavigation.requestRoutes({
    waypoints: [
    { latitude: 52.379, longitude: 4.900, name: 'Origin' },
    { latitude: 52.368, longitude: 4.904, name: 'Destination' },
    ],
    profile: 'driving-traffic',
    steps: true,
    });
    await MapboxNavigation.startActiveGuidance({ response, simulate: true });
    };

    const isActive =
    sessionState?.state === 'activeGuidance' ||
    sessionState?.state === 'freeDrive';

    return (
    <>
    {isActive && (
    <MapboxNavigationMapView
    style={{ flex: 1 }}
    navigationCameraState="following"
    routeLineColor="#6728a1"
    />
    )}
    </>
    );
    }
    MapboxNavigation.setAccessToken(token: string): void
    

    Set the Mapbox public access token. Must be called before any other method.

    MapboxNavigation.requestRoutes(options: RequestRoutesOptions): Promise<DirectionsResponse>
    

    Request routes from the Mapbox Directions API.

    const response = await MapboxNavigation.requestRoutes({
    waypoints: [
    { latitude: 52.379, longitude: 4.900 },
    { latitude: 52.368, longitude: 4.904 },
    ],
    profile: 'driving-traffic', // 'driving' | 'driving-traffic' | 'walking' | 'cycling'
    alternatives: true,
    steps: true,
    language: 'nl',
    avoid: ['toll', 'ferry'],
    });
    MapboxNavigation.startActiveGuidance(options: StartActiveGuidanceOptions): Promise<void>
    

    Start a turn-by-turn navigation session using a previously requested route.

    await MapboxNavigation.startActiveGuidance({
    response, // DirectionsResponse from requestRoutes
    routeIndex: 0, // which route to navigate (default: 0)
    simulate: true, // replay route without real GPS (default: false)
    });
    MapboxNavigation.stopNavigation(): Promise<void>
    
    MapboxNavigation.startFreeDrive(): Promise<void>
    MapboxNavigation.pauseFreeDrive(): Promise<void>

    Start or pause free-drive mode. In free drive the map shows your location without an active route.

    MapboxNavigation.getSessionState(): Promise<SessionState>
    // Returns: 'idle' | 'freeDrive' | 'activeGuidance'
    MapboxNavigation.getCurrentLocation(): Promise<{ latitude: number; longitude: number } | null>
    
    MapboxNavigation.navigateNextLeg(): Promise<void>
    

    Advance to the next waypoint leg in a multi-stop route.

    MapboxNavigation.requestLocationPermission(options?: {
    background?: boolean;
    precise?: boolean;
    }): Promise<'granted' | 'denied' | 'restricted'>
    MapboxNavigation.getLocationPermissionStatus(): LocationPermissionStatus
    
    MapboxNavigation.configureTts(options: ConfigureTtsOptions): Promise<void>
    

    Configure text-to-speech voice instructions.

    await MapboxNavigation.configureTts({
    enabled: true, // default: true
    volume: 0.8, // 0.0–1.0
    speechRate: 1.2, // 0.5–2.0
    voiceIdentifier: 'nl-NL',
    engine: 'mapbox', // 'platform' (default) | 'mapbox'
    });
    • platform — uses AVSpeechSynthesizer (iOS) or android.speech.tts.TextToSpeech (Android). Offline, free.
    • mapbox — fetches cloud-rendered MP3 audio per instruction via the Mapbox Voice API. Higher quality, requires network.
    MapboxNavigation.setKeepScreenOn(enabled: boolean): void
    
    MapboxNavigation.setSimulated(enabled: boolean, speedMultiplier?: number): Promise<void>
    

    Toggle simulation at runtime. speedMultiplier is supported on Android only.

    MapboxNavigation.refreshRouteNow(): Promise<void>
    MapboxNavigation.pauseRouteRefresh(): Promise<void>
    MapboxNavigation.resumeRouteRefresh(): Promise<void>

    Android only. iOS handles route refresh automatically.

    MapboxNavigation.startHistoryRecording(): Promise<void>
    const filePath = await MapboxNavigation.stopHistoryRecording(): Promise<string>

    Control the map programmatically. These are module-level methods that operate on the currently mounted <MapboxNavigationMapView>.

    // Camera
    await MapboxNavigation.setCamera({
    center: [4.9, 52.37], // [lng, lat]
    zoom: 14,
    bearing: 90,
    pitch: 45,
    animationDuration: 1000, // ms, 0 = instant
    padding: { top: 100, right: 20, bottom: 160, left: 20 },
    });

    // Sources
    await MapboxNavigation.addGeoJsonSource('my-source', {
    data: { type: 'FeatureCollection', features: [...] },
    });
    await MapboxNavigation.removeSource('my-source');

    // Layers
    await MapboxNavigation.addLineLayer('my-line', {
    sourceId: 'my-source',
    paint: { lineColor: '#ff0000', lineWidth: 3, lineOpacity: 0.8 },
    belowLayerId: 'some-layer',
    });
    await MapboxNavigation.addCircleLayer('my-circles', {
    sourceId: 'my-source',
    paint: { circleColor: '#00ff00', circleRadius: 6 },
    });
    await MapboxNavigation.removeLayer('my-line');

    // Images
    await MapboxNavigation.addImage('marker', 'https://example.com/pin.png');
    await MapboxNavigation.removeImage('marker');

    Subscribe using Expo's useEvent hook:

    import { useEvent } from 'expo';
    import { ExpoMapboxNavigationNative } from '@heumes-it/expo-mapbox-navigation';

    const progress = useEvent(ExpoMapboxNavigationNative as any, 'onRouteProgress') as any;

    Fires ~1 Hz during active guidance.

    {
    distanceRemaining: number; // meters
    durationRemaining: number; // seconds
    fractionTraveled: number; // 0.0–1.0
    currentLegIndex: number;
    currentStepIndex: number;
    currentStreetName?: string;
    distanceToNextTurn?: number; // meters
    speedLimit?: { speed: number; unit: 'km/h' | 'mph'; sign?: 'vienna' | 'mutcd' };
    lanes?: Array<{ indications: string[]; valid: boolean; active?: boolean }>;
    upcomingManeuver?: { type: string; modifier?: string; instruction?: string };
    }
    { latitude: number; longitude: number; bearing?: number; speed?: number; accuracy?: number; matchState: 'matched' | 'notMatched' | 'uncertain' }
    
    { state: 'idle' | 'freeDrive' | 'activeGuidance' }
    
    { text: string; ssmlText?: string; distanceAlongStep: number }
    
    {
    primary: { text: string; type?: string; modifier?: string; components?: Array<{ text: string; type?: string }> };
    secondary?: { text: string };
    sub?: { text: string };
    distanceAlongStep: number;
    lanes?: Array<{ indications: string[]; valid: boolean; active?: boolean }>;
    }
    { speed: number; unit: 'km/h' | 'mph'; sign?: 'vienna' | 'mutcd' }
    

    Reroute lifecycle events. onRerouteCompleted includes { route }, onRerouteFailed includes { code, message }.

    Waypoint arrival events. onWaypointApproaching fires at ~500m with { waypointIndex, distanceRemaining }.

    Route update events during active guidance.

    <MapboxNavigationMapView
    style={{ flex: 1 }}
    styleURL="mapbox://styles/mapbox/navigation-day-v1"
    navigationCameraState="following" // 'following' | 'overview' | 'idle'
    routeLineColor="#6728a1" // hex color for the route line
    />

    string, defaults to 'mapbox://styles/mapbox/navigation-day-v1'. Any Mapbox style URL.

    'following' | 'overview' | 'idle', defaults to 'following'.

    • following — camera tracks the user puck with bearing-locked tilt
    • overview — camera fits the remaining route geometry
    • idle — user-controlled via gestures

    string (hex), defaults to Mapbox blue. Overrides the base route line color. Traffic congestion colors (moderate/heavy/severe) are preserved.

    iOS — Mapbox Navigation SDK v3 via SPM. The config plugin injects a Podfile post_install hook that embeds SPM binary frameworks and patches ExpoModulesProvider.swift for Swift 6 compatibility.

    Android — Mapbox Navigation SDK v3.18.0 via Maven. Requires MAPBOX_DOWNLOADS_TOKEN in ~/.gradle/gradle.properties. The map view uses TextureView mode with a singleton holder to prevent black-screen on tab navigation remount.

    Route refreshrefreshRouteNow() / pauseRouteRefresh() / resumeRouteRefresh() are implemented on Android. iOS handles refresh automatically.

    Simulation speedsetSimulated(true, speedMultiplier) speed control works on Android. iOS simulation runs at a fixed speed.

    This project is an independent, community-built package and is not affiliated with, endorsed by, or sponsored by Mapbox, Inc. "Mapbox" is a registered trademark of Mapbox, Inc. Use of the Mapbox Navigation SDK is subject to Mapbox's own terms of service.

    MIT