iOS 版 Driver SDK 使用入门

驱动程序 SDK 是一个可集成到驱动程序应用中的库。时间是 负责根据车辆的位置、路线、 剩余距离和预计到达时间。它还与 Navigation SDK 集成,后者可用于 为驾驶员提供精细导航指示。

最低系统要求

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

    本指南假定您的应用已实现 Navigation SDK 以及 舰队引擎 后端已设置完毕且可用不过,示例代码提供 此示例展示了如何设置 Navigation SDK

    您还必须启用 Maps SDK for iOS 在您的 Google Cloud 项目中,并获取 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 或手动配置 iOS 版驱动程序 SDK。

    使用 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 install 命令。这会安装 Podfile 及其可能具有的任何依赖项。

      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。 如果看不到这些设置,请将“构建设置”栏中的过滤条件从基本更改为全部

    Alpha/Beta 版 SDK

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

    • CocoaPods 工具:要安装此工具,请打开终端并运行 。

      sudo gem install cocoapods
      

      请参阅 CocoaPods 入门指南 了解详情。

    • 您的开发账号已列入 Google 访问权限列表。Pod 代码库 Alpha 版和 Beta 版 SDK 不是公开源代码。接收者 请联系 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 install 命令。此命令会安装 及其可能具有的任何依赖项。

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

    检查 Apple 隐私清单文件

    Apple 要求为 App Store 中的应用提供应用隐私权详细信息。如需了解最新动态和更多信息,请访问 Apple App Store 隐私权详情页面

    Apple 隐私清单文件包含在 SDK 的资源包中。如需验证隐私清单文件是否包含在内并检查其内容,请创建应用的归档,并从归档中生成隐私报告

    实现授权和身份验证

    当您的驱动程序应用生成更新并将其发送到 Fleet Engine 后端时, 请求必须包含有效的访问令牌。要授权并 对请求进行身份验证后,驱动程序 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 实例,您首先需要创建一个 GMTDDeliveryDriverAPI 实例的 providerIDvehicleIDdriverContextaccessTokenProviderproviderID等同于 Google Cloud 项目 ID。您可以访问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 事件

    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 设置为 YES GMTDDeliveryVehicleReporter。然后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