跟踪行程时,您的消费者应用会向消费者显示相应车辆的位置。为此,您的应用需要开始跟踪行程,更新行程进度,并在行程结束后停止跟踪行程。
本文档介绍了该过程的运作方式。
开始跟踪行程
如需开始跟踪行程,请按以下步骤操作:
从
ViewController
收集所有用户输入,例如下车点和上车点。创建一个新的
ViewController
以直接开始跟踪行程。
以下示例展示了如何在视图加载后立即开始跟踪行程。
Swift
/*
* MapViewController.swift
*/
override func viewDidLoad() {
super.viewDidLoad()
...
self.mapView = GMTCMapView(frame: UIScreen.main.bounds)
self.mapView.delegate = self
self.view.addSubview(self.mapView)
}
func mapViewDidInitializeCustomerState(_: GMTCMapView) {
self.mapView.pickupLocation = self.selectedPickupLocation
self.mapView.dropoffLocation = self.selectedDropoffLocation
self.startConsumerMatchWithLocations(
pickupLocation: self.mapView.pickupLocation!,
dropoffLocation: self.mapView.dropoffLocation!
) { [weak self] (tripName, error) in
guard let strongSelf = self else { return }
if error != nil {
// print error message.
return
}
let tripService = GMTCServices.shared().tripService
// Create a tripModel instance for listening the update of the trip
// specified by this trip name.
let tripModel = tripService.tripModel(forTripName: tripName)
// Create a journeySharingSession instance based on the tripModel
let journeySharingSession = GMTCJourneySharingSession(tripModel: tripModel)
// Add the journeySharingSession instance on the mapView for UI updating.
strongSelf.mapView.show(journeySharingSession)
// Register for the trip update events.
tripModel.register(strongSelf)
strongSelf.currentTripModel = tripModel
strongSelf.currentJourneySharingSession = journeySharingSession
strongSelf.hideLoadingView()
}
self.showLoadingView()
}
Objective-C
/*
* MapViewController.m
*/
- (void)viewDidLoad {
[super viewDidLoad];
...
self.mapView = [[GMTCMapView alloc] initWithFrame:CGRectZero];
self.mapView.delegate = self;
[self.view addSubview:self.mapView];
}
// Handle the callback when the GMTCMapView did initialized.
- (void)mapViewDidInitializeCustomerState:(GMTCMapView *)mapview {
self.mapView.pickupLocation = self.selectedPickupLocation;
self.mapView.dropoffLocation = self.selectedDropoffLocation;
__weak __typeof(self) weakSelf = self;
[self startTripBookingWithPickupLocation:self.selectedPickupLocation
dropoffLocation:self.selectedDropoffLocation
completion:^(NSString *tripName, NSError *error) {
__typeof(self) strongSelf = weakSelf;
GMTCTripService *tripService = [GMTCServices sharedServices].tripService;
// Create a tripModel instance for listening to updates to the trip specified by this trip name.
GMTCTripModel *tripModel = [tripService tripModelForTripName:tripName];
// Create a journeySharingSession instance based on the tripModel.
GMTCJourneySharingSession *journeySharingSession =
[[GMTCJourneySharingSession alloc] initWithTripModel:tripModel];
// Add the journeySharingSession instance on the mapView for updating the UI.
[strongSelf.mapView showMapViewSession:journeySharingSession];
// Register for trip update events.
[tripModel registerSubscriber:self];
strongSelf.currentTripModel = tripModel;
strongSelf.currentJourneySharingSession = journeySharingSession;
[strongSelf hideLoadingView];
}];
[self showLoadingView];
}
停止关注行程
行程结束或取消后,您会停止跟踪该行程。以下示例展示了如何停止分享正在进行的行程。
Swift
/*
* MapViewController.swift
*/
func cancelCurrentActiveTrip() {
// Stop the tripModel
self.currentTripModel.unregisterSubscriber(self)
// Remove the journey sharing session from the mapView's UI stack.
self.mapView.hide(journeySharingSession)
}
Objective-C
/*
* MapViewController.m
*/
- (void)cancelCurrentActiveTrip {
// Stop the tripModel
[self.currentTripModel unregisterSubscriber:self];
// Remove the journey sharing session from the mapView's UI stack.
[self.mapView hideMapViewSession:journeySharingSession];
}
更新行程进度
在行程期间,您可以按如下方式管理行程进度:
当行程完成或取消时,停止监听更新。如需查看示例,请参阅停止监听更新示例。
示例:开始监听更新
以下示例展示了如何注册 tripModel
回调。
Swift
/*
* MapViewController.swift
*/
override func viewDidLoad() {
super.viewDidLoad()
// Register for trip update events.
self.currentTripModel.register(self)
}
Objective-C
/*
* MapViewController.m
*/
- (void)viewDidLoad {
[super viewDidLoad];
// Register for trip update events.
[self.currentTripModel registerSubscriber:self];
...
}
示例:停止监听更新
以下示例展示了如何取消 tripModel
回调的注册。
Swift
/*
* MapViewController.swift
*/
deinit {
self.currentTripModel.unregisterSubscriber(self)
}
Objective-C
/*
* MapViewController.m
*/
- (void)dealloc {
[self.currentTripModel unregisterSubscriber:self];
...
}
处理行程更新示例
以下示例展示了如何实现 GMTCTripModelSubscriber
协议,以在行程状态更新时处理回调。
Swift
/*
* MapViewController.swift
*/
func tripModel(_: GMTCTripModel, didUpdate trip: GMTSTrip?, updatedPropertyFields: GMTSTripPropertyFields) {
// Update the UI with the new `trip` data.
self.updateUI(with: trip)
}
func tripModel(_: GMTCTripModel, didUpdate tripStatus: GMTSTripStatus) {
// Handle trip status did change.
}
func tripModel(_: GMTCTripModel, didUpdateActiveRouteRemainingDistance activeRouteRemainingDistance: Int32) {
// Handle remaining distance of active route did update.
}
func tripModel(_: GMTCTripModel, didUpdateActiveRoute activeRoute: [GMTSLatLng]?) {
// Handle trip active route did update.
}
func tripModel(_: GMTCTripModel, didUpdate vehicleLocation: GMTSVehicleLocation?) {
// Handle vehicle location did update.
}
func tripModel(_: GMTCTripModel, didUpdatePickupLocation pickupLocation: GMTSTerminalLocation?) {
// Handle pickup location did update.
}
func tripModel(_: GMTCTripModel, didUpdateDropoffLocation dropoffLocation: GMTSTerminalLocation?) {
// Handle drop off location did update.
}
func tripModel(_: GMTCTripModel, didUpdatePickupETA pickupETA: TimeInterval) {
// Handle the pickup ETA did update.
}
func tripModel(_: GMTCTripModel, didUpdateDropoffETA dropoffETA: TimeInterval) {
// Handle the drop off ETA did update.
}
func tripModel(_: GMTCTripModel, didUpdateRemaining remainingWaypoints: [GMTSTripWaypoint]?) {
// Handle updates to the pickup, dropoff or intermediate destinations of the trip.
}
func tripModel(_: GMTCTripModel, didFailUpdateTripWithError error: Error?) {
// Handle the error.
}
func tripModel(_: GMTCTripModel, didUpdateIntermediateDestinations intermediateDestinations: [GMTSTerminalLocation]?) {
// Handle the intermediate destinations being updated.
}
func tripModel(_: GMTCTripModel, didUpdateActiveRouteTraffic activeRouteTraffic: GMTSTrafficData?) {
// Handle trip active route traffic being updated.
}
Objective-C
/*
* MapViewController.m
*/
#pragma mark - GMTCTripModelSubscriber implementation
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateTrip:(nullable GMTSTrip *)trip
updatedPropertyFields:(enum GMTSTripPropertyFields)updatedPropertyFields {
// Update the UI with the new `trip` data.
[self updateUIWithTrip:trip];
...
}
- (void)tripModel:(GMTCTripModel *)tripModel didUpdateTripStatus:(enum GMTSTripStatus)tripStatus {
// Handle trip status did change.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateActiveRouteRemainingDistance:(int32_t)activeRouteRemainingDistance {
// Handle remaining distance of active route did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateActiveRoute:(nullable NSArray<GMTSLatLng *> *)activeRoute {
// Handle trip active route did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateVehicleLocation:(nullable GMTSVehicleLocation *)vehicleLocation {
// Handle vehicle location did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdatePickupLocation:(nullable GMTSTerminalLocation *)pickupLocation {
// Handle pickup location did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateDropoffLocation:(nullable GMTSTerminalLocation *)dropoffLocation {
// Handle drop off location did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel didUpdatePickupETA:(NSTimeInterval)pickupETA {
// Handle the pickup ETA did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateRemainingWaypoints:(nullable NSArray<GMTSTripWaypoint *> *)remainingWaypoints {
// Handle updates to the pickup, dropoff or intermediate destinations of the trip.
}
- (void)tripModel:(GMTCTripModel *)tripModel didUpdateDropoffETA:(NSTimeInterval)dropoffETA {
// Handle the drop off ETA did update.
}
- (void)tripModel:(GMTCTripModel *)tripModel didFailUpdateTripWithError:(nullable NSError *)error {
// Handle the error.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateIntermediateDestinations:
(nullable NSArray<GMTSTerminalLocation *> *)intermediateDestinations {
// Handle the intermediate destinations being updated.
}
- (void)tripModel:(GMTCTripModel *)tripModel
didUpdateActiveRouteTraffic:(nullable GMTSTrafficData *)activeRouteTraffic {
// Handle trip active route traffic being updated.
}
处理行程错误
如果您订阅了 tripModel
并发生错误,则可以通过实现委托方法 tripModel(_:didFailUpdateTripWithError:)
来获取 tripModel
的回调。错误消息遵循 Google Cloud 错误标准。如需详细了解错误消息定义和所有错误代码,请参阅 Google Cloud 错误文档。
以下是行程监控期间可能发生的一些常见错误:
HTTP | RPC | 说明 |
---|---|---|
400 | INVALID_ARGUMENT | 客户端指定的的行程名称无效。行程名称必须遵循格式 providers/{provider_id}/trips/{trip_id} 。provider_id 必须是服务提供商所拥有的 Cloud 项目的 ID。 |
401 | UNAUTHENTICATED | 如果没有有效的身份验证凭据,您会收到此错误。 例如,在 JWT 令牌签名时不含行程 ID,或者 JWT 令牌已过期。 |
403 | PERMISSION_DENIED | 如果客户端没有足够的权限(例如,具有消费者角色的用户尝试调用 updateTrip),如果 JWT 令牌无效,或者客户端项目未启用该 API,您会收到此错误。 可能缺少 JWT 令牌,或者令牌在签名时使用的行程 ID 与请求的行程 ID 不匹配。 |
429 | RESOURCE_EXHAUSTED | 资源配额为零或流量超出限制。 |
503 | UNAVAILABLE | 服务不可用。通常是服务器已关闭。 |
504 | DEADLINE_EXCEEDED | 超出请求时限。仅当调用方设置的时限短于方法的默认时限(即请求的时限不足以让服务器处理请求)且请求未在时限内完成时,才会发生此错误。 |
处理使用方 SDK 错误
使用方 SDK 会使用回调机制将行程更新错误发送到使用方应用。回调参数是平台专用的返回值类型(Android 上的 TripUpdateError
和 iOS 上的 NSError
)。
提取状态代码
传递给回调的错误通常是 gRPC 错误,您还可以从中提取状态代码形式的其他信息。如需查看状态代码的完整列表,请参阅 gRPC 中的状态代码及其用法。
Swift
系统会在 tripModel(_:didFailUpdateTripWithError:)
中回调 NSError
。
// Called when there is a trip update error.
func tripModel(_ tripModel: GMTCTripModel, didFailUpdateTripWithError error: Error?) {
// Check to see if the error comes from gRPC.
if let error = error as NSError?, error.domain == "io.grpc" {
let gRPCErrorCode = error.code
...
}
}
Objective-C
NSError
会在 tripModel:didFailUpdateTripWithError:
中回调。
// Called when there is a trip update error.
- (void)tripModel:(GMTCTripModel *)tripModel didFailUpdateTripWithError:(NSError *)error {
// Check to see if the error comes from gRPC.
if ([error.domain isEqualToString:@"io.grpc"]) {
NSInteger gRPCErrorCode = error.code;
...
}
}
解读状态代码
状态代码涵盖两种错误:服务器和网络相关错误,以及客户端错误。
服务器和网络错误
以下状态代码针对的是网络错误或服务器错误,您无需采取任何措施来解决这些问题。而 Consumer SDK 会自动从中恢复。
状态代码 | 说明 |
---|---|
ABORTED | 服务器已停止发送响应。这通常是由服务器问题导致的。 |
已取消 | 服务器终止了外发响应。当 应用被发送到后台,或 消费者应用中的状态发生变化时,通常会发生这种情况。 |
INTERRUPTED | |
DEADLINE_EXCEEDED | 服务器的响应时间过长。 |
UNAVAILABLE | 服务器不可用。这通常是由网络问题导致的。 |
客户端错误
以下状态代码针对的是客户端错误,您必须采取措施来解决这些问题。在您结束行程共享之前,Consumer SDK 会继续重试刷新行程,但在您采取行动之前,行程不会恢复。
状态代码 | 说明 |
---|---|
INVALID_ARGUMENT | 消费者应用指定的的行程名称无效;行程名称必须采用 providers/{provider_id}/trips/{trip_id} 格式。
|
NOT_FOUND | 此行程从未创建。 |
PERMISSION_DENIED | 消费者应用权限不足。在以下情况下,会发生此错误:
|
RESOURCE_EXHAUSTED | 资源配额为零,或者流量速率超出速率限制。 |
UNAUTHENTICATED | 由于 JWT 令牌无效,请求未通过身份验证。如果 JWT 令牌签名时没有行程 ID,或者 JWT 令牌已过期,就会发生此错误。 |