Driver SDK를 사용하여 이동 및 주문 진행률 애플리케이션에 향상된 탐색 및 추적을 제공할 수 있습니다. Driver SDK는 주문형 차량 공유 및 배송 솔루션 Fleet Engine에 차량 위치 및 작업 업데이트를 제공합니다.
Driver SDK는 Fleet Engine 서비스와 커스텀 서비스가 차량의 위치와 상태를 인식하도록 합니다. 예를 들어 차량은 ONLINE
또는 OFFLINE
일 수 있고 이동이 진행됨에 따라 차량 위치가 변경됩니다.
최소 시스템 요구사항
기본 요건
이 가이드에서는 앱에서 이미 Navigation SDK를 구현했으며 Fleet Engine 백엔드가 설정되어 사용 가능하다고 가정합니다. 그러나 코드 예에서는 Navigation SDK를 설정하는 방법의 샘플을 제공합니다.
또한 Google Cloud 프로젝트에서 iOS용 Maps SDK를 사용 설정하고 API 키를 가져와야 합니다.
프로젝트 구성
CocoaPods를 사용하여 드라이버 SDK를 구성할 수 있습니다.
CocoaPods 사용
CocoaPods를 사용하여 드라이버 SDK를 구성하려면 다음 항목이 필요합니다.
- CocoaPods 도구: 이 도구를 설치하려면 터미널을 열고 다음 명령어를 실행합니다.
shell sudo gem install cocoapods
자세한 내용은 CocoaPods 시작 가이드를 참고하세요.
드라이버 SDK용 Podfile을 만들고 이를 사용하여 API 및 종속 항목을 설치합니다. 프로젝트 디렉터리에 Podfile이라는 파일을 만듭니다. 이 파일은 프로젝트의 종속 항목을 정의합니다. Podfile을 수정하고 종속 항목을 추가합니다. 다음은 종속 항목이 포함된 예입니다.
source "https://github.com/CocoaPods/Specs.git" target 'YOUR_APPLICATION_TARGET_NAME_HERE' do pod 'GoogleRidesharingDriver' end
다음은 드라이버 SDK의 알파 및 베타 포드를 종속 항목으로 포함하는 예입니다.
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
Podfile을 저장합니다. 터미널을 열고 Podfile이 있는 디렉터리로 이동합니다.
cd <path-to-project>
pod 설치 명령어를 실행합니다. 그러면 Podfile에 지정된 API가 종속 항목과 함께 설치됩니다.
pod install
Xcode를 닫은 후 프로젝트의 .xcworkspace 파일을 (더블클릭) 열어 Xcode를 실행합니다. 지금부터는 .xcworkspace 파일을 사용하여 프로젝트를 열어야 합니다.
알파/베타 SDK 버전
iOS용 드라이버 SDK의 알파 또는 베타 버전을 구성하려면 다음 항목이 필요합니다.
CocoaPods 도구: 이 도구를 설치하려면 터미널을 열고 다음 명령어를 실행합니다.
sudo gem install cocoapods
자세한 내용은 CocoaPods 시작 가이드를 참고하세요.
Google 액세스 목록에 있는 개발 계정 SDK 알파 및 베타 버전의 포드 저장소는 공개 소스가 아닙니다. 이러한 버전에 액세스하려면 Google 고객 엔지니어에게 문의하세요. 엔지니어가 개발 계정을 액세스 목록에 추가한 다음 인증을 위한 쿠키를 설정합니다.
프로젝트가 액세스 목록에 포함되면 포드에 액세스할 수 있습니다.
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
Podfile을 저장합니다. 터미널을 열고 Podfile이 있는 디렉터리로 이동합니다.
cd <path-to-project>
pod 설치 명령어를 실행합니다. 이 명령어는 Podfile에 지정된 API를 종속 항목과 함께 설치합니다.
pod install
Xcode를 닫은 후 프로젝트의 .xcworkspace 파일을 (더블클릭) 열어 Xcode를 실행합니다. 지금부터는 .xcworkspace 파일을 사용하여 프로젝트를 열어야 합니다.
승인 및 인증 구현
드라이버 앱이 업데이트를 생성하여 Fleet Engine 백엔드로 전송하는 경우 요청에 유효한 액세스 토큰이 포함되어야 합니다. 이러한 요청을 승인하고 인증하기 위해 드라이버 SDK는 GMTDAuthorization
프로토콜을 따라 객체를 호출합니다. 객체는 필요한 액세스 토큰을 제공합니다.
앱 개발자는 토큰 생성 방법을 선택할 수 있습니다. 구현을 통해 다음 작업을 할 수 있어야 합니다.
- HTTPS 서버에서 액세스 토큰을 가져옵니다(JSON 형식일 수도 있음).
- 토큰을 파싱하고 캐시합니다.
- 토큰이 만료되면 토큰을 새로고침합니다.
Fleet Engine 서버에서 예상하는 토큰에 대한 자세한 내용은 승인을 위한 JSON 웹 토큰 (JWT) 만들기를 참조하세요.
제공업체 ID는 Google Cloud 프로젝트 ID와 동일합니다. 자세한 내용은 Fleet Engine 빠른 시작 가이드를 참고하세요.
다음 예에서는 액세스 토큰 제공자를 구현합니다.
Swift
import GoogleRidesharingDriver
private let providerURL = "INSERT_YOUR_TOKEN_PROVIDER_URL"
class SampleAccessTokenProvider: NSObject, GMTDAuthorization {
private struct AuthToken {
// The cached vehicle token.
let token: String
// Keep track of when the token expires for caching.
let expiration: TimeInterval
// Keep track of the vehicle ID the cached token is for.
let vehicleID: String
}
enum AccessTokenError: Error {
case missingAuthorizationContext
case missingData
}
private var authToken: AuthToken?
func fetchToken(
with authorizationContext: GMTDAuthorizationContext?,
completion: @escaping GMTDAuthTokenFetchCompletionHandler
) {
// Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
guard let authorizationContext = authorizationContext else {
completion(nil, AccessTokenError.missingAuthorizationContext)
return
}
let vehicleID = authorizationContext.vehicleID
// If appropriate, use the cached token.
if let authToken = authToken,
authToken.expiration > Date.now.timeIntervalSince1970 && authToken.vehicleID == vehicleID
{
completion(authToken.token, nil)
return
}
// Otherwise, try to fetch a new token from your server.
let request = URLRequest(url: URL(string: providerURL))
let task = URLSession.shared.dataTask(with: request) { [weak self] data, _, error in
guard let strongSelf = self else { return }
guard error == nil else {
completion(nil, error)
return
}
// Replace the following key values with the appropriate keys based on your
// server's expected response.
let vehicleTokenKey = "VEHICLE_TOKEN_KEY"
let tokenExpirationKey = "TOKEN_EXPIRATION"
guard let data = data,
let fetchData = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let token = fetchData[vehicleTokenKey] as? String,
let expiration = fetchData[tokenExpirationKey] as? Double
else {
completion(nil, AccessTokenError.missingData)
return
}
strongSelf.authToken = AuthToken(
token: token, expiration: expiration, vehicleID: vehicleID)
completion(token, nil)
}
task.resume()
}
}
Objective-C
#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 {
// 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 vehicletoken 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
RidesharingDriverAPI 인스턴스 만들기
GMTDVehicleReporter
인스턴스를 가져오려면 먼저 providerID, 차량 ID, driveContext 및 accessTokenProvider를 사용하여 GMTDRidesharingDriverAPI
인스턴스를 만들어야 합니다. ProviderID는 Google Cloud 프로젝트 ID와 동일합니다. 또한 드라이버 API에서 직접 GMTDVehicleReporter
인스턴스에 액세스할 수 있습니다.
다음 예시에서는 GMTDRidesharingDriverAPI
인스턴스를 만듭니다.
Swift
import GoogleRidesharingDriver
private let providerID = "INSERT_YOUR_PROVIDER_ID"
class SampleViewController: UIViewController {
private let mapView: GMSMapView
override func viewDidLoad() {
super.viewDidLoad()
let vehicleID = "INSERT_CREATED_VEHICLE_ID"
let accessTokenProvider = SampleAccessTokenProvider()
let driverContext = GMTDDriverContext(
accessTokenProvider: accessTokenProvider,
providerID: providerID,
vehicleID: vehicleID,
navigator: mapView.navigator)
let ridesharingDriverAPI = GMTDRidesharingDriverAPI(driverContext: driverContext)
}
}
Objective-C
#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];
GMTDRidesharingDriverAPI *ridesharingDriverAPI = [[GMTDRidesharingDriverAPI alloc] initWithDriverContext:driverContext];
}
선택적으로 VehicleReporter 이벤트를 수신 대기
GMTDVehicleReporter
는 locationTrackingEnabled
가 true
일 때 차량을 주기적으로 업데이트합니다. 이러한 주기적인 업데이트에 응답하기 위해 모든 객체는 GMTDVehicleReporterListener
프로토콜을 준수하여 GMTDVehicleReporter
이벤트를 구독할 수 있습니다.
다음과 같은 이벤트를 처리할 수 있습니다.
vehicleReporter(_:didSucceed:)
백엔드 서비스가 차량 위치 및 상태 업데이트를 성공적으로 수신했다고 드라이버 앱에 알립니다.
vehicleReporter(_:didFail:withError:)
리스너에 차량 업데이트에 실패했음을 알립니다. 위치 추적이 사용 설정되어 있는 한
GMTDVehicleReporter
는 최신 데이터를 Fleet Engine 백엔드로 계속 전송합니다.
다음 예에서는 이러한 이벤트를 처리합니다.
Swift
import GoogleRidesharingDriver
private let providerID = "INSERT_YOUR_PROVIDER_ID"
class SampleViewController: UIViewController, GMTDVehicleReporterListener {
private let mapView: GMSMapView
override func viewDidLoad() {
// Assumes you have implemented the sample code up to this step.
ridesharingDriverAPI.vehicleReporter.add(self)
}
func vehicleReporter(_ vehicleReporter: GMTDVehicleReporter, didSucceed vehicleUpdate: GMTDVehicleUpdate) {
// Handle update succeeded.
}
func vehicleReporter(_ vehicleReporter: GMTDVehicleReporter, didFail vehicleUpdate: GMTDVehicleUpdate, withError error: Error) {
// Handle update failed.
}
}
Objective-C
/*
* 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 have implemented the sample code up to this step.
[ridesharingDriverAPI.vehicleReporter addListener:self];
}
- (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter didSucceedVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate {
// Handle update succeeded.
}
- (void)vehicleReporter:(GMTDVehicleReporter *)vehicleReporter didFailVehicleUpdate:(GMTDVehicleUpdate *)vehicleUpdate withError:(NSError *)error {
// Handle update failed.
}
@end
GMTDVehicleReporter를 GMSRoadSnappedLocationProvider에 리스너로 추가
드라이버 SDK에 위치 업데이트를 제공하려면 GMTDVehicleReporter
를 GMSRoadSnappedLocationProvider
의 리스너로 설정해야 합니다.
Swift
import GoogleRidesharingDriver
private let providerID = "INSERT_YOUR_PROVIDER_ID"
class SampleViewController: UIViewController, GMTDVehicleReporterListener {
private let mapView: GMSMapView
override func viewDidLoad() {
// Assumes you have implemented the sample code up to this step.
if let roadSnappedLocationProvider = mapView.roadSnappedLocationProvider {
roadSnappedLocationProvider.add(ridesharingDriverAPI.vehicleReporter)
roadSnappedLocationProvider.startUpdatingLocation()
}
}
}
Objective-C
/*
* 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 have implemented the sample code up to this step.
[_mapView.roadSnappedLocationProvider addListener:ridesharingDriverAPI.vehicleReporter];
[_mapView.roadSnappedLocationProvider startUpdatingLocation];
}
@end
위치 추적 사용 설정
위치 추적을 사용 설정하려면 GMTDVehicleReporter
에서 앱에서 locationTrackingEnabled
를 true
로 설정하면 됩니다. GMTDVehicleReporter
에서 자동으로 위치 업데이트를 전송합니다.
서비스가 일치하고 차량을 경로에 할당하고 나면 GMSNavigator
가 내비게이션 모드 (목적지가 setDestinations
를 통해 설정된 경우)가 되면 GMTDVehicleReporter
에서 자동으로 경로 업데이트를 전송합니다.
경로 업데이트 중에 설정된 경로는 운전자가 내비게이션 세션 중에 이동하는 경로와 동일합니다.
따라서 여정 공유가 올바르게 작동하려면 setDestinations
를 통해 설정된 경유지가 Fleet Engine 백엔드에 설정된 대상과 일치해야 합니다.
locationTrackingEnabled
가 true
로 설정된 경우 이동 및 차량 업데이트가 locationUpdateInterval
에 설정된 값을 기준으로 일정한 간격으로 Fleet Engine 백엔드로 전송됩니다. locationTrackingEnabled
이 false
로 설정되면 업데이트가 중지되고 최종 차량 업데이트 요청이 Fleet Engine 백엔드로 전송되어 차량 상태가 GMTDVehicleState.offline
로 설정됩니다.
locationTrackingEnabled
가 false
로 설정된 경우 실패를 처리하는 방법에 대한 특별 고려사항은 updateVehicleState
를 참조하세요.
다음 예는 위치 추적을 사용 설정합니다.
Swift
import GoogleRidesharingDriver
private let providerID = "INSERT_YOUR_PROVIDER_ID"
class SampleViewController: UIViewController, GMTDVehicleReporterListener {
private let mapView: GMSMapView
override func viewDidLoad() {
// Assumes you have implemented the sample code up to this step.
ridesharingDriverAPI.vehicleReporter.locationTrackingEnabled = true
}
}
Objective-C
/*
* 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 have implemented the sample code up to this step.
ridesharingDriverAPI.vehicleReporter.locationTrackingEnabled = YES;
}
@end
기본적으로 보고 간격은 10초이지만 보고 간격은 locationUpdateInterval
를 사용하여 변경할 수 있습니다. 지원되는 최소 업데이트 간격은 5초입니다. 지원되는 최대 업데이트 간격은 60초입니다. 자주 업데이트할수록 요청 및 오류가 느려질 수 있습니다.
차량 상태 업데이트
다음 예는 차량 상태를 ONLINE
로 설정하는 방법을 보여줍니다.
자세한 내용은 updateVehicleState
를 참조하세요.
Swift
import GoogleRidesharingDriver
private let providerID = "INSERT_YOUR_PROVIDER_ID"
class SampleViewController: UIViewController, GMTDVehicleReporterListener {
private let mapView: GMSMapView
override func viewDidLoad() {
// Assumes you have implemented the sample code up to this step.
ridesharingDriverAPI.vehicleReporter.update(.online)
}
}
Objective-C
#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 have implemented the sample code up to this step.
[ridesharingDriverAPI.vehicleReporter
updateVehicleState:GMTDVehicleStateOnline];
}
@end
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
위치 업데이트를 사용 중지하고 차량을 오프라인으로 전환합니다.
앱에서 업데이트를 사용 중지하고 차량을 오프라인으로 전환할 수 있습니다. 예를 들어 운전자의 교대 근무가 끝나면 앱에서 locationTrackingEnabled
를 false
로 설정할 수 있습니다. 또한 업데이트를 사용 중지하면 Fleet Engine 백엔드에서 차량 상태가 OFFLINE
로 설정됩니다.
Swift
vehicleReporter.locationTrackingEnabled = false
Objective-C
_vehicleReporter.locationTrackingEnabled = NO;