Getting started with the Driver SDK for iOS

The Driver SDK is a library that you integrate into your driver app. It is responsible for updating the Fleet Engine with the vehicle location, route, distance remaining, and ETA. It also integrates with the Navigation SDK, which provides turn-by-turn navigation instructions for the driver.

Minimum system requirements

  • The mobile device must be running iOS 14 or later.
  • Xcode version 15 or later.
  • Prerequisites

    This guide assumes your app already implements the Navigation SDK and that the Fleet Engine backend is set up and available. However, the example code provides a sample of how to set up the Navigation SDK.

    You must also enable the Maps SDK for iOS in your Google Cloud Project and Get an API Key.

    Local development

    For local development, it is sufficient to log in with the Cloud SDK.

    gcloud

    gcloud auth login
    

    The email used to sign in must be a member of the Workspace Group.

    Automation (build systems or continuous integration)

    Set up your automation hosts according to best practices:

    • If your process runs inside a Google Cloud environment, use automatic credential detection.

    • Otherwise, store the service account key file in a secure location on the host's file-system and set the GOOGLE_APPLICATION_CREDENTIALS environment variable appropriately.

    The service account email associated with the credentials must be a member of the Workspace Group.

    Project configuration

    Swift Package Manager

    The Driver SDK can be installed via Swift Package Manager. To add the SDK, ensure you have removed any existing Driver SDK dependencies.

    To add the SDK to a new or existing project, follow these steps:

    1. Open your Xcode project or workspace, then go to File > Add Package Dependencies.
    2. Enter https://github.com/googlemaps/ios-driver-sdk as the URL, press Enter to pull in the package, and click "Add Package".
    3. To install a specific version, set the Dependency Rule field to one of the version-based options. For new projects, we recommend specifying the latest version and using the "Exact Version" option. Once complete, click "Add Package".
    4. From the Choose Package Products window, verify GoogleRidesharingDriver will be added to your designated main target. Once complete, click "Add Package".
    5. To verify your installation, navigate to your target's General pane. In the Frameworks, Libraries, and Embedded Content you should see the installed packages. You can also view the "Package Dependencies" section of "Project Navigator" to verify the package and its version.

    To update the package for an existing project, follow these steps:

    1. If you are upgrading from a version earlier than 9.0.0, you must remove the following dependencies: GoogleMapsBase, GoogleMapsCore, and GoogleMapsM4B after upgrading. Do not remove the dependency for GoogleMaps. For more information, see the Version 9.0.0 Release Notes.

      From your Xcode project configuration settings, find Frameworks, Libraries, and Embedded Content. Use the minus sign(-) to remove the following framework:

      • GoogleMapsBase (Only for upgrades from versions earlier than 9.0.0)
      • GoogleMapsCore (Only for upgrades from versions earlier than 9.0.0)
      • GoogleMapsM4B (Only for upgrades from versions earlier than 9.0.0)
    2. From Xcode, go to "File > Packages > Update To Latest Package Versions".
    3. To verify your installation, go to the Package Dependencies section of Project Navigator to verify the package and its version.

    To remove existing Driver SDK dependencies added using CocoaPods, follow these steps:

    1. Close your Xcode workspace. Open terminal and execute the following command:
      sudo gem install cocoapods-deintegrate cocoapods-clean 
      pod deintegrate 
      pod cache clean --all
    2. Remove the Podfile, Podfile.resolved and the Xcode workspace if you are not using them for anything other than CocoaPods.

    To remove the existing Driver SDK installed manually, follow these steps:

    1. From your Xcode project configuration settings, find Frameworks, Libraries, and Embedded Content. Use the minus sign(-) to remove the following framework:

      • GoogleRidesharingDriver.xcframework
    2. From the top level directory of your Xcode project, remove the GoogleRidesharingDriver bundle.

    CocoaPods

    To configure the Driver SDK using CocoaPods, you need the following items:

    • The CocoaPods tool: To install this tool, open the Terminal and run the following command.
       sudo gem install cocoapods
    
    1. Create a Podfile for the Driver SDK and use it to install the API and its dependencies: Create a file named Podfile in your project directory. This file defines your project's dependencies. Edit the Podfile and add your dependencies. Here is an example which includes the dependencies:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      

      Here is an example which includes the Alpha and Beta pods for the Driver SDK as dependencies:

      source "https://cpdc-eap.googlesource.com/ridesharing-driver-sdk.git"
      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. Save the Podfile. Open a terminal and go to the directory containing the Podfile:

      cd <path-to-project>
      
    3. Run the pod install command. This will install the APIs specified in the Podfile, along with any dependencies they may have.

      pod install
      
    4. Close Xcode, and then open (double-click) your project's .xcworkspace file to launch Xcode. From this time onwards, you must use the .xcworkspace file to open the project.

    Refer to the CocoaPods Getting Started guide for more details.

    Manual installation

    An XCFramework is a binary package that you use to install the Driver SDK. You can use this package on multiple platforms, including machines using Apple silicon. This guide shows how to manually add the XCFramework containing the Driver SDK to your project and configure your build settings in Xcode.

    Download the SDK binary and resources:

    1. Extract the files to access the XCFramework and resources.

    2. Start Xcode and either open an existing project, or create a new project. If you're new to iOS, create a new project and select the iOS App template.

    3. Create a Frameworks group under your project group if one does not exist already.

    4. To install the Driver SDK, drag the GoogleRidesharingDriver.xcframework file into your project under Frameworks, Libraries, and Embedded Content. When prompted, select Copy items if needed.

    5. Drag the downloaded GoogleRidesharingDriver.bundle into the top level directory of your Xcode project. When prompted, select Copy items if needed.

    6. Select your project from the Project Navigator, and choose your application's target.

    7. Open the Build Phases tab, and in Link Binary with Libraries, add the following frameworks and libraries if they are not already present:

      • Accelerate.framework
      • AudioToolbox.framework
      • AVFoundation.framework
      • CoreData.framework
      • CoreGraphics.framework
      • CoreLocation.framework
      • CoreTelephony.framework
      • CoreText.framework
      • GLKit.framework
      • ImageIO.framework
      • libc++.tbd
      • libxml2.tbd
      • libz.tbd
      • LocalAuthentication.framework
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
      • WebKit.framework
    8. Choose your project, rather than a specific target, and open the Build Settings tab. In the Other Linker Flags section, add -ObjC for both debug and release. If these settings are not visible, change the filter in the Build Settings bar from Basic to All.

    Inspect Apple Privacy Manifest file

    Apple requires app privacy details for apps on the App Store. Visit the Apple App Store Privacy Details page for updates and more information.

    The Apple Privacy Manifest file is included in the resources bundle for the SDK. To verify that the Privacy Manifest File has been included, and to inspect its contents, create an archive of your app and generate a privacy report from the archive.

    Implement authorization and authentication

    When your Driver app generates and sends updates to the Fleet Engine backend, the requests must include valid access tokens. To authorize and authenticate these requests, the Driver SDK calls your object conforming to the GMTDAuthorization protocol. The object is responsible for providing the required access token.

    As the app developer, you choose how tokens are generated. Your implementation should provide the ability to do the following:

    • Fetch an access token, possibly in JSON format, from an HTTPS server.
    • Parse and cache the token.
    • Refresh the token when it expires.

    For details of the tokens expected by the Fleet Engine server, see Creating a JSON Web Token (JWT) for authorization.

    The provider ID is the same as Google Cloud Project ID. See Fleet Engine Deliveries API User Guide for more information.

    The following example implements an access token provider:

    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    // SampleAccessTokenProvider.h
    @interface SampleAccessTokenProvider : NSObject<GMTDAuthorization>
    @end
    
    static NSString *const PROVIDER_URL = @"INSERT_YOUR_TOKEN_PROVIDER_URL";
    
    // SampleAccessTokenProvider.m
    @implementation SampleAccessTokenProvider{
      // The cached vehicle token.
      NSString *_cachedVehicleToken;
      // Keep track of the vehicle ID the cached token is for.
      NSString *_lastKnownVehicleID;
      // Keep track of when tokens expire for caching.
      NSTimeInterval _tokenExpiration;
    }
    
    - (void)fetchTokenWithContext:(nullable GMTDAuthorizationContext *)authorizationContext
                       completion:(nonnull GMTDAuthTokenFetchCompletionHandler)completion {
      if (!completion) {
        NSAssert(NO, @"%s encountered an unexpected nil completion.", __PRETTY_FUNCTION__);
        return;
      }
    
      // Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
      NSString *vehicleID = authorizationContext.vehicleID;
      if (!vehicleID) {
        NSAssert(NO, @"Vehicle ID is missing from authorizationContext.");
        return;
      }
    
    // Clear cached vehicle token if vehicle ID has changed.
      if (![_lastKnownVehicleID isEqual:vehicleID]) {
        _tokenExpiration = 0.0;
        _cachedVehicleToken = nil;
      }
      _lastKnownVehicleID = vehicleID;
    
      // Clear cached vehicle token if it has expired.
      if ([[NSDate date] timeIntervalSince1970] > _tokenExpiration) {
        _cachedVehicleToken = nil;
      }
    
      // If appropriate, use the cached token.
      if (_cachedVehicleToken) {
        completion(_cachedVehicleToken, nil);
        return;
      }
      // Otherwise, try to fetch a new token from your server.
      NSURL *requestURL = [NSURL URLWithString:PROVIDER_URL];
      NSMutableURLRequest *request = 
                              [[NSMutableURLRequest alloc] initWithURL:requestURL];
      request.HTTPMethod = @"GET";
      // Replace the following key values with the appropriate keys based on your
      // server's expected response.
      NSString *vehicleTokenKey = @"VEHICLE_TOKEN_KEY";
      NSString *tokenExpirationKey = @"TOKEN_EXPIRATION";
      __weak typeof(self) weakSelf = self;
      void (^handler)(NSData *_Nullable data, NSURLResponse *_Nullable response,
                      NSError *_Nullable error) =
          ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
            typeof(self) strongSelf = weakSelf;
            if (error) {
              completion(nil, error);
              return;
            }
    
            NSError *JSONError;
            NSMutableDictionary *JSONResponse =
                [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&JSONError];
    
            if (JSONError) {
              completion(nil, JSONError);
              return;
            } else {
              // Sample code only. No validation logic.
              id expirationData = JSONResponse[tokenExpirationKey];
              if ([expirationData isKindOfClass:[NSNumber class]]) {
                NSTimeInterval expirationTime = ((NSNumber *)expirationData).doubleValue;
                strongSelf->_tokenExpiration = [[NSDate date] timeIntervalSince1970] + expirationTime;
              }
              strongSelf->_cachedVehicleToken = JSONResponse[vehicleTokenKey];
              completion(JSONResponse[vehicleTokenKey], nil);
            }
        };
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *mainQueueURLSession =  
           [NSURLSession  sessionWithConfiguration:config delegate:nil
    delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *task = [mainQueueURLSession dataTaskWithRequest:request completionHandler:handler];
    [task resume];
    }
    
    @end
    

    Create a DeliveryDriverAPI instance

    To get a GMTDDeliveryVehicleReporter instance, you first need to create a GMTDDeliveryDriverAPI instance using the providerID, vehicleID, driverContext, and accessTokenProvider. The providerID is the same as Google Cloud Project ID. And you can access the GMTDDeliveryVehicleReporter instance from the driver API directly.

    The following example creates a GMTDDeliveryDriverAPI instance:

    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView;
    }
    
    - (void)viewDidLoad {
      NSString *vehicleID = @"INSERT_CREATED_VEHICLE_ID";
      SampleAccessTokenProvider *accessTokenProvider = 
                                    [[SampleAccessTokenProvider alloc] init];
      GMTDDriverContext *driverContext = 
         [[GMTDDriverContext alloc] initWithAccessTokenProvider:accessTokenProvider
                                                     providerID:PROVIDER_ID 
                                                  vehicleID:vehicleID 
          navigator:_mapView.navigator];
    
      GMTDDeliveryDriverAPI *deliveryDriverAPI = [[GMTDDeliveryDriverAPI alloc] initWithDriverContext:driverContext];
    }
    

    Optionally listen to VehicleReporter events

    GMTDDeliveryVehicleReporter periodically updates the vehicle when locationTrackingEnabled is YES. To respond to these periodic updates, any object can subscribe to GMTDDeliveryVehicleReporter events by conforming to theGMTDVehicleReporterListener protocol.

    You can handle the following events:

    • vehicleReporter:didSucceedVehicleUpdate

      Informs the Driver app that the backend services successfully received the vehicle location and state update.

    • vehicleReporter:didFailVehicleUpdate:withError

      Informs the listener that a vehicle update failed. As long as location tracking is enabled, GMTDDeliveryVehicleReporter continues to send the latest data to Fleet Engine backend.

    The following example handles these events:

    SampleViewController.h
    @interface SampleViewController : UIViewController<GMTDVehicleReporterListener>
    @end
    
    SampleViewController.m
    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView;
    }
    
    - (void)viewDidLoad {
      // ASSUMES YOU IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      [ridesharingDriverAPI.vehicleReporter addListener:self];
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didSucceedVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate {
      // Handle update succeeded.
    }
    
    - (void)vehicleReporter:(GMTDDeliveryVehicleReporter *)vehicleReporter didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate withError:(NSError *)error {
      // Handle update failed.
    }
    
    @end
    

    Enable location tracking

    To enable location tracking, your app can set locationTrackingEnabled to YES on GMTDDeliveryVehicleReporter. Then GMTDDeliveryVehicleReporter automatically sends location updates. When the GMSNavigator is in navigation mode (when a destination is set through setDestinations) and locationTrackingEnabled is set to YES, GMTDDeliveryVehicleReporter automatically sends route and ETA updates as well.

    The route set during those updates is the same route the driver is navigating to during the navigation session. Thus, for fleet tracking to work properly, the waypoint set through -setDestinations:callback: should match the destination set in the Fleet Engine backend.

    The following example enables location tracking:

    SampleViewController.m
    #import "SampleViewController.h"
    #import "SampleAccessTokenProvider.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    static NSString *const PROVIDER_ID = @"INSERT_YOUR_PROVIDER_ID";
    
    @implementation SampleViewController {
     GMSMapView *_mapView; 
    }
    
    - (void)viewDidLoad {
      // ASSUMES YOU IMPLEMENTED HAVE THE SAMPLE CODE UP TO THIS STEP.
      deliveryDriverAPI.vehicleReporter.locationTrackingEnabled = YES;
    }
    
    @end
    

    By default, the reporting interval is 10 seconds, but the reporting interval can be changed with locationUpdateInterval. The minimum supported update interval is 5 seconds. The maximum supported update interval is 60 seconds. More frequent updates may result in slower requests and errors.

    Disable location updates and take the vehicle offline

    Your app can disable location updates for a vehicle. For example, when a driver's shift ends, your app can set locationTrackingEnabled to NO.

      _vehicleReporter.locationTrackingEnabled = NO