단일 목적지 경로 만들기 및 표시

이 튜토리얼에서는 단일 승차 및 하차 경로가 포함된 경로를 만든 후 이 여정을 소비자와 공유하는 과정을 안내합니다.

기본 요건

이 튜토리얼을 완료하려면 다음을 완료해야 합니다.

  1. Fleet Engine 설정 자세한 내용은 Fleet Engine: 초기 설정을 참고하세요.

  2. 앱을 Driver SDK와 통합합니다. 자세한 내용은 Android용 드라이버 SDK 초기화와 iOS용 드라이버 SDK 통합 가이드를 참고하세요.

  3. 소비자 대면 앱을 소비자 SDK와 통합합니다. 자세한 내용은 Android용 Consumer SDK 시작하기와 iOS용 Consumer SDK 시작하기를 참조하세요.

  4. 승인 토큰을 설정합니다. 승인 토큰에 대한 자세한 내용은 Fleet Engine 시작하기 가이드의 승인을 위한 JSON 웹 토큰 만들기와 Fleet Engine 소비자 SDK 문서의 인증 및 승인을 참조하세요.

1단계: Fleet Engine에서 차량 만들기

차량은 Fleet의 차량을 나타내는 객체입니다. 소비자 앱에서 이벤트를 추적하려면 Fleet Engine에서 객체를 만들어야 합니다.

다음 두 가지 접근 방식 중 하나를 사용하여 차량을 만들 수 있습니다.

gRPC
CreateVehicleRequest 요청 메시지와 함께 CreateVehicle() 메서드를 호출합니다. CreateVehicle()을(를) 호출하려면 Fleet Engine 수퍼유저 권한이 있어야 합니다.
REST
https://fleetengine.googleapis.com/v1/providers.vehicles.create에 전화 걸기

주의사항

차량을 만들 때는 다음 주의사항이 적용됩니다.

  • 초기 차량 상태를 OFFLINE로 설정해야 합니다. 이렇게 하면 Fleet Engine이 이동에 맞는 차량을 찾을 수 있습니다.

  • 차량의 provider_id는 Fleet Engine을 호출하는 데 사용되는 서비스 계정이 포함된 Google Cloud 프로젝트의 프로젝트 ID와 동일해야 합니다. 여러 서비스 계정이 동일한 차량 공유 제공업체의 Fleet Engine에 액세스할 수 있지만 현재 Fleet Engine은 동일한 차량에 액세스하는 여러 Google Cloud 프로젝트의 서비스 계정을 지원하지 않습니다.

  • CreateVehicle()에서 반환된 응답에는 Vehicle 인스턴스가 포함됩니다. UpdateVehicle()를 사용하여 업데이트되지 않은 인스턴스는 7일 후에 삭제됩니다. 차량이 이미 존재하지 않는지 확인하기 위해 CreateVehicle()를 호출하기 전에 GetVehicle()를 호출해야 합니다. GetVehicle()NOT_FOUND 오류를 반환하면 CreateVehicle() 호출을 진행해야 합니다. 자세한 내용은 차량 및 차량 수명 주기를 참고하세요.

다음 제공업체 코드 샘플은 Fleet Engine에서 차량을 만드는 방법을 보여줍니다.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";

VehicleServiceBlockingStub vehicleService = VehicleService.newBlockingStub(channel);

String parent = "providers/" + PROJECT_ID;

Vehicle vehicle = Vehicle.newBuilder()
    .setVehicleState(VehicleState.OFFLINE)  // Initial state
    .addSupportedTripTypes(TripType.EXCLUSIVE)
    .setMaximumCapacity(4)
    .setVehicleType(VehicleType.newBuilder().setCategory(VehicleType.Category.AUTO))
    .build();

CreateVehicleRequest createVehicleRequest = CreateVehicleRequest.newBuilder()
    .setParent(parent)
    .setVehicleId("8241890")  // Vehicle ID assigned by solution provider.
    .setVehicle(vehicle)      // Initial state.
    .build();

