ติดตามการเดินทางใน iOS

เลือกแพลตฟอร์ม Android iOS JavaScript

เมื่อคุณติดตามการเดินทาง แอปสำหรับผู้บริโภคจะแสดงตำแหน่งของยานพาหนะที่เหมาะสมให้ผู้บริโภคเห็น ในการดำเนินการดังกล่าว แอปของคุณต้องเริ่มติดตามการเดินทาง อัปเดตความคืบหน้าของการเดินทาง และหยุดติดตามการเดินทางเมื่อการเดินทางเสร็จสมบูรณ์

เอกสารนี้กล่าวถึงวิธีการทำงานของกระบวนการดังกล่าว

เริ่มติดตามการเดินทาง

วิธีเริ่มติดตามการเดินทางมีดังนี้

  • รวบรวมข้อมูลทั้งหมดจากผู้ใช้ทั้งหมด เช่น จุดส่งและจุดรับจาก 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];
  ...
}

ตัวอย่างการหยุดฟังข้อมูลอัปเดต

ตัวอย่างต่อไปนี้แสดงวิธียกเลิกการลงทะเบียนของ Callback 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 ได้โดยใช้วิธีผู้รับมอบสิทธิ์ tripModel(_:didFailUpdateTripWithError:) ซึ่งข้อความแสดงข้อผิดพลาดจะเป็นไปตามมาตรฐานข้อผิดพลาดของ Google Cloud ดูคำจำกัดความของข้อความแสดงข้อผิดพลาดโดยละเอียดและรหัสข้อผิดพลาดทั้งหมดได้จากเอกสารประกอบเกี่ยวกับข้อผิดพลาดของ Google Cloud

ข้อผิดพลาดที่พบบ่อยซึ่งอาจเกิดขึ้นระหว่างการตรวจสอบการเดินทางมีดังนี้

HTTP RPC คำอธิบาย
400 INVALID_ARGUMENT ไคลเอ็นต์ระบุชื่อการเดินทางไม่ถูกต้อง ชื่อการเดินทางต้องเป็นไปตามรูปแบบ providers/{provider_id}/trips/{trip_id} provider_id ต้องเป็นรหัสของโปรเจ็กต์ที่อยู่ในระบบคลาวด์ซึ่งผู้ให้บริการเป็นเจ้าของ
401 ไม่มีการตรวจสอบสิทธิ์ คุณจะได้รับข้อผิดพลาดนี้หากไม่มีข้อมูลเข้าสู่ระบบการตรวจสอบสิทธิ์ที่ถูกต้อง เช่น หากโทเค็น JWT มีการรับรองโดยไม่มีรหัสการเดินทาง หรือโทเค็น JWT หมดอายุ
403 PERMISSION_DENIED คุณจะได้รับข้อผิดพลาดนี้หากไคลเอ็นต์มีสิทธิ์ไม่เพียงพอ (เช่น ผู้ใช้ที่มีบทบาทผู้บริโภคพยายามเรียกใช้ updateTrip) หากโทเค็น JWT ไม่ถูกต้อง หรือไม่ได้เปิดใช้ API สำหรับโปรเจ็กต์ไคลเอ็นต์ โทเค็น JWT อาจหายไปหรือลงนามโทเค็นด้วยรหัสการเดินทางที่ไม่ตรงกับรหัสการเดินทางที่ขอ
429 RESOURCE_EXHAUSTED โควต้าทรัพยากรเป็น 0 หรืออัตราการเข้าชมเกินขีดจํากัด
503 UNAVAILABLE ไม่พร้อมให้บริการ โดยทั่วไปแล้ว เซิร์ฟเวอร์จะหยุดทำงาน
504 DEADLINE_EXCEEDED เกินกำหนดเวลาในการส่งคำขอแล้ว ข้อผิดพลาดนี้จะเกิดขึ้นก็ต่อเมื่อผู้เรียกใช้กําหนดเวลาให้สั้นกว่าเวลาหมดอายุเริ่มต้นของเทมเพลต (กล่าวคือ เวลาหมดอายุที่ขอไม่เพียงพอสําหรับให้เซิร์ฟเวอร์ประมวลผลคําขอ) และคำขอไม่เสร็จสิ้นภายในเวลาดังกล่าว

จัดการข้อผิดพลาดของ Consumer SDK

Consumer SDK จะส่งข้อผิดพลาดในการอัปเดตการเดินทางไปยังแอปของผู้บริโภคโดยใช้กลไก Callback พารามิเตอร์การเรียกกลับคือประเภทผลลัพธ์เฉพาะแพลตฟอร์ม ( TripUpdateError ใน Android และ NSError ใน iOS)

