開始使用 iOS 版 Driver SDK

Driver SDK 是整合至驅動程式應用程式的程式庫。是 負責更新 Fleet Engine 與駕駛人的位置、路線 距離剩餘距離,以及預計到達時間這個 SDK 也整合了 Navigation SDK 為駕駛提供即時路線導航指示。

基本系統需求

  • 行動裝置必須搭載 iOS 14 以上版本。
  • Xcode 15 以上版本。
  • 必要條件

    本指南假設您的應用程式已實作 Navigation SDK,且 機群引擎 皆已設定完成不過,範例程式碼提供 範例說明如何設定 Navigation SDK

    您也必須啟用 Maps SDK for iOS ,然後取得 API 金鑰

    取得使用權限

    如果您是 Google Workspace 客戶,請建立 Workspace 群組,例如 在新手上路期間使用 google-maps-platform-sdk-users@workspacedomain.com,以及 向 Google 提供名稱建議您採取這種做法。 您的 Workspace 群組會加入許可清單 會授予正確的 CocoaPods 存放區存取權。確認使用者 需要存取權的電子郵件和服務帳戶電子郵件都列在這份清單中。

    如果貴機構無法建立 Workspace 群組,請將名單傳送給 Google 存取這些構件的使用者及服務帳戶電子郵件。

    本機開發

    如要進行本機開發,使用 Cloud SDK

    gcloud

    gcloud auth login
    

    用來登入的電子郵件地址必須是 Workspace 群組的成員。

    自動化 (建構系統或持續整合)

    根據以下項目設定自動化主機: 最佳做法

    • 如果您的程序是在 Google Cloud 環境中執行,請使用 自動 憑證偵測

    • 否則,請將服務帳戶金鑰檔案儲存在 並將金鑰設為 GOOGLE_APPLICATION_CREDENTIALS 環境變數

    與憑證相關聯的服務帳戶電子郵件地址必須是 開始練習

    專案設定

    您可以使用 CocoaPods 設定驅動程式 SDK。

    使用 CocoaPods

    如要使用 CocoaPods 設定 Driver SDK,您必須備妥下列項目:

    • CocoaPods 工具:如要安裝此工具,請開啟終端機並執行 。 shell sudo gem install cocoapods 詳情請參閱 CocoaPods 入門指南 ,掌握更多詳細資訊。
    1. 建立驅動程式 SDK 的 Podfile,並使用該 Pod 來安裝 API 及其依附元件:在專案中建立名為 Podfile 的檔案 目錄。這個檔案定義了專案的依附元件。編輯 Podfile 並新增依附元件這個例子包含了 依附元件:

      source "https://github.com/CocoaPods/Specs.git"
      
      target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
        pod 'GoogleRidesharingDriver'
      end
      
    2. 儲存 Podfile。開啟終端機並前往包含 Podfile:

      cd <path-to-project>
      
    3. 執行 pod 安裝指令。這個指令會安裝 Podfile 及其所有依附元件。

      pod install
      
    4. 關閉 Xcode,然後開啟 (按兩下) 專案的 .xcworkspace 檔案 來啟動 Xcode從現在起,您必須使用 .xcworkspace 檔案 開啟專案

    Alpha/Beta 版 SDK 版本

    您需要設定 iOS 版 Driver SDK 的 Alpha 或 Beta 版本 下列項目:

    • CocoaPods 工具:如要安裝此工具,請開啟終端機並執行 。

      sudo gem install cocoapods
      

      詳情請參閱 CocoaPods 入門指南 ,掌握更多詳細資訊。

    • Google 存取清單上的開發人員帳戶。Pod 存放區 的 SDK 的 Alpha 和 Beta 版本並非公開來源。目的地: 存取這些版本,請與 Google 客戶工程師聯絡。 工程師會將您的開發帳戶新增至存取清單, 就會設定 Cookie 驗證。

    當專案列入存取清單後,您就可以存取 Pod。

    1. 建立 iOS 專用 Driver SDK 的 Podfile,然後透過該 Pod 安裝 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. 儲存 Podfile。開啟終端機並前往包含 Podfile:

      cd <path-to-project>
      
    3. 執行 pod 安裝指令。這個指令會安裝 Podfile 及其所有依附元件。

      pod install
      
    4. 關閉 Xcode,然後開啟 (按兩下) 專案的 .xcworkspace 檔案 來啟動 Xcode從現在起,您必須使用 .xcworkspace 檔案 開啟專案

    安裝 XCFramework

    XCFramework 是用於安裝驅動程式 SDK 的二進位套件。這個套件可用於多個平台,包括使用 M1 晶片組的機器。 本指南說明如何手動將含有驅動程式 SDK 的 XCFramework 新增至專案,並在 Xcode 中進行建構設定。

    下載 SDK 二進位檔和資源:

    1. 將壓縮的檔案解壓縮,以存取 XCFramework 和資源。

    2. 啟動 Xcode,然後開啟現有專案,或建立新專案。如果您是 iOS 新手,請建立新專案並選取 iOS 應用程式範本。

    3. 如果沒有架構群組,請在專案群組下建立。

    4. 將下載的 gRPCCertificates.bundle 檔案拖曳至 Xcode 專案的頂層目錄。畫面上出現提示時,請視需要選取「複製項目」。

    5. 如要安裝驅動程式 SDK,請將 GoogleRidesharingDriver.xcframework 檔案拖曳到專案「Frameworks、Library 和 Embedded Content」下方。畫面上出現提示時,請視需要選取「複製項目」。

    6. 將下載的 GoogleRidesharingDriver.bundle 拖曳至 Xcode 專案的頂層目錄。系統提示時,請選取 Copy items if needed

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

    8. 開啟「建構階段」分頁,然後在連結二進位檔和程式庫的連結二進位檔中,加入下列架構和程式庫 (如果尚未加入):

      • 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
    9. 選擇您的專案 (而非特定目標),然後開啟「Build Settings」分頁。在「Other Linker Flags」部分中,為偵錯和發布版本新增 ‑ObjC。 如果您沒有看到這些設定,請將「Build Settings」列中的篩選器從「Basic」變更為「All」

    檢查 Apple 隱私權資訊清單檔案

    Apple 要求在 App Store 上架應用程式,要求取得應用程式隱私權詳細資訊。如需最新資訊和其他資訊,請前往 Apple App Store 隱私權詳細資料頁面

    Apple 隱私權資訊清單檔案包含在 SDK 資源套件中。如要確認隱私權資訊清單檔案已納入並檢查其中的內容,請建立應用程式的封存檔案,然後從封存檔中產生隱私權報告

    實作授權和驗證

    當驅動程式應用程式產生更新並傳送至 Fleet Engine 後端時, 要求必須包含有效的存取權杖。為了授權及 驗證這些要求之後,驅動程式 SDK 會呼叫符合 GMTDAuthorization 因此效能相當卓越這個物件負責提供必要的存取權杖。

    應用程式開發人員可以選擇產生權杖的產生方式,實作項目 應能夠執行下列操作:

    • 從 HTTPS 伺服器擷取存取權杖 (可能為 JSON 格式)。
    • 剖析及快取權杖。
    • 請在權杖過期時重新整理。

    如要進一步瞭解 Fleet Engine 伺服器預期的權杖,請參閱 建立用於授權的 JSON Web Token (JWT)

    提供者 ID 與 Google Cloud 專案 ID 相同。 請參閱 Fleet Engine Deliveries API 使用手冊 瞭解詳情

    以下範例實作存取權杖供應工具:

    #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) carID、driveContext 和 accessTokenProvider。providerID 與 Google Cloud 專案 ID。此外,您可以存取 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 為「是」。如要回應這些定期更新, 物件可訂閱 GMTDDeliveryVehicleReporter 事件,方法是遵守 GMTDVehicleReporterListener 通訊協定。

    您可以處理下列事件:

    • vehicleReporter:didSucceedVehicleUpdate

      通知駕駛應用程式,後端服務已成功收到 車輛位置和狀態更新。

    • 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 設為 YESGMTDDeliveryVehicleReporter。則 GMTDDeliveryVehicleReporter 將會 = 自動傳送位置更新資訊。GMSNavigator在導航期間 模式 (當目的地透過 setDestinations 設定時) 和 locationTrackingEnabled已設為 YESGMTDDeliveryVehicleReporter 會 自動傳送路線和預計到達時間。

    這些更新期間設定的路線會與駕駛人行駛的路線相同 正在導航工作階段。因此,為了確保運送追蹤功能正常運作 正確,透過 -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 如果遮罩為空白,就有可能發生 更新。以下範例說明如何處理這個錯誤:

    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