最后一公里舰队解决方案目前仅向部分客户提供。如需了解详情,请与销售人员联系

iOS 版 Driver SDK 使用入门

Driver SDK 是一个集成到驱动程序中的库。它负责使用舰队的位置、路线、剩余距离和预计到达时间更新 Fleet Engine。它还与 Navigation SDK 集成,Navigation SDK 可以为驾驶员提供精细导航。

最低系统要求

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

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

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

    获取使用权限

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

    如果您的组织无法创建 Workspace 群组,请向 Google 发送需要访问这些工件的用户和服务帐号列表。

    本地开发

    对于本地开发,使用 Cloud SDK 登录就足够了。

    gcloud

    gcloud auth login
    

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

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

    根据最佳做法设置自动化主机:

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

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

    与凭据关联的服务帐号电子邮件地址必须是 Workspace Goup 成员。

    项目配置

    您可以使用 CocoaPods 配置 Driver SDK。

    使用 CocoaPods

    如需使用 CocoaPods 配置 Driver SDK,您需要以下各项:

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

      sudo gem install cocoapods
      

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

    • Google 访问权限列表中的开发帐号。此 SDK 的 Pod 代码库没有公开来源。如需访问该 pod,请与 Google 客户工程师联系。工程师将您的开发帐号添加到访问权限列表中,然后设置 Cookie 以进行身份验证。

    将项目添加到访问权限列表中后,您就可以访问该 pod。

    1. 为 Driver SDK 创建一个 Podfile,并使用它安装 API 及其依赖项:在项目目录中创建一个名为 Podfile 的文件。此文件定义项目的依赖项。修改 Podfile 并添加依赖项。下面是一个包含依赖项的示例:

      source "https://cpdc-eap.googlesource.com/ridesharing-driver-sdk.git"
      source "https://cpdc-eap.googlesource.com/geo-nav-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 文件打开项目。

    安装 XCFramework

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

    1. 解压缩您从 Google 收到的源文件。

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

    3. 在您的项目组下创建一个框架组(如果尚不存在)。

    4. 将包含 XCFramework 的 ZIP 文件所在 Resources 目录下的 gRPCCertificates.bundle 文件拖动到 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(构建设置)标签页。在 Other Linker Flags(其他链接器标记)部分中,为调试和发布添加 ‑ObjC。 如果您看不到这些设置,请在“构建设置”栏中将过滤条件从基本改为全部

    实现授权和身份验证

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

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

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

    如需详细了解 Fleet Engine 服务器预期的令牌,请参阅创建 JSON Web 令牌 (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 实例,您首先需要使用 providerID、VehicleID、driverContext 和 accessTokenProvider 创建 GMTDDeliveryDriverAPI 实例。provider ID 与 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 为 YES 时,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 还会自动发送路线和 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