// The Vehicle is created in the OFFLINE state, and no initial position is
// provided.  When the driver app calls the rideshare provider, the state can be
// set to ONLINE, and the driver app updates the vehicle location.
try {
  Vehicle createdVehicle = vehicleService.createVehicle(createVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

2단계: 위치 추적 사용 설정

위치 추적은 이동 중에 차량의 위치를 추적하는 것을 의미하며 여기서 운전자 앱이 차량의 현재 위치가 포함된 Fleet Engine으로 원격 분석을 전송합니다. 위치 정보에서 지속적으로 업데이트되는 이 스트림은 이동 경로를 따라 차량의 진행 상황을 전달하는 데 사용됩니다. 위치 추적을 사용 설정하면 드라이버 앱이 기본 빈도인 5초마다 한 번씩 이 원격 분석 데이터를 전송하기 시작합니다.

Android 및 iOS에서 위치 추적을 사용 설정하는 방법은 다음과 같습니다.

다음 코드 예에서는 위치 추적을 사용 설정하는 방법을 보여줍니다.

Java

RidesharingVehicleReporter vehicleReporter = ...;

vehicleReporter.enableLocationTracking();

Kotlin

val vehicleReporter = ...

vehicleReporter.enableLocationTracking()

Swift

vehicleReporter.locationTrackingEnabled = true

Objective-C

_vehicleReporter.locationTrackingEnabled = YES;

3단계: 차량 상태를 온라인으로 설정

차량의 상태를 온라인으로 설정하여 (즉, 차량을 사용할 수 있도록 하기 위해) 차량을 가동하지만 위치 추적을 사용 설정하기 전에는 차량을 사용할 수 없습니다.

Android 및 iOS의 경우 다음과 같이 차량 상태를 온라인으로 설정합니다.

다음 코드 예는 차량 상태를 ONLINE로 설정하는 방법을 보여줍니다.

Java

vehicleReporter.setVehicleState(VehicleState.ONLINE);

Kotlin

vehicleReporter.setVehicleState(VehicleState.ONLINE)

Swift

vehicleReporter.update(.online)

Objective-C

[_vehicleReporter updateVehicleState:GMTDVehicleStateOnline];

4단계: Fleet Engine에서 이동 만들기

프로그래매틱 방식으로 Trip는 여정을 나타내는 객체이며, 차량과 일치시킨 다음 추적할 수 있도록 각 이동 요청에 대해 하나씩 만들어야 합니다.

필수 속성

이동을 만들려면 다음 필드가 필요합니다.

parent
공급업체 ID가 포함된 문자열입니다. Fleet Engine을 호출하는 데 사용되는 서비스 계정이 포함된 Google Cloud 프로젝트의 프로젝트 ID와 동일해야 합니다.
trip_id
이 여정을 고유하게 식별하는, 만드는 문자열입니다.
trip_type
TripType 열거형 값 중 하나 (SHARED 또는 EXCLUSIVE)
pickup_point
여행의 출발지입니다.

이동을 만들 때 number_of_passengers, dropoff_point, vehicle_id를 제공할 수 있지만 이러한 입력란은 필수가 아닙니다. vehicle_id를 제공하면 경로에 나머지 경유지 목록이 포함되며, 이 목록을 사용하여 운전자 앱에서 목적지를 설정할 수 있습니다.

다음 예는 그랜드 인도네시아 이스트 몰에 대한 여행을 만드는 방법을 보여줍니다. 이 여정에는 승객 2명이 관여하며 이 여행은 독점적이며 상태는 신규입니다. 이동의 provider_id는 프로젝트 ID와 같아야 합니다. 이 예에서는 차량 공유 제공업체가 프로젝트 ID가 my-rideshare-co-gcp-project인 Google Cloud 프로젝트를 만들었습니다. 이 프로젝트에는 Fleet Engine을 호출하기 위한 서비스 계정이 포함되어야 합니다.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// Trip initial settings.
String parent = "providers/" + PROJECT_ID;

Trip trip = Trip.newBuilder()
    .setTripType(TripType.EXCLUSIVE) // Use TripType.SHARED for carpooling.
    .setPickupPoint(                 // Grand Indonesia East Mall.
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.195139).setLongitude(106.820826)))
    .setNumberOfPassengers(2)
    // Provide the drop-off point if available.
    .setDropoffPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder()
                .setLatitude(-6.1275).setLongitude(106.6537)))
    .build();

// Create trip request
CreateTripRequest createTripRequest = CreateTripRequest.newBuilder()
    .setParent(parent)
    .setTripId("trip-8241890")  // Trip ID assigned by the provider.
    .setTrip(trip)              // The initial state is NEW.
    .build();

// Error handling.
try {
  Trip createdTrip = tripService.createTrip(createTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

5단계: 드라이버 앱에서 목적지 설정

소비자를 운전자와 페어링한 후에는 운전자 앱에서 경로의 목적지를 구성해야 합니다. 차량의 목적지는 GetTrip(), UpdateTrip(), GetVehicle()에서 반환하는 경유지 컬렉션에서 가져올 수 있습니다.

  • Android용 Navigation SDK 메서드 setDestination()를 호출하거나 iOS용 Navigation SDK 메서드 setDestinations()를 호출하여 대상을 설정합니다.

소비자 앱에서 경로를 올바르게 렌더링하려면 setDestination()에 제공된 지리 좌표(LatLng)가 경로의 경유지에 있는 지리 좌표와 일치해야 합니다. 자세한 내용은 단일 대상으로 라우팅여러 대상으로 라우팅 가이드를 참조하세요.

다음 코드 샘플은 드라이버 앱에서 대상을 설정하는 방법을 보여줍니다.

Java

private void navigateToPlace(String placeId, RoutingOptions travelMode) {
  Waypoint destination;
  try {
    destination = Waypoint.fromPlaceId(placeId, null);
  } catch (Waypoint.UnsupportedPlaceIdException e) {
    displayMessage("Error starting navigation: Place ID is not supported.");
    return;
  }

  // Create a future to await the result of the asynchronous navigator task.
  ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
      mNavigator.setDestination(destination, travelMode);

  // Define the action to perform when the SDK has determined the route.
  pendingRoute.setOnResultListener(
      new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
        @Override
        public void onResult(Navigator.RouteStatus code) {
          switch (code) {
            case OK:
              // Hide the toolbar to maximize the navigation UI.
              if (getActionBar() != null) {
                getActionBar().hide();
              }

              // Enable voice audio guidance (through the device speaker).
              mNavigator.setAudioGuidance(
                  Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);

              // Simulate vehicle progress along the route for demo/debug builds.
              if (BuildConfig.DEBUG) {
                mNavigator.getSimulator().simulateLocationsAlongExistingRoute(
                    new SimulationOptions().speedMultiplier(5));
              }

              // Start turn-by-turn guidance along the current route.
              mNavigator.startGuidance();
              break;
            // Handle error conditions returned by the navigator.
            case NO_ROUTE_FOUND:
              displayMessage("Error starting navigation: No route found.");
              break;
            case NETWORK_ERROR:
              displayMessage("Error starting navigation: Network error.");
              break;
            case ROUTE_CANCELED:
              displayMessage("Error starting navigation: Route canceled.");
              break;
            default:
              displayMessage("Error starting navigation: "
                  + String.valueOf(code));
          }
        }
      });
}

Kotlin

private fun navigateToPlace(placeId: String, travelMode: RoutingOptions) {
  val destination =
    try {
      Waypoint.fromPlaceId(placeId, null)
    } catch (e: Waypoint.UnsupportedPlaceIdException) {
      displayMessage("Error starting navigation: Place ID is not supported.")
      return@navigateToPlace
    }

  // Create a future to await the result of the asynchronous navigator task.
  val pendingRoute = mNavigator.setDestination(destination, travelMode)

  // Define the action to perform when the SDK has determined the route.
  pendingRoute.setOnResultListener(
    object : ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
      override fun onResult(code: Navigator.RouteStatus) {
        when (code) {
          Navigator.RouteStatus.OK -> {
            // Hide the toolbar to maximize the navigation UI.
            getActionBar()?.hide()

            // Enable voice audio guidance (through the device speaker).
            mNavigator.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE)

            // Simulate vehicle progress along the route for demo/debug builds.
            if (BuildConfig.DEBUG) {
              mNavigator
                .getSimulator()
                .simulateLocationsAlongExistingRoute(SimulationOptions().speedMultiplier(5))
            }

            // Start turn-by-turn guidance along the current route.
            mNavigator.startGuidance()
          }
          Navigator.RouteStatus.NO_ROUTE_FOUND -> {
            displayMessage("Error starting navigation: No route found.")
          }
          Navigator.RouteStatus.NETWORK_ERROR -> {
            displayMessage("Error starting navigation: Network error.")
          }
          Navigator.RouteStatus.ROUTE_CANCELED -> {
            displayMessage("Error starting navigation: Route canceled.")
          }
          else -> {
            displayMessage("Error starting navigation: ${code.name}")
          }
        }
      }
    }
  )
}

Swift

private func startNavigation() {
  let destinations = [
    GMSNavigationWaypoint(
      placeID: "ChIJnUYTpNASkFQR_gSty5kyoUk", title: "PCC Natural Market"),
    GMSNavigationWaypoint(
      placeID: "ChIJJ326ROcSkFQRBfUzOL2DSbo", title: "Marina Park"),
  ]

  mapView.navigator?.setDestinations(destinations, callback: { routeStatus in
    guard routeStatus == .OK else {
      // Error starting navigation.
      return
    }
    mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    mapView.navigator?.isGuidanceActive = true
    mapView.navigator?.sendsBackgroundNotifications = true
    mapView.cameraMode = .following
  })
}

Objective-C

- (void)startNavigation {
  NSArray<GMSNavigationWaypoint *> *destinations =
  @[[[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJnUYTpNASkFQR_gSty5kyoUk"
                                             title:@"PCC Natural Market"],
    [[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJJ326ROcSkFQRBfUzOL2DSbo"
                                             title:@"Marina Park"]];

  [_mapView.navigator setDestinations:destinations
                             callback:^(GMSRouteStatus routeStatus) {
                               if (routeStatus != GMSRouteStatusOK) {
                                 // Error starting navigation.
                                 return;
                               }
                               [_mapView.locationSimulator simulateLocationsAlongExistingRoute];
                               _mapView.navigator.guidanceActive = YES;
                               _mapView.navigator.sendsBackgroundNotifications = YES;
                               _mapView.cameraMode = GMSNavigationCameraModeFollowing;
                             }];
}

6단계: 소비자 앱에서 경로 업데이트 수신 대기

  • Android의 경우 TripModelManager에서 TripModel 객체를 가져오고 TripModelCallback 리스너를 등록하여 경로의 데이터 업데이트를 수신 대기할 수 있습니다.

  • iOS의 경우 GMTCTripService에서 GMTCTripModel 객체를 가져오고 GMTCTripModelSubscriber 구독자를 등록하여 경로의 데이터 업데이트를 수신 대기할 수 있습니다.

TripModelCallback 리스너와 GMTCTripModelSubscriber 구독자를 사용하면 앱이 자동 새로고침 간격에 따라 새로고침할 때마다 정기적인 이동 진행률 업데이트를 수신할 수 있습니다. 변경되는 값만 콜백을 트리거할 수 있습니다. 그러지 않으면 콜백이 무음으로 유지됩니다.

TripModelCallback.onTripUpdated()tripModel(_:didUpdate:updatedPropertyFields:) 메서드는 데이터 변경사항에 관계없이 항상 호출됩니다.

예시 1

다음 코드 샘플은 TripModelManager/GMTCTripService에서 TripModel를 가져와서 리스너를 설정하는 방법을 보여줍니다.

Java

// Start journey sharing after a trip has been created via Fleet Engine.
TripModelManager tripModelManager = consumerApi.getTripModelManager();

// Get a TripModel object.
TripModel tripModel = tripModelManager.getTripModel(tripName);

// Register a listener on the trip.
TripModelCallback tripCallback = new TripModelCallback() {
  ...
};
tripModel.registerTripCallback(tripCallback);

// Set the refresh interval.
TripModelOptions tripModelOptions = TripModelOptions.builder()
    .setRefreshInterval(5000) // interval in milliseconds, so 5 seconds
    .build();
tripModel.setTripModelOptions(tripModelOptions);

// The trip stops auto-refreshing when all listeners are unregistered.
tripModel.unregisterTripCallback(tripCallback);

Kotlin

// Start journey sharing after a trip has been created via Fleet Engine.
val tripModelManager = consumerApi.getTripModelManager()

// Get a TripModel object.
val tripModel = tripModelManager.getTripModel(tripName)

// Register a listener on the trip.
val tripCallback = TripModelCallback() {
  ...
}

tripModel.registerTripCallback(tripCallback)

// Set the refresh interval.
val tripModelOptions =
  TripModelOptions.builder()
    .setRefreshInterval(5000) // interval in milliseconds, so 5 seconds
    .build()

tripModel.setTripModelOptions(tripModelOptions)

// The trip stops auto-refreshing when all listeners are unregistered.
tripModel.unregisterTripCallback(tripCallback)

Swift

let tripService = GMTCServices.shared().tripService

// Create a tripModel instance for listening for updates from the trip
// specified by the trip name.
let tripModel = tripService.tripModel(forTripName: tripName)

// Register for the trip update events.
tripModel.register(self)

// Set the refresh interval (in seconds).
tripModel.options.autoRefreshTimeInterval = 5

// Unregister for the trip update events.
tripModel.unregisterSubscriber(self)

Objective-C

GMTCTripService *tripService = [GMTCServices sharedServices].tripService;

// Create a tripModel instance for listening for updates from the trip
// specified by the trip name.
GMTCTripModel *tripModel = [tripService tripModelForTripName:tripName];

// Register for the trip update events.
[tripModel registerSubscriber:self];

// Set the refresh interval (in seconds).
tripModel.options.autoRefreshTimeInterval = 5;

// Unregister for the trip update events.
[tripModel unregisterSubscriber:self];

예 2

다음 코드 샘플은 TripModelCallback 리스너와 GMTCTripModelSubscriber 구독자를 설정하는 방법을 보여줍니다.

Java

// Implements a callback for the trip model so your app can listen for trip
// updates from Fleet Engine.
TripModelCallback subscriber =
  new TripModelCallback() {

    @Override
    public void onTripStatusUpdated(TripInfo tripInfo, @TripStatus int status) {
      // ...
    }

    @Override
    public void onTripActiveRouteUpdated(TripInfo tripInfo, List<LatLng> route) {
      // ...
    }

    @Override
    public void onTripVehicleLocationUpdated(
        TripInfo tripInfo, @Nullable VehicleLocation vehicleLocation) {
      // ...
    }

    @Override
    public void onTripPickupLocationUpdated(
        TripInfo tripInfo, @Nullable TerminalLocation pickup) {
      // ...
    }

    @Override
    public void onTripPickupTimeUpdated(TripInfo tripInfo, @Nullable Long timestampMillis) {
      // ...
    }

    @Override
    public void onTripDropoffLocationUpdated(
        TripInfo tripInfo, @Nullable TerminalLocation dropoff) {
      // ...
    }

    @Override
    public void onTripDropoffTimeUpdated(TripInfo tripInfo, @Nullable Long timestampMillis) {
      // ...
    }

    @Override
    public void onTripETAToNextWaypointUpdated(
        TripInfo tripInfo, @Nullable Long timestampMillis) {
      // ...
    }

    @Override
    public void onTripActiveRouteRemainingDistanceUpdated(
        TripInfo tripInfo, @Nullable Integer distanceMeters) {
      // ...
    }

    @Override
    public void onTripUpdateError(TripInfo tripInfo, TripUpdateError error) {
      // ...
    }

    @Override
    public void onTripUpdated(TripInfo tripInfo) {
      // ...
    }

    @Override
    public void onTripRemainingWaypointsUpdated(
        TripInfo tripInfo, List<TripWaypoint> waypointList) {
      // ...
    }

    @Override
    public void onTripIntermediateDestinationsUpdated(
        TripInfo tripInfo, List<TerminalLocation> intermediateDestinations) {
      // ...
    }

    @Override
    public void onTripRemainingRouteDistanceUpdated(
        TripInfo tripInfo, @Nullable Integer distanceMeters) {
      // ...
    }

    @Override
    public void onTripRemainingRouteUpdated(TripInfo tripInfo, List<LatLng> route) {
      // ...
    }
  };

Kotlin

// Implements a callback for the trip model so your app can listen for trip
// updates from Fleet Engine.
val subscriber =
  object : TripModelCallback() {
    override fun onTripStatusUpdated(tripInfo: TripInfo, status: @TripStatus Int) {
      // ...
    }

    override fun onTripActiveRouteUpdated(tripInfo: TripInfo, route: List<LatLng>) {
      // ...
    }

    override fun onTripVehicleLocationUpdated(
      tripInfo: TripInfo,
      vehicleLocation: VehicleLocation?
    ) {
      // ...
    }

    override fun onTripPickupLocationUpdated(tripInfo: TripInfo, pickup: TerminalLocation?) {
      // ...
    }

    override fun onTripPickupTimeUpdated(tripInfo: TripInfo, timestampMillis: Long?) {
      // ...
    }

    override fun onTripDropoffLocationUpdated(tripInfo: TripInfo, dropoff: TerminalLocation?) {
      // ...
    }

    override fun onTripDropoffTimeUpdated(tripInfo: TripInfo, timestampMillis: Long?) {
      // ...
    }

    override fun onTripETAToNextWaypointUpdated(tripInfo: TripInfo, timestampMillis: Long?) {
      // ...
    }

    override fun onTripActiveRouteRemainingDistanceUpdated(
      tripInfo: TripInfo,
      distanceMeters: Int?
    ) {
      // ...
    }

    override fun onTripUpdateError(tripInfo: TripInfo, error: TripUpdateError) {
      // ...
    }

    override fun onTripUpdated(tripInfo: TripInfo) {
      // ...
    }

    override fun onTripRemainingWaypointsUpdated(
      tripInfo: TripInfo,
      waypointList: List<TripWaypoint>
    ) {
      // ...
    }

    override fun onTripIntermediateDestinationsUpdated(
      tripInfo: TripInfo,
      intermediateDestinations: List<TerminalLocation>
    ) {
      // ...
    }

    override fun onTripRemainingRouteDistanceUpdated(tripInfo: TripInfo, distanceMeters: Int?) {
      // ...
    }

    override fun onTripRemainingRouteUpdated(tripInfo: TripInfo, route: List<LatLng>) {
      // ...
    }
  }

Swift

class TripModelSubscriber: NSObject, GMTCTripModelSubscriber {

  func tripModel(_: GMTCTripModel, didUpdate trip: GMTSTrip?, updatedPropertyFields: GMTSTripPropertyFields) {
    // Update the UI with the new `trip` data.
    updateUI(with: trip)
    ...
  }

  func tripModel(_: GMTCTripModel, didUpdate tripStatus: GMTSTripStatus) {
    // Handle trip status did change.
  }

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

  ...
}

Objective-C

@interface TripModelSubscriber : NSObject <GMTCTripModelSubscriber>
@end

@implementation TripModelSubscriber

- (void)tripModel:(GMTCTripModel *)tripModel
            didUpdateTrip:(nullable GMTSTrip *)trip
    updatedPropertyFields:(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
    didUpdateActiveRoute:(nullable NSArray<GMTSLatLng *> *)activeRoute {
  // Handle trip 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.
}
…
@end

언제든지 다음과 같이 이동 정보에 액세스할 수 있습니다.

  • Android용 Consumer SDK 메서드 TripModel.getTripInfo()를 호출합니다. 이 메서드를 호출해도 데이터를 새로고침 빈도로 계속 새로고침할 수는 있지만 강제로 데이터를 새로고침하지는 않습니다.

  • iOS용 Consumer SDK 속성 GMTCTripModel.currentTrip을 가져옵니다.

7단계: 차량 ID로 이동 업데이트

Fleet Engine이 경로를 따라 차량을 추적할 수 있도록 차량 ID로 이동을 구성해야 합니다.

  • UpdateTripRequestUpdateTrip 엔드포인트를 호출하여 차량 ID로 이동을 업데이트할 수 있습니다. update_mask 필드를 사용하여 차량 ID를 업데이트한다고 지정합니다.

Notes

  • 경로를 만들 때 목적지를 지정하지 않으면 언제든지 여기에서 지정할 수 있습니다.

  • 진행 중인 이동에서 차량을 변경해야 하는 경우 이동 상태를 다시 새 상태로 설정하고 위에서 한 것처럼 이동을 새 차량 ID로 업데이트해야 합니다.

다음 코드 샘플은 차량 ID로 이동을 업데이트하는 방법을 보여줍니다.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "trip-8241890";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// The trip settings to update.
Trip trip = Trip.newBuilder()
    .setVehicleId("8241890")
    .build();

// The trip update request.
UpdateTripRequest updateTripRequest =
    UpdateTripRequest.newBuilder()      // No need for the header.
        .setName(tripName)
        .setTrip(trip)
        .setUpdateMask(FieldMask.newBuilder().addPaths("vehicle_id"))
        .build();

// Error handling.
// If the Fleet Engine has both a trip and vehicle with IDs, and if the
// credentials validate, then the service updates the trip.
try {
  Trip updatedTrip = tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:                    // Neither the trip nor vehicle exist.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

8단계: 소비자 앱에 여정 표시

ConsumerController 객체를 사용하여 Rides and Deliveries 사용자 인터페이스 요소 API에 액세스합니다.

자세한 내용은 사용자 인터페이스 요소 API 사용을 참고하세요.

다음 코드 예는 여정 공유 사용자 인터페이스를 시작하는 방법을 보여줍니다.

Java

JourneySharingSession session = JourneySharingSession.createInstance(tripModel);
consumerController.showSession(session);

Kotlin

val session = JourneySharingSession.createInstance(tripModel)
consumerController.showSession(session)

Swift

let journeySharingSession = GMTCJourneySharingSession(tripModel: tripModel)
mapView.show(journeySharingSession)

Objective-C

GMTCJourneySharingSession *journeySharingSession =
    [[GMTCJourneySharingSession alloc] initWithTripModel:tripModel];
[self.mapView showMapViewSession:journeySharingSession];

9단계: Fleet Engine에서 이동 상태 관리

TripStatus 열거형 값 중 하나를 사용하여 이동 상태를 지정합니다. 이동 상태가 변경되면 (예: ENROUTE_TO_PICKUP에서 ARRIVED_AT_PICKUP로 변경) Fleet Engine을 통해 이동 상태를 업데이트해야 합니다. 이동 상태는 항상 NEW 값으로 시작하고 COMPLETE 또는 CANCELED 값으로 끝납니다. 자세한 내용은 trip_status를 참고하세요.

다음 코드 샘플은 Fleet Engine에서 이동 상태를 업데이트하는 방법을 보여줍니다.

static final String PROJECT_ID = "my-rideshare-co-gcp-project";
static final String TRIP_ID = "trip-8241890";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// Trip settings to be updated.
Trip trip = Trip.newBuilder()
    .setTripStatus(TripStatus.ARRIVED_AT_PICKUP)
    .build();

// Trip update request
UpdateTripRequest updateTripRequest = UpdateTripRequest.newBuilder()
    .setName(tripName)
    .setTrip(trip)
    .setUpdateMask(FieldMask.newBuilder().addPaths("trip_status"))
    .build();

// Error handling.
try {
  Trip updatedTrip = tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:            // The trip doesn't exist.
      break;
    case FAILED_PRECONDITION:  // The given trip status is invalid.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}