ดึงรหัสสถานะ

โดยปกติแล้ว ข้อผิดพลาดที่ส่งไปยังการเรียกกลับจะเป็นข้อผิดพลาด gRPC และคุณยังดึงข้อมูลเพิ่มเติมจากข้อผิดพลาดเหล่านั้นในรูปแบบรหัสสถานะได้ด้วย ดูรายการรหัสสถานะทั้งหมดได้ที่รหัสสถานะและการใช้งานใน gRPC

Swift

ระบบจะเรียก NSError กลับมาใน tripModel(_:didFailUpdateTripWithError:)

// 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;
    ...
  }
}

ตีความรหัสสถานะ

รหัสสถานะครอบคลุมข้อผิดพลาด 2 ประเภท ได้แก่ ข้อผิดพลาดเกี่ยวกับเซิร์ฟเวอร์และเครือข่าย รวมถึงข้อผิดพลาดฝั่งไคลเอ็นต์

ข้อผิดพลาดเกี่ยวกับเซิร์ฟเวอร์และเครือข่าย

รหัสสถานะต่อไปนี้แสดงข้อผิดพลาดเกี่ยวกับเครือข่ายหรือเซิร์ฟเวอร์ และคุณไม่จำเป็นต้องดำเนินการใดๆ เพื่อแก้ไข Consumer SDK จะกู้คืนจากข้อผิดพลาดเหล่านี้โดยอัตโนมัติ

รหัสสถานะคำอธิบาย
ยกเลิก เซิร์ฟเวอร์หยุดส่งการตอบกลับ ซึ่งมักเกิดจากปัญหาเซิร์ฟเวอร์
ยกเลิกแล้ว เซิร์ฟเวอร์สิ้นสุดการตอบกลับขาออก โดยปกติ กรณีนี้จะเกิดขึ้นเมื่อ
ส่งแอปไปยังเบื้องหลัง หรือเมื่อมีการเปลี่ยนสถานะในแอป
Consumer
ขัดข้อง
DEADLINE_EXCEEDED เซิร์ฟเวอร์ใช้เวลาตอบสนองนานเกินไป
UNAVAILABLE เซิร์ฟเวอร์ไม่พร้อมใช้งาน ซึ่งมักเกิดจากปัญหาเกี่ยวกับเครือข่าย

ข้อผิดพลาดของไคลเอ็นต์

รหัสสถานะต่อไปนี้เป็นรหัสข้อผิดพลาดของไคลเอ็นต์ และคุณต้องดำเนินการเพื่อแก้ไข Consumer SDK จะพยายามรีเฟรชการเดินทางต่อไปจนกว่าคุณจะสิ้นสุดการแชร์การเดินทาง แต่การเดินทางจะไม่กู้คืนจนกว่าคุณจะดำเนินการ

รหัสสถานะคำอธิบาย
INVALID_ARGUMENT แอป Consumer ระบุชื่อการเดินทางไม่ถูกต้อง ชื่อการเดินทางต้องเป็นไปตามรูปแบบ providers/{provider_id}/trips/{trip_id}
NOT_FOUND ไม่เคยสร้างการเดินทางนี้
PERMISSION_DENIED แอปสำหรับผู้บริโภคมีสิทธิ์ไม่เพียงพอ ข้อผิดพลาดนี้เกิดขึ้นเมื่อ
  • แอปสำหรับผู้บริโภคไม่มีสิทธิ์
  • ไม่ได้เปิดใช้ Consumer SDK สำหรับโปรเจ็กต์ใน Google Cloud Console
  • ไม่มีโทเค็น JWT หรือไม่ถูกต้อง
  • โทเค็น JWT ลงชื่อด้วยรหัสการเดินทางที่ไม่ตรงกับการเดินทางที่ขอ
RESOURCE_EXHAUSTED โควต้าทรัพยากรอยู่ที่ 0 หรือมีอัตราการไหลเวียนของการรับส่งข้อมูลเกินขีดจำกัดความเร็ว
ไม่มีการตรวจสอบสิทธิ์ คำขอตรวจสอบสิทธิ์ไม่สำเร็จเนื่องจากโทเค็น JWT ไม่ถูกต้อง ข้อผิดพลาดนี้เกิดขึ้นเมื่อมีการลงนามโทเค็น JWT โดยไม่มีรหัสการเดินทาง หรือเมื่อโทเค็น JWT หมดอายุ