Google Navigation SDK for React Native

repository·main·Indexed 42 days ago

https://github.com/googlemaps/react-native-navigation-sdk

A Beta React Native library for the Navigation SDK on Google Maps Platform, providing native navigation components for Android and iOS. It includes the NavigationView and MapView components, a NavigationController for managing sessions and guidance, and a NavigationProvider for global configuration of terms and conditions.

Tokens
28.8K
Snippets
70
Records
97
Agent score
52%

What's inside Google Navigation SDK for React Native

  1. Update Map Objects in Place (0.14.x)

    main

    In 0.14.0, add* methods (like addMarker) function as 'add or update' operations. If you provide an id that already exists on the map, the existing object is updated with the new properties instead of creating a duplicate. This allows for easier state management using custom IDs.

    // Create a marker with a custom ID
    const marker = await mapViewController.addMarker({
      id: 'user-location',
      position: { lat: 37.7749, lng: -122.4194 },
      title: 'Current Location',
    });
    
    // Update the same marker using the same custom ID
    const updatedMarker = await mapViewController.addMarker({
      id: 'user-location',
      position: { lat: 37.7849, lng: -122.4294 },
      title: 'Updated Location',
    });
    
    console.log(updatedMarker.id === marker.id); // true
  2. Prevent UI overlap between prompts and travel estimates

    main

    When using AndroidAutoBaseScreen, the SDK automatically detects Navigation SDK prompts (like traffic or rerouting). To prevent these prompts from overlapping with your TravelEstimate in the NavigationTemplate, you should:

    1. Override onPromptVisibilityChanged(boolean promptVisible) and call invalidate() to trigger a template refresh.
    2. In onGetTemplate(), use isPromptVisible() to conditionally add the travel estimate to the builder.

    This ensures the estimate is only displayed when no modal prompts are active.

    @Override
    protected void onPromptVisibilityChanged(boolean promptVisible) {
      invalidate();
    }
    
    @Override
    public Template onGetTemplate() {
      NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
      // Configure actions, map action strip, and navigation info.
    
      if (!isPromptVisible()) {
        builder.setDestinationTravelEstimate(travelEstimate);
      }
    
      return builder.build();
    }
  3. Support for Android Auto and Apple CarPlay

    main
    The Google Navigation for React Native (Beta) plugin is compatible with both Android Auto and Apple CarPlay infotainment systems. For specific implementation details and platform-specific requirements, refer to the dedicated documentation files: ANDROIDAUTO.md for Android Auto and CARPLAY.md for Apple CarPlay.
  4. Register navigation event listeners

    main

    Use the setter functions returned by useNavigation() to handle navigation events. To remove a listener, pass null or undefined to the setter. Use removeAllListeners() during component unmounting to clean up all listeners.

    Supported Event Setters

    • setOnStartGuidance(listener: () => void)
    • setOnArrival(listener: (event: { waypoint: Waypoint, isFinalDestination: boolean }) => void)
    • setOnLocationChanged(listener: (event: { location: Location }) => void)
    • setOnRawLocationChanged(listener: (event: { location: Location }) => void)
    • setOnNavigationReady(listener: () => void)
    • setOnNavigationInitError(listener: (event: { errorCode: NavigationInitErrorCode }) => void)
    • setOnRouteChanged(listener: () => void)
    • setOnReroutingRequestedByOffRoute(listener: () => void)
    • setOnTrafficUpdated(listener: () => void)
    • setOnRemainingTimeOrDistanceChanged(listener: (event: any) => void)
    • setOnTurnByTurn(listener: (event: { navInfo: NavInfo }) => void)
    const { setOnArrival, setOnRouteChanged, removeAllListeners } = useNavigation();
    
    useEffect(() => {
      setOnArrival((event) => {
        console.log('Arrived at', event.waypoint);
        if (event.isFinalDestination) {
          navigationController.stopGuidance();
        }
      });
      setOnRouteChanged(() => console.log('Route changed'));
      
      return () => removeAllListeners();
    }, [setOnArrival, setOnRouteChanged, removeAllListeners]);
    
    // To remove a single listener:
    setOnArrival(null);
  5. Migrate from 0.17.x to 0.18.x

    main

    Version 0.18.0 upgrades the iOS Google Navigation SDK to 11.0.0 and changes how it is resolved.

    Key Changes

    • iOS Dependency Management: The iOS Navigation SDK is now resolved via Swift Package Manager during pod install instead of a CocoaPods GoogleNavigation dependency. CocoaPods still manages React Native autolinking and other pods, but it no longer fetches Google Navigation. You may need to configure framework linkage in your Podfile (the sample app uses dynamic frameworks).
    • iOS Display Behavior:
      • showTrafficLights and showStopSigns no longer affect iOS navigation views (they are always displayed in SDK 11). These options still work on Android.
      • MapType.TERRAIN is unavailable during active navigation on iOS, though it remains available for non-navigation maps.
    • iOS Permissions: Add an NSMotionUsageDescription entry to your Info.plist to prevent potential crashes related to motion sensors.

    Migration Steps

    Reinstall pods after upgrading:

    cd ios && pod install
  6. Initialize the Navigation SDK with NavigationProvider

    main

    Wrap your application's root component with NavigationProvider to provide the necessary context for navigation. This component allows you to configure the global Terms and Conditions dialog and Android-specific task removal behavior.

    import React from 'react';
    import {
      NavigationProvider,
      TaskRemovedBehavior,
    } from '@googlemaps/react-native-navigation-sdk';
    
    const App = () => {
      return (
        <NavigationProvider
          termsAndConditionsDialogOptions={{
            title: 'Terms and Conditions',
            companyName: 'Your Company Name',
            showOnlyDisclaimer: false,
            uiParams: {
              backgroundColor: '#FFFFFF',
              titleColor: 'rgba(0,0,0,1)',
            },
          }}
          taskRemovedBehavior={TaskRemovedBehavior.CONTINUE_SERVICE}
        >
          {/* Add your application components here */}
        </NavigationProvider>
      );
    };
    
    export default App;
  7. Migrate from 0.13.x to 0.14.x

    main

    Version 0.14.0 requires React Native's New Architecture (Fabric & TurboModules) and drops support for the legacy architecture. This migration involves enabling the New Architecture, updating the navigation initialization flow, and moving from callback objects to individual setter functions and declarative props.

    ### Prerequisites
    - **React Native 0.79 or higher** is required
    - **New Architecture must be enabled** in your project
  8. Configure Android for Google Navigation SDK

    main

    To use the Navigation SDK on Android, you must meet several configuration requirements in your Gradle files:

    1. Enable New Architecture: Set newArchEnabled=true in android/gradle.properties.
    2. Enable Jetifier: Set android.enableJetifier=true in android/gradle.properties to ensure AndroidX compatibility.
    3. Enable Core Library Desugaring: This is mandatory. In android/app/build.gradle, enable coreLibraryDesugaringEnabled and add the required dependency.
    4. Set Minimum SDK: Ensure minSdkVersion is at least 24 in android/app/build.gradle.
    5. API Key: It is recommended to use the Google Maps Secrets Gradle Plugin to manage your API key.
    // android/gradle.properties
    newArchEnabled=true
    android.enableJetifier=true
    
    // android/app/build.gradle
    android {
        defaultConfig {
            minSdkVersion 24
        }
        compileOptions {
            coreLibraryDesugaringEnabled true
        }
    }
    
    dependencies {
        coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5'
    }
  9. Update Navigation Initialization (0.14.x)

    main

    The initialization flow in 0.14.x separates Terms and Conditions (ToS) handling from session initialization.

    1. Configure NavigationProvider: termsAndConditionsDialogOptions is now a required prop.
    2. Handle ToS: Use areTermsAccepted() to check status and showTermsAndConditionsDialog() to prompt the user.
    3. Initialize Session: Call init(), which now returns a NavigationSessionStatus instead of throwing errors.
    4. Error Handling: Instead of the onNavigationInitError event, check the return value of init() against the NavigationSessionStatus enum.
    import {
      NavigationProvider,
      TaskRemovedBehavior,
      useNavigation,
      NavigationSessionStatus 
    } from '@googlemaps/react-native-navigation-sdk';
    
    // 1. Provider Configuration
    <NavigationProvider
      termsAndConditionsDialogOptions={{
        title: 'Terms',
        companyName: 'My Company',
        showOnlyDisclaimer: false,
        uiParams: {
          backgroundColor: '#FFFFFF',
          titleColor: '#000000',
        },
      }}
      taskRemovedBehavior={TaskRemovedBehavior.CONTINUE_SERVICE}
    >
      {children}
    </NavigationProvider>
    
    // 2. Initialization Logic
    const { navigationController } = useNavigation();
    
    const initNavigation = async () => {
      const termsAccepted = await navigationController.showTermsAndConditionsDialog();
      if (!termsAccepted) return;
    
      const status = await navigationController.init();
      switch (status) {
        case NavigationSessionStatus.OK: 
          console.log('Success'); break;
        case NavigationSessionStatus.NOT_AUTHORIZED: 
          console.error('API key error'); break;
        // ... handle other statuses
      }
    };
  10. Handle Location and Background Permissions

    main

    The Navigation SDK requires system permissions for location services and background execution. The SDK does not manage these permissions for you. You must use a library like react-native-permissions to request and handle them in your application code before initializing the SDK.

    import {request, PERMISSIONS, RESULTS} from 'react-native-permissions';
    import {Platform} from 'react-native';
    
    const requestPermissions = async () => {
        const result = await request(
            Platform.OS === "android" ?
                PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION :
                PERMISSIONS.IOS.LOCATION_ALWAYS,
        );
    
        if (result === RESULTS.GRANTED) {
            setArePermissionsApproved(true);
        } else {
            // Handle denied permission
        }
    };