Pierwsze kroki z pakietem SDK Driver na iOS

Pakiet Driver SDK to biblioteka zintegrowana z aplikacją sterownika. Odpowiada za aktualizowanie Fleet Engine o lokalizację kierowcy, trasę, pozostały dystans i szacowany czas dotarcia. Integruje się też z pakietem Navigation SDK, który zawiera szczegółowe instrukcje nawigacji dla kierowcy.

Minimalne wymagania systemowe

  • Na urządzeniu mobilnym musi być zainstalowany iOS 13 lub nowszy.
  • Xcode w wersji 14 lub nowszej.
  • Wymagania wstępne

    W tym przewodniku zakładamy, że Twoja aplikacja korzysta już z nawigacji SDK oraz że backend Fleet Engine jest skonfigurowany i dostępny. Ten przykładowy kod pokazuje jednak, jak skonfigurować pakiet SDK nawigacji.

    Musisz też włączyć w projekcie Google Cloud pakiet SDK Map Google na iOS i uzyskać klucz interfejsu API.

    Uzyskaj dostęp

    Jeśli jesteś klientem Google Workspace, podczas rejestracji utwórz grupę dyskusyjną Workspace, na przykład google-maps-platform-sdk-users@workspacedomain.com, i podaj jej nazwę. To zalecana metoda. Twoja grupa Workspace zostanie dodana do listy dozwolonych, która zapewnia dostęp do odpowiednich repozytoriów CocoaPods. Upewnij się, że adresy e-mail użytkowników i konta usługi, które wymagają dostępu, znajdują się na tej liście.

    Jeśli Twoja organizacja nie może tworzyć grup Workspace, wyślij do Google listę adresów e-mail użytkowników i kont usługi, którzy potrzebują dostępu do tych artefaktów.

    Programowanie lokalne

    W przypadku programowania lokalnego wystarczy zalogować się za pomocą pakietu SDK Cloud.

    gcloud

    gcloud auth login
    

    Adres e-mail używany do logowania musi należeć do grupy Workspace.

    Automatyzacja (systemy tworzenia systemów lub ciągłej integracji)

    Skonfiguruj hosty automatyzacji zgodnie ze sprawdzonymi metodami:

    • Jeśli proces działa w środowisku Google Cloud, użyj automatycznego wykrywania danych logowania.

    • W przeciwnym razie zapisz plik klucza konta usługi w bezpiecznej lokalizacji w systemie plików hosta i odpowiednio ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS.

    Adres e-mail konta usługi powiązany z danymi logowania musi należeć do grupy Workspace.

    Konfiguracja projektu

    Możesz skonfigurować pakiet SDK sterownika za pomocą CocoaPods.

    Korzystanie z CocoaPods

    Aby skonfigurować pakiet SDK sterownika za pomocą CocoaPods, potrzebujesz tych elementów:

    1. Utwórz plik Podfile dla pakietu Driver SDK i użyj go do zainstalowania interfejsu API i jego zależności: utwórz w katalogu projektu plik o nazwie Podfile. Ten plik określa zależności w projekcie. Edytuj plik Podfile i dodaj zależności. Oto przykład uwzględniający zależności:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. Zapisz plik Podfile. Otwórz terminal i przejdź do katalogu z plikiem Podfile:

      cd <path-to-project>
      
    3. Uruchom polecenie instalacji podów. Spowoduje to zainstalowanie interfejsów API określonych w pliku Podfile oraz wszystkich ich zależności.

      pod install
      
    4. Zamknij Xcode, a następnie otwórz (dwukrotnie) plik .xcworkspace swojego projektu, by uruchomić Xcode. Od tej pory projekt będzie można otwierać tylko za pomocą pliku .xcworkspace.

    Wersje pakietu SDK alfa i beta

    Aby skonfigurować wersję alfa lub beta pakietu Driver SDK na iOS, potrzebujesz tych elementów:

    • Narzędzie CocoaPods: aby zainstalować to narzędzie, otwórz terminal i uruchom to polecenie.

      sudo gem install cocoapods
      

      Więcej informacji znajdziesz w przewodniku dla początkujących.

    • Twoje konto programisty jest na liście dostępu Google. Repozytorium poda wersji alfa i beta pakietu SDK nie jest publicznym źródłem. Aby uzyskać dostęp do tych wersji, skontaktuj się z inżynierem Google ds. obsługi klienta. Inżynier dodaje Twoje konto dewelopera do listy dostępu, a następnie ustawia plik cookie do uwierzytelniania.

    Gdy projekt znajdzie się na liście dostępu, uzyskasz dostęp do poda.

    1. Utwórz plik Podfile dla pakietu Driver SDK na iOS i użyj go do zainstalowania interfejsu API i jego zależności: utwórz w katalogu projektu plik o nazwie Podfile. Ten plik określa zależności w projekcie. Edytuj plik Podfile i dodaj zależności. Oto przykład uwzględniający zależności:

      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. Zapisz plik Podfile. Otwórz terminal i przejdź do katalogu z plikiem Podfile:

      cd <path-to-project>
      
    3. Uruchom polecenie instalacji podów. Spowoduje to zainstalowanie interfejsów API określonych w pliku Podfile oraz wszystkich ich zależności.

      pod install
      
    4. Zamknij Xcode, a następnie otwórz (dwukrotnie) plik .xcworkspace swojego projektu, by uruchomić Xcode. Od tej pory projekt będzie można otwierać tylko za pomocą pliku .xcworkspace.

    Wdrażanie autoryzacji i uwierzytelniania

    Gdy aplikacja sterownika generuje i wysyła aktualizacje do backendu Fleet Engine, żądania muszą zawierać prawidłowe tokeny dostępu. Aby autoryzować i uwierzytelnić te żądania, pakiet SDK sterownika wywołuje obiekt zgodnie z protokołem GMTDAuthorization. Obiekt odpowiada za udostępnienie wymaganego tokena dostępu.

    Jako deweloper aplikacji możesz wybrać sposób generowania tokenów. Implementacja powinna umożliwiać:

    • Wygeneruj token dostępu w formacie JSON z serwera HTTPS.
    • Przeanalizuj i zapisz token w pamięci podręcznej.
    • Odśwież token, gdy straci ważność.

    Informacje o tokenach, których oczekuje serwer Fleet Engine, znajdziesz w sekcji Tworzenie tokena internetowego JSON (JWT) do autoryzacji.

    Identyfikator dostawcy jest taki sam jak identyfikator projektu Google Cloud. Więcej informacji znajdziesz w przewodniku użytkownika interfejsu API Fleet Engine Deliveries.

    Oto przykład implementowania dostawcy tokena dostępu:

    #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
    

    Tworzenie instancji DeliveryDriverAPI

    Aby pobrać instancję GMTDDeliveryVehicleReporter, musisz najpierw utworzyć instancję GMTDDeliveryDriverAPI przy użyciu identyfikatorów providerID, vehicleID, sterownikContext i accessTokenProvider. Identyfikator dostawcy jest taki sam jak identyfikator projektu Google Cloud. Instancja GMTDDeliveryVehicleReporter jest też dostępna bezpośrednio z poziomu interfejsu API sterownika.

    Ten przykład tworzy instancję 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];
    }
    

    Opcjonalnie nasłuchiwanie zdarzeń VehicleReporter

    GMTDDeliveryVehicleReporter okresowo aktualizuje pojazd, gdy locationTrackingEnabled ma wartość YES (TAK). Aby móc reagować na te okresowe aktualizacje, każdy obiekt może subskrybować zdarzenia GMTDDeliveryVehicleReporter zgodnie z protokołem GMTDVehicleReporterListener.

    Możesz obsługiwać te zdarzenia:

    • vehicleReporter:didSucceedVehicleUpdate

      Informuje aplikację sterownika, że usługi backendu pomyślnie otrzymały aktualizację lokalizacji i stanu pojazdu.

    • vehicleReporter:didFailVehicleUpdate:withError

      Informuje detektor, że aktualizacja pojazdu nie powiodła się. Dopóki śledzenie lokalizacji jest włączone, GMTDDeliveryVehicleReporter nadal wysyła najnowsze dane do backendu Fleet Engine.

    Ten przykład obsługuje te zdarzenia:

    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
    

    Włącz śledzenie lokalizacji

    Aby włączyć śledzenie lokalizacji, ustaw locationTrackingEnabled na YES w aplikacji GMTDDeliveryVehicleReporter. Następnie GMTDDeliveryVehicleReporter = automatycznie wysyła aktualizacje lokalizacji. Gdy GMSNavigator jest w trybie nawigacji (gdy miejsce docelowe jest ustawione na setDestinations), a locationTrackingEnabled ma wartość YES, GMTDDeliveryVehicleReporter automatycznie wysyła też informacje o trasie i szacowanym czasie dotarcia na miejsce.

    Trasa ustawiona podczas tych aktualizacji będzie tą samą trasą, którą kierowca porusza się podczas sesji nawigacji. Aby śledzenie przesyłki działało prawidłowo, punkt pośredni ustawiony w -setDestinations:callback: powinien być zgodny z miejscem docelowym ustawionym w backendzie Fleet Engine.

    Ten przykład umożliwia włączenie śledzenia lokalizacji:

    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
    

    Domyślnie interwał raportowania wynosi 10 sekund, ale można go zmienić za pomocą locationUpdateInterval. Minimalny obsługiwany interwał aktualizacji to 5 sekund. Maksymalny obsługiwany interwał aktualizacji to 60 sekund. Częstsze aktualizacje mogą powodować wolniejsze żądania i błędy.

    Wyłącz aktualizacje lokalizacji

    Twoja aplikacja może wyłączyć aktualizacje lokalizacji pojazdu. Na przykład, gdy kończy się zmiana kierowcy, aplikacja może ustawić locationTrackingEnabled na NO.

      _vehicleReporter.locationTrackingEnabled = NO
    

    Obsługa błędów update_mask

    Gdy GMTDDeliveryVehicleReporter wysyła aktualizację pojazdu, gdy maska jest pusta, może wystąpić błąd update_mask. Zwykle występuje on przy pierwszej aktualizacji po uruchomieniu. Z przykładu poniżej dowiesz się, jak obsłużyć ten błąd:

    Swift

    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
      }
    }
    
    

    Objective-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