iOS 版 Driver SDK 使用入门

Driver SDK 是您集成到驾驶员应用中的库。它负责使用车辆位置、路线、剩余距离和预计到达时间更新 Fleet Engine。此外,它还与 Navigation SDK 集成,后者可为驾驶员提供精细导航说明。

最低系统要求

  • 移动设备必须搭载 iOS 13 或更高版本。
  • Xcode 版本 14 或更高版本。
  • 前提条件

    本指南假定您的应用已实现 Navigation SDK,并且 Fleet Engine 后端已设置且可用。不过,示例代码提供了如何设置 Navigation SDK 的示例。

    您还必须在 Google Cloud 项目中启用 Maps SDK for iOS获取 API 密钥

    获取使用权限

    如果您是 Google Workspace 客户,请在初始配置期间创建一个 Workspace 群组(例如 google-maps-platform-sdk-users@workspacedomain.com),并向 Google 提供其名称。这是推荐的方法。 然后,您的工作区群组就会添加到许可名单中,该许可名单可授予对正确 CocoaPods 代码库的访问权限。确认此列表中包含需要访问权限的用户电子邮件地址和服务帐号电子邮件地址。

    如果贵组织无法创建工作区群组,请向 Google 发送需要访问这些工件的用户和服务帐号电子邮件地址列表。

    本地开发

    对于本地开发,使用 Cloud SDK 登录即可。

    gcloud

    gcloud auth login
    

    用于登录的电子邮件地址必须是 Workspace 群组的成员。

    自动化(构建系统或持续集成)

    根据最佳实践设置自动化主机:

    • 如果您的进程在 Google Cloud 环境中运行,请使用自动凭据检测。

    • 否则,请将服务帐号密钥文件存储在主机文件系统上的安全位置,并适当设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量。

    与凭据关联的服务帐号电子邮件地址必须是工作区群组的成员。

    项目配置

    您可以使用 Cocoapods 或手动配置 Driver SDK for iOS。

    使用 Cocoapods

    要配置 iOS 版驱动程序 SDK,您需要具备以下各项:

    • CocoaPods 工具:如需安装此工具,请打开终端并运行以下命令。 shell sudo gem install cocoapods 如需了解详情,请参阅 CocoaPods 入门指南
    1. 为 iOS 版驱动程序 SDK 创建 Podfile,并使用它来安装 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 中指定的 API 及其可能具有的任何依赖项。

      pod install
      
    4. 关闭 Xcode,然后打开(双击)您项目的 .xcworkspace 文件以启动 Xcode。从此刻开始,您必须使用 .xcworkspace 文件打开项目。

    安装 XCFramework

    下载 SDK 二进制文件和资源:

    XCFramework 是用于安装驱动程序 SDK 的二进制软件包。您可以在多个平台(包括使用 M1 芯片组的机器)上使用此软件包。本指南介绍了如何将包含驱动程序 SDK 的 XCFramework 手动添加到您的项目中,以及如何在 Xcode 中配置构建设置。

    1. 将解压缩的文件解压缩以访问 XCFramework 和资源。

    2. 启动 Xcode,并打开现有项目或创建一个新项目。如果您是 iOS 新手,请创建一个新项目,然后选择 iOS 应用模板。

    3. 在项目组下创建一个框架组(如果还没有的话)。

    4. 将下载的 gRPCCertificates.bundle 文件拖动到您的 Xcode 项目的顶级目录中。出现提示时,选择“Copy items if needed”。

    5. 如需安装驱动程序 SDK,请将 GoogleRidesharingDriver.xcframework 文件拖动到框架、库和嵌入式内容下的项目中。出现提示时,选择“Copy items if needed”。

    6. 将下载的 GoogleRidesharingDriver.bundle 拖动到您的 Xcode 项目的顶级目录中。出现提示时,选择 Copy items if needed

    7. 从项目导航器中选择您的项目,然后选择应用的目标。

    8. 打开“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
      • LocalAuthentication.framework
      • OpenGLES.framework
      • QuartzCore.framework
      • SystemConfiguration.framework
      • UIKit.framework
      • WebKit.framework
    9. 选择您的项目(而不是特定目标),并打开“Build Settings”(构建设置)标签页。Other Linker Flags 部分中,添加用于调试和发布的 ‑ObjC。 如果看不到这些设置,请在“Build Settings”(构建设置)栏中,将过滤条件从 Basic(基本)更改为 All(全部)。

    Alpha/Beta 版 SDK 版本

    如需配置适用于 iOS 的 Alpha 版或 Beta 版驱动程序 SDK,您需要以下各项:

    • CocoaPods 工具:如需安装此工具,请打开终端并运行以下命令。

      sudo gem install cocoapods
      

      如需了解详情,请参阅 CocoaPods 入门指南

    • 您的开发帐号在 Google 访问权限列表中。Alpha 版和 Beta 版 SDK 的 Pod 代码库不是公开源代码。如需使用这些版本,请与 Google 客户工程师联系。该工程师将您的开发帐号添加到访问权限列表中,然后设置用于身份验证的 Cookie

    您的项目显示在访问权限列表中后,您可以访问该 Pod。

    1. 为 iOS 版驱动程序 SDK 创建 Podfile,并使用它来安装 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 中指定的 API 及其可能具有的任何依赖项。

      pod install
      
    4. 关闭 Xcode,然后打开(双击)您项目的 .xcworkspace 文件以启动 Xcode。从此刻开始,您必须使用 .xcworkspace 文件打开项目。

    实现授权和身份验证

    当驱动程序应用生成更新并将其发送到 Fleet Engine 后端时,请求必须包含有效的访问令牌。为了对这些请求进行授权和身份验证,Driver SDK 会按照 GMTDAuthorization 协议调用您的对象。该对象负责提供所需的访问令牌。

    作为应用开发者,您可以选择令牌的生成方式。您的实现应能够执行以下操作:

    • 从 HTTPS 服务器提取访问令牌(可能采用 JSON 格式)。
    • 解析并缓存令牌。
    • 请在令牌过期后刷新令牌。

    如需详细了解 Fleet Engine 服务器预期的令牌,请参阅创建 JSON 网络令牌 (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 实例,您首先需要使用 providerIDvehicleIDdriverContextaccessTokenProvider 创建一个 GMTDDeliveryDriverAPI 实例。providerID 与 Google Cloud 项目 ID 相同。您也可以直接从驱动程序 API 访问 GMTDDeliveryVehicleReporter 实例。

    以下示例创建了一个 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 事件

    locationTrackingEnabled 为“是”时,GMTDDeliveryVehicleReporter 会定期更新车辆。为了响应这些定期更新,任何对象都可以通过符合 GMTDVehicleReporterListener 协议来订阅 GMTDDeliveryVehicleReporter 事件。

    您可以处理以下事件:

    • 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
    

    启用位置跟踪

    如需启用位置信息跟踪,您的应用可以在 GMTDDeliveryVehicleReporter 上将 locationTrackingEnabled 设置为 YES。然后,GMTDDeliveryVehicleReporter 会自动发送位置信息更新。当 GMSNavigator 处于导航模式(通过 setDestinations 设置目的地时)且 locationTrackingEnabled 设置为 YES 时,GMTDDeliveryVehicleReporter 也会自动发送路线和预计到达时间更新。

    在这些更新期间设置的路线与驾驶员在导航会话期间导航到的路线相同。因此,为了使舰队跟踪正常运行,通过 -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