متابعة رحلة على جهاز 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];
  ...
}

مثال على إيقاف الاستماع إلى آخر الأخبار

يوضّح المثال التالي كيفية إلغاء تسجيل tripModel callback.

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 Error. للحصول على تعريفات تفصيلية لرسائل الخطأ وجميع رموز الخطأ، يُرجى الرجوع إلى مستندات أخطاء Google Cloud.

في ما يلي بعض الأخطاء الشائعة التي يمكن أن تحدث أثناء تتبُّع الرحلات:

HTTP متوسط عائد النقرة الوصف
400 INVALID_ARGUMENT حدّد العميل اسم رحلة غير صالح. يجب أن يتّبع اسم الرحلة التنسيق providers/{provider_id}/trips/{trip_id}. يجب أن يكون provider_id هو رقم تعريف مشروع على السحابة الإلكترونية الذي يملكه مقدّم الخدمة.
401 UNAUTHENTICATED يظهر هذا الخطأ إذا لم تتوفر بيانات اعتماد مصادقة صالحة. على سبيل المثال، إذا تم توقيع رمز JWT المميّز بدون معرّف رحلة أو إذا انتهت صلاحية رمز JWT المميّز.
403 PERMISSION_DENIED يظهر لك هذا الخطأ إذا لم يكن لدى العميل إذن كافٍ (على سبيل المثال، إذا حاول مستخدم لديه دور المستهلك استدعاء updateTrip)، أو إذا كان رمز JWT غير صالح، أو إذا لم تكن واجهة برمجة التطبيقات مفعَّلة لمشروع العميل. قد يكون رمز JWT المميّز غير متوفّر أو تم توقيعه باستخدام معرّف رحلة لا يتطابق مع معرّف الرحلة المطلوب.
429 RESOURCE_EXHAUSTED الحصة المخصصة للموارد صفر أو يتجاوز معدّل عدد الزيارات الحدّ الأقصى.
503 UNAVAILABLE الخدمة غير متاحة. عادةً ما يكون الخادم معطّلاً.
504 DEADLINE_EXCEEDED تجاوز الموعد النهائي للطلب لا يحدث هذا الخطأ إلا إذا حدّد المتصل موعدًا نهائيًا أقصر من الموعد النهائي التلقائي للطريقة (أي أنّ الموعد النهائي المطلوب غير كافٍ ليتمكّن الخادم من معالجة الطلب) ولم يكتمل الطلب خلال الموعد النهائي.

التعامل مع أخطاء Consumer SDK

ترسل حزمة تطوير البرامج (SDK) للمستهلك أخطاء تحديث الرحلة إلى تطبيق المستهلك باستخدام آلية ردّ الاتصال. معلمة ردّ الاتصال هي نوع القيمة التي تم إرجاعها خاصة بالنظام الأساسي ( 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;
    ...
  }
}

تفسير رموز الحالة

تغطي رموز الحالة نوعَين من الأخطاء: الأخطاء المتعلقة بالخادم والشبكة، والأخطاء من جهة العميل.

أخطاء الخادم والشبكة

رموز الحالة التالية مخصّصة لأخطاء الشبكة أو الخادم، ولا يلزمك اتّخاذ أي إجراء لحلّها. وتتعافى حزمة تطوير البرامج (SDK) المخصّصة للمستهلك تلقائيًا من هذه الأخطاء.

رمز الحالةالوصف
تم إلغاؤه توقّف الخادم عن إرسال الردّ. ويحدث ذلك عادةً بسبب مشكلة في الخادم.
تم إلغاؤها أنهى الخادم الاستجابة الصادرة. يحدث ذلك عادةً عندما
يتم إرسال التطبيق إلى الخلفية، أو عند حدوث تغيير في الحالة في
تطبيق المستهلك.
تمت مقاطعتها
DEADLINE_EXCEEDED استغرق الخادم وقتًا طويلاً جدًا للاستجابة.
UNAVAILABLE كان الخادم غير متوفّر. ويحدث ذلك عادةً بسبب مشكلة في الشبكة.

أخطاء في تطبيق العميل

رموز الحالة التالية مخصّصة للأخطاء من جهة العميل، ويجب اتّخاذ إجراء لحلّها. تواصل حزمة تطوير البرامج (SDK) للمستهلك إعادة محاولة إعادة تحميل الرحلة إلى أن تنهي مشاركة الرحلة، ولكن لن يتم استردادها إلى أن تتّخذ إجراءً.

رمز الحالةالوصف
INVALID_ARGUMENT حدّد تطبيق المستهلك اسم رحلة غير صالح، ويجب أن يتّبع اسم الرحلة التنسيق providers/{provider_id}/trips/{trip_id}.
NOT_FOUND لم يتم إنشاء الرحلة أبدًا.
PERMISSION_DENIED لا يملك تطبيق المستهلك أذونات كافية. يحدث هذا الخطأ في الحالات التالية:
  • لا يملك تطبيق المستهلك الأذونات اللازمة
  • لم يتم تفعيل حزمة تطوير البرامج (SDK) الخاصة بالمستهلكين للمشروع في Google Cloud Console.
  • رمز JWT غير متوفّر أو غير صالح.
  • يتم توقيع رمز JWT المميّز باستخدام معرّف رحلة لا يتطابق مع الرحلة المطلوبة.
RESOURCE_EXHAUSTED حصة الموارد تساوي صفرًا، أو أنّ معدّل تدفّق الزيارات يتجاوز الحدّ الأقصى للسرعة.
UNAUTHENTICATED تعذَّر إكمال عملية المصادقة للطلب بسبب رمز JWT غير صالح. يحدث هذا الخطأ عندما يتم توقيع رمز JWT المميّز بدون رقم تعريف الرحلة، أو عندما تنتهي صلاحية رمز JWT المميّز.