Last Mile Fleet Solution is currently available only to select customers. Contact sales to learn more.

Начало работы с Driver SDK для iOS

Driver SDK — это библиотека, которую вы интегрируете в свое приложение для водителей. Он отвечает за обновление Fleet Engine с указанием местоположения водителя, маршрута, оставшегося расстояния и ожидаемого времени прибытия. Он также интегрируется с Navigation SDK, который предоставляет водителю пошаговые инструкции по навигации.

Минимальные системные требования

  • Мобильное устройство должно работать под управлением iOS 13 или более поздней версии.
  • Xcode версии 14 или новее.
  • Предпосылки

    В этом руководстве предполагается, что ваше приложение уже реализует Navigation SDK , а серверная часть Fleet Engine настроена и доступна. Однако в примере кода показано, как настроить пакет SDK для навигации .

    Вы также должны включить Maps SDK для iOS в своем проекте Google Cloud и получить ключ API .

    Получить доступ

    Если вы являетесь клиентом Google Workspace, во время регистрации создайте группу Workspace , например google-maps-platform-sdk-users@workspacedomain.com , и сообщите название Google. Это рекомендуемый подход. Затем ваша рабочая группа будет добавлена ​​в список разрешенных, который предоставляет доступ к правильным репозиториям CocoaPods. Подтвердите, что адреса электронной почты пользователей и учетных записей служб, которым требуется доступ, включены в этот список.

    Если ваша организация не может создавать группы рабочей области, отправьте в Google список адресов электронной почты пользователей и учетных записей служб, которым требуется доступ к этим артефактам.

    Местное развитие

    Для локальной разработки достаточно авторизоваться с помощью Cloud SDK .

    gcloud

    gcloud auth login
    

    Электронная почта, используемая для входа, должна быть членом рабочей группы.

    Автоматизация (построение систем или непрерывная интеграция)

    Настройте хосты автоматизации в соответствии с рекомендациями :

    • Если ваш процесс выполняется в среде Google Cloud, используйте автоматическое определение учетных данных.

    • В противном случае сохраните файл ключа учетной записи службы в безопасном месте в файловой системе хоста и соответствующим образом задайте переменную среды GOOGLE_APPLICATION_CREDENTIALS .

    Адрес электронной почты сервисной учетной записи, связанный с учетными данными, должен принадлежать группе Workspace.

    Конфигурация проекта

    Вы можете настроить Driver SDK с помощью CocoaPods.

    Используйте CocoaPods

    Чтобы настроить Driver SDK с помощью CocoaPods, вам потребуются следующие элементы:

    • Инструмент CocoaPods: чтобы установить этот инструмент, откройте Терминал и выполните следующую команду. shell sudo gem install cocoapods Дополнительные сведения см. в руководстве по началу работы с CocoaPods .
    1. Создайте Podfile для Driver SDK и используйте его для установки API и его зависимостей: Создайте файл с именем Podfile в каталоге вашего проекта. Этот файл определяет зависимости вашего проекта. Отредактируйте Podfile и добавьте свои зависимости. Вот пример, который включает зависимости:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. Сохраните подфайл. Откройте терминал и перейдите в каталог, содержащий подфайл:

      cd <path-to-project>
      
    3. Запустите команду установки модуля. Это установит API, указанные в подфайле, вместе со всеми возможными зависимостями.

      pod install
      
    4. Закройте Xcode, а затем откройте (дважды щелкните) файл .xcworkspace вашего проекта, чтобы запустить Xcode. С этого момента для открытия проекта необходимо использовать файл .xcworkspace.

    Альфа/бета версии SDK

    Чтобы настроить альфа- или бета-версии Driver SDK для iOS, вам потребуются следующие элементы:

    • Инструмент CocoaPods: чтобы установить этот инструмент, откройте Терминал и выполните следующую команду.

      sudo gem install cocoapods
      

      Дополнительные сведения см. в руководстве по началу работы с CocoaPods .

    • Ваша учетная запись разработки в списке доступа Google. Репозиторий модулей альфа- и бета-версий SDK не является общедоступным. Чтобы получить доступ к этим версиям, обратитесь к инженеру по работе с клиентами Google. Инженер добавляет вашу учетную запись разработки в список доступа, а затем устанавливает файл cookie для аутентификации.

    После того, как ваш проект появится в списке доступа, вы сможете получить доступ к модулю.

    1. Создайте Podfile для Driver SDK для iOS и используйте его для установки API и его зависимостей: Создайте файл с именем Podfile в каталоге вашего проекта. Этот файл определяет зависимости вашего проекта. Отредактируйте Podfile и добавьте свои зависимости. Вот пример, который включает зависимости:

      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. Сохраните подфайл. Откройте терминал и перейдите в каталог, содержащий подфайл:

      cd <path-to-project>
      
    3. Запустите команду установки модуля. Это установит API, указанные в подфайле, вместе со всеми возможными зависимостями.

      pod install
      
    4. Закройте Xcode, а затем откройте (дважды щелкните) файл .xcworkspace вашего проекта, чтобы запустить Xcode. С этого момента для открытия проекта необходимо использовать файл .xcworkspace.

    Установите XCFramework

    XCFramework — это двоичный пакет, который используется для установки Driver SDK. Вы можете использовать этот пакет на нескольких платформах, включая машины с чипсетом M1. В этом руководстве показано, как вручную добавить XCFramework, содержащий Driver SDK, в ваш проект и настроить параметры сборки в Xcode.

    1. Распакуйте исходные файлы, которые вы получили от Google.

    2. Запустите Xcode и либо откройте существующий проект, либо создайте новый проект. Если вы новичок в iOS, создайте новый проект и выберите шаблон приложения iOS.

    3. Создайте группу Frameworks в своей группе проектов, если она еще не существует.

    4. Перетащите файл gRPCCertificates.bundle , включенный в каталог Resources архива, содержащего XCFramework, в каталог верхнего уровня вашего проекта Xcode. При появлении запроса выберите Копировать элементы, если это необходимо.

    5. Чтобы установить Driver SDK, перетащите файл GoogleRidesharingDriver.xcframework в свой проект в разделе Frameworks, Libraries, and Embedded Content . При появлении запроса выберите Копировать элементы, если это необходимо.

    6. Выберите свой проект в Навигаторе проектов и выберите цель вашего приложения.

    7. Откройте вкладку Build Phases и в Link Binary with Libraries добавьте следующие платформы и библиотеки, если их еще нет:

      • 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
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
      • LocalAuthentication.framework
      • WebKit.framework
    8. Выберите свой проект, а не конкретную цель, и откройте вкладку Build Settings . В разделе «Другие флаги компоновщика» добавьте ‑ObjC как для отладки, так и для выпуска. Если эти настройки не отображаются, измените фильтр на панели Build Settings с Basic на All .

    Реализовать авторизацию и аутентификацию

    Когда ваше приложение Driver создает и отправляет обновления на серверную часть Fleet Engine, запросы должны включать действительные токены доступа. Чтобы авторизовать и аутентифицировать эти запросы, Driver SDK вызывает ваш объект, соответствующий протоколу GMTDAuthorization . Объект отвечает за предоставление требуемого токена доступа.

    Как разработчик приложения, вы выбираете, как генерируются токены. Ваша реализация должна предоставлять возможность делать следующее:

    • Получите токен доступа, возможно, в формате JSON, с HTTPS-сервера.
    • Разберите и кэшируйте токен.
    • Обновите токен по истечении срока его действия.

    Дополнительные сведения о токенах, ожидаемых сервером Fleet Engine, см. в разделе Создание веб-токена JSON (JWT) для авторизации .

    Идентификатор поставщика совпадает с идентификатором проекта Google Cloud. Дополнительную информацию см. в Руководстве пользователя API доставки Fleet Engine .

    В следующем примере реализуется поставщик маркеров доступа:

    #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
    

    Создайте экземпляр DeliveryDriverAPI

    Чтобы получить экземпляр GMTDDeliveryVehicleReporter , сначала необходимо создать экземпляр GMTDDeliveryDriverAPI , используя providerID, VehicleID, driverContext и accessTokenProvider. Идентификатор провайдера совпадает с идентификатором проекта Google Cloud. И вы можете получить доступ к экземпляру GMTDDeliveryVehicleReporter напрямую из API драйвера.

    В следующем примере создается экземпляр GMTDDeliveryDriverAPI :

    #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];
    }
    

    При желании прослушивайте события VehicleReporter

    GMTDDeliveryVehicleReporter периодически обновляет транспортное средство, если для locationTrackingEnabled YES. Чтобы реагировать на эти периодические обновления, любой объект может подписаться на события GMTDDeliveryVehicleReporter , соблюдая протокол GMTDVehicleReporterListener .

    Вы можете обрабатывать следующие события:

    • vehicleReporter:didSucceedVehicleUpdate

      Сообщает приложению Driver, что серверные службы успешно получили информацию о местоположении и состоянии автомобиля.

    • vehicleReporter:didFailVehicleUpdate:withError

      Сообщает слушателю, что обновление транспортного средства не удалось. Пока включено отслеживание местоположения, GMTDDeliveryVehicleReporter продолжает отправлять последние данные в серверную часть Fleet Engine.

    В следующем примере обрабатываются эти события:

    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
    

    Включить отслеживание местоположения

    Чтобы включить отслеживание местоположения, ваше приложение может установить для locationTrackingEnabled YES в GMTDDeliveryVehicleReporter . Затем GMTDDeliveryVehicleReporter будет автоматически отправлять обновления местоположения. Когда GMSNavigator находится в режиме навигации (когда пункт назначения задан через setDestinations ) и locationTrackingEnabled установлено значение YES , GMTDDeliveryVehicleReporter также автоматически отправляет обновления маршрута и ETA.

    Маршрут, установленный во время этих обновлений, будет тем же маршрутом, по которому движется водитель во время сеанса навигации. Таким образом, для правильной работы отслеживания отправлений путевая точка, установленная с помощью -setDestinations:callback: должна совпадать с пунктом назначения, установленным в бэкэнде Fleet Engine.

    Следующий пример включает отслеживание местоположения:

    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
    

    По умолчанию интервал создания отчетов составляет 10 секунд, но этот интервал можно изменить с помощью locationUpdateInterval . Минимальный поддерживаемый интервал обновления составляет 5 секунд. Максимальный поддерживаемый интервал обновления составляет 60 секунд. Более частые обновления могут привести к более медленным запросам и ошибкам.

    Отключить обновления местоположения

    Ваше приложение может отключить обновления местоположения для автомобиля. Например, когда смена водителя заканчивается, ваше приложение может установить для locationTrackingEnabled значение NO .

      _vehicleReporter.locationTrackingEnabled = NO
    

    Обработка ошибок update_mask

    Когда GMTDDeliveryVehicleReporter отправляет обновление транспортного средства, может возникнуть ошибка update_mask , когда маска пуста, и обычно это происходит при первом обновлении после запуска. В следующем примере показано, как обработать эту ошибку:

    Быстрый

    import GoogleRidesharingDriver
    
    class VehicleReporterListener: NSObject, GMTDVehicleReporterListener {
      func vehicleReporter(
        _ vehicleReporter: GMTDVehicleReporter,
        didFail vehicleUpdate: GMTDVehicleUpdate,
        withError error: Error
      ) {
        let fullError = error as NSError
        if let innerError = fullError.userInfo[NSUnderlyingErrorKey] as? NSError {
          let innerFullError = innerError as NSError
          if innerFullError.localizedDescription.contains("update_mask cannot be empty") {
            emptyMaskUpdates += 1
            return
          }
        }
        failedUpdates += 1
      }
    
      override init() {
        emptyMaskUpdates = 0
        failedUpdates = 0
      }
    }
    
    

    Цель-C

    #import "VehicleReporterListener.h"
    #import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
    
    @implementation VehicleReporterListener {
      NSInteger emptyMaskUpdates = 0;
      NSInteger failedUpdates = 0;
    }
    
    - (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter
      didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate
                 withError:(NSError *)error {
      for (NSError *underlyingError in error.underlyingErrors) {
        if ([underlyingError.localizedDescription containsString:@"update_mask cannot be empty"]) {
          emptyMaskUpdates += 1;
          return;
        }
      }
      failedUpdates += 1
    }
    
    @end