The Movement SDK also offers features which you can use to augment your in-app experience, bringing location to the forefront to offer more compelling interactions to your users.

## Journeys

Journeys allows partners to build powerful, location-aware experiences. You can use Journeys to power in-store & curbside pickup, delivery tracking, location-based marketing, and more.

When a user is ready to embark on a journey (i.e. they tap on "I'm on my way"), Journeys will start monitoring for their arrival, provide live ETAs throughout the way, and automatically detect when a user has arrived at their destination.

### Requirements

- **Movement SDK v4.0.0+**  
- **Background Location & Precise Location Enabled**

### Required AppDelegate Method

Include the following delegate methods to track journey state/eta/etc. Foursquare will return one of the following journey states:

- **In Progress**: The journey has started successfully and will now send regular updates.
- **Approaching**: The user is now approaching the destination.
- **Arrived**: The user has arrived at the destination.
- **Completed**: The journey has been completed. This is a user-generated action
- **Canceled**: The journey has been canceled. This is a user-generated action.

```swift
protocol MovementSdkManagerDelegate {
…
    fun movementSdkManager(_ movementSdkManager: MovementSdkManager, handleJourneyUpdate journey: Journey)
…
}
```

### Available Methods

Include the following methods to ensure the correct Journeys behaviors are tracked.

- Start Journey
- Get Current Journey
- Cancel Journey
- Checkin Journey
- Complete Journey

```swift
// method
MovementSdkManager.sharedManager.start(destinationId: String, destinationType: JourneyDestinationType)
// usage
MovementSdkManager.sharedManager.startJourney(destinationId: venueId, destinationType: .venue, metadata: nil) { error in
    guard error == nil else {
        // handle error
        return
    }
}
```

```swift
// method
func MovementSdkManager.currentJourney() -> Journey?
// usage
if let journey = MovementSdkManager.sharedManager.currentJourney() {
    // do something with journey
}
```

```swift
// method
func MovementSdkManager.cancelJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.cancelJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}
```

```swift
// method
func MovementSdkManager.checkinJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.checkinJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}
```

```swift
// method
func MovementSdkManager.completeJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.completeJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}
```

### Error Handling

Using the delegate method:

```swift
protocol MovementSdkManagerDelegate {
…
    fun movementSdkManager(_ movementManager: MovementSdkManager, handleError error: Error)
…
}

extension FoursquareMovementService: MovementSdkManagerDelegate {
…
    func movementSdkManager(_ movementManager: MovementSdkManager, handleError error: Error){
        // handle error
    }
}
```

## Get Current Location

Current Location is the most comprehensive of the in-app features, allowing you to get precise place information for any user who has given your app permission to use location.

Using **Current Location** you can:

### Get Current Place

```swift
MovementSdkManager.shared().getCurrentLocation { (currentLocation, error) in
   currentLocation.currentPlace
}
```

### Get Matched Geofences

```swift
MovementSdkManager.shared().getCurrentLocation { (currentLocation, error) in
   currentLocation.matchedGeofences
}
```

### Get Last Known User State

You can access User State in one of two ways:

- Subscribing to changes via the MovementSdkManager delegate

```swift
func movementSdkManager(_ movementSdkManager: MovementSdkManager, handleUserState updatedUserState: UserState, changedComponents: UserStateComponent) {
    switch changedComponents {
    case .city:
      print("Welcome to \(updatedUserState.city)")
    }
}
```

- Accessing via the **MovementSdkManager** Instance

```swift
MovementSdkManager.shared().lastKnownUserState()
```

## Receive Geofence Events

The Movement SDK allows geofencing around a configurable set of venues or points. Geofences can be set for the venues, categories, or chains of your choosing.

### Event Types

Geofences have five potential event types that are delivered directly to the client:

| Event Type | Description |
| --- | --- |
| entrance | Triggered on the first GPS signal that is received inside of the geofence. |
| dwell | Triggered after the user has "dwelled" within the geofence for a configurable length of time. Default is 1 minute. |
| venue confirmed | Triggered when the device has dwelled inside a geofence radius and confirmed a stop at the venue within the radius. |
| exit | Triggered on the first GPS signal that is received outside of the geofence. |
| presence | Triggered when the device is in a geofence radius during a get location request. |

### Receiving Events

```swift
// In your implementation of the Movement SDK delegate, add:
func movementSdkManager(_ movementSdkManager: MovementSdkManager, handle geofenceEvents: [GeofenceEvent]) {
    // Code to handle geofenceEvents...
}
```

### Geofence Event Structure

a geofence event will contain fields such as:

| Field | Description |
| --- | --- |
| eventType | `entrance`, `dwell`, `venueConfirmed`, `exit`, or `presence`. |
| venue | Same as regular SDK venue object. |
| categoryIDs | Array of categoryIDs used by triggered geofence. |
| chainIDs | Array of chainIDs used by triggered geofence. |
| partnerVenueID | String of harmonized venueId. |
| location | Object containing location information about the geofence event. |
| timestamp | Unix/epoch timestamp in milliseconds of when the event occurred. |

### Geofence Management

Geofences can be managed through the Geofence builder in your Developer Console or via our Geofence API.
