> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/ios/ja/maps/llms.txt)

# User Location

The Mapbox Maps SDK for iOS enables your application to observe and respond to the user's location. It helps you request permission to access a user's location, use a location provider to get location information for the device, and display the user's location on the map visually.

## Privacy and permissions

Users must grant your application permission before it can access information about their location. During this permission prompt, a custom string may be presented explaining how location will be used. This is specified by adding the key `NSLocationWhenInUseUsageDescription` to the `Info.plist` file with a value that describes why the application is requesting these permissions.

Before iOS 14, the device could only send the user's exact location. With iOS 14, users can opt into only sharing reduced-accuracy locations. Since users may toggle full-accuracy location off when initial permission for their location is requested by the app or in the System settings, developers are strongly encouraged to support reduced-accuracy locations.

### Request temporary access to full-accuracy location

Certain application features may require full-accuracy locations. The SDK provides a wrapper of Apple's Core Location APIs that requests temporary access to full-accuracy locations when the user has opted out.

Make the following adjustments to your `Info.plist` file to enable these prompts and provide explanations to appear within them:

-   Provide users with a brief explanation of how the app will use their location data for temporary access:
    
    ```xml
    ...
    // highlight-start
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Your precise location is used to calculate turn-by-turn directions, show your location on the map, and help improve the map.</string>
    // highlight-end
    ...
    ```
    
-   Add `LocationAccuracyAuthorizationDescription` as an element of the `NSLocationTemporaryUsageDescriptionDictionary` dictionary to give users a brief explanation of why a feature in your app requires their exact location:
    
    ```xml
    ...
    // highlight-start
    <key>NSLocationTemporaryUsageDescriptionDictionary</key>
    <dict>
      <key>LocationAccuracyAuthorizationDescription</key>
      <string>Please enable precise location. Turn-by-turn directions only work when precise location data is available.</string>
    </dict>
    // highlight-end
    ...
    ```
    

If necessary for your application, you can request permanent location access by setting `NSLocationAlwaysAndWhenInUseUsageDescription` instead of `NSLocationWhenInUseUsageDescription`

### Handle changes in location authorization

After the current session elapses, your users will be prompted to give location permissions the next time they open your app. Your users must enable full-accuracy location during this prompt or in the app's system settings to avoid being asked repeatedly for location accuracy permissions.

### Customize accuracy authorization handling

If you want to customize how accuracy authorization updates are handled, use the location permission delegate. The [`AppleLocationProviderDelegate`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/applelocationproviderdelegate/) protocol has a set of delegate methods that will be called when the user makes changes to location permissions.

```swift
class ViewController: UIViewController {
    // This controller's initialization has been omitted in this code snippet
    var mapView: MapView!
    // A location provider that you use to customize location settings.
    let locationProvider = AppleLocationProvider()

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView = MapView()
        // Override the default location provider with the custom one.
        mapView.location.override(provider: locationProvider)
        locationProvider.delegate = self
    }

    // Method that will be called as a result of the delegate below
    func requestPermissionsButtonTapped() {
        locationProvider.requestTemporaryFullAccuracyAuthorization(withPurposeKey: "CustomKey")
    }
}

extension ViewController: AppleLocationProviderDelegate {
    func appleLocationProvider(
        _ locationProvider: MapboxMaps.AppleLocationProvider,
        didChangeAccuracyAuthorization accuracyAuthorization: CLAccuracyAuthorization
    ) {
        if accuracyAuthorization == .reducedAccuracy {
         // Perform an action in response to the new change in accuracy
        }
    }
}
```

The code above uses on a `withPurposeKey` parameter to handle a location permission change. This value must correspond to the key of a key/value pair that was specified in `Info.plist`.

```xml
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
    <key>CustomKey</key>
    <string>We temporarily require your precise location for an optimal experience.</string>
</dict>
```

You should also omit the `LocationAccuracyAuthorizationDescription` key from `NSLocationTemporaryUsageDescriptionDictionary` so that the SDK will not show the prompt automatically.

## Working with location

The [`LocationManager`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/locationmanager/) in the Maps SDK manages [location puck](#location-puck) and the [location-tracking](#location-tracking) viewport.

There are two types of location data used by the `LocationManager`:

-   Location data, represented by a sequence of [`Location`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/location/) updates.
-   Heading (compass) data, represented by a sequence of [`Heading`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/heading/) updates.

The location data is used for geographical positioning, while the heading data is optional and is used to display the user's device orientation on the map.

By default, the `LocationManager` creates the default instance of [`AppleLocationProvider`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/applelocationprovider/) to receive the location data. You can create your own instance and use it to change the default settings or use a completely custom provider.

```swift
// Override location provider to customize settings.
let locationProvider = AppleLocationProvider()
locationProvider.options.activityType = .automotiveNavigation
mapView.location.override(provider: locationProvider)
```

### Custom location providers

If you have a custom location source, you can supply your own data to the map.

To achieve that, implement and override the [`LocationProvider`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/locationprovider/) and [`HeadingProvider`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/headingprovider/) protocols:

```swift
// Set custom location and heading providers
let locationProvider: LocationProvider = //...
let headingProvider: HeadingProvider = //...
mapView.location.override(locationProvider: locationProvider, headingProvider: headingProvider)
```

In SwiftUI, use [`MapReader`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/mapreader/) and [Combine](https://developer.apple.com/documentation/combine) publishers to override the location providers.

```swift
/// SwiftUI
struct LocationOverrideExample: View {
    private class LocationProvider {
        @Published var location = Location(coordinate: .zero)
        @Published var heading = Heading(direction: 0, accuracy: 0)
    }
    @State private var provider = LocationProvider()

    var body: some View {
        MapReader { proxy in
            Map {
                Puck2D(bearing: .heading)
            }
            .onAppear {
                /// Override the location and Heading provider with Combine publishers.
                proxy.location?.override(
                    locationProvider: provider.$location.map { [$0] }.eraseToSignal(),
                    headingProvider: provider.$heading.eraseToSignal())
            }
        }
    }
}
```

The [`eraseToSignal`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/signal/erasetosignal()/) in the example above converts any [`Publisher`](https://developer.apple.com/documentation/combine/publisher) to the internal [`Signal`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/signal/), which is used internally by the Maps SDK.

> **Note (warning): Permissions**
> 
> When implementing a custom location providers, be sure you ask user permissions for location data.

## Location puck

Enabling user location puck in [`LocationOptions`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/locationoptions/) will render a puck on the map that shows the device's current location and handle requesting permissions and all the nuances that come with different permission levels.

Enable the default user location display using the following code:

**SwiftUI**

```swift

Map {
  // By default, the built-in 2D puck doesn't show the user's heading.
  Puck2D()
  
  // To display the heading, you must enable it explicitly as follows:
  Puck2D(bearing: .heading)
}
  
```

**UIKit**

```swift

// By default, the built-in 2D puck doesn't show the user's heading.
mapView.location.options.puckType = .puck2D()    

// To display the heading, you must enable it explicitly as follows:
let configuration = Puck2DConfiguration.makeDefault(showBearing: true)
mapView.location.options.puckType = .puck2D(configuration)
  
```

> **Related content (example): [Show the user's location on the map](https://docs.mapbox.com/ios/ja/maps/examples/tracking-mode/)**
> 
> Show the user's location on a map using the default location puck.

![A screenshot of an iOS application displaying the user's location on a map.](https://docs.mapbox.com/ios/ja/assets/ideal-img/beta-maps-examples-user-location-view.666ebe2.480.png)

### Set puck style options

There are several options to customize the appearance of the location puck using [`LocationOptions`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/locationoptions/). Using the [`PuckType` enum](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/pucktype/), you can set whether to use a [2D](https://docs.mapbox.com/ios/ja/maps/examples/custom-location-puck/) or [3D](https://docs.mapbox.com/ios/ja/maps/examples/custom-3D-puck/) puck.

### Set Puck Bearing Source

On iOS, the user location can track bearing using the device [`heading`](https://developer.apple.com/documentation/corelocation/clheading) or device [`course`](https://developer.apple.com/documentation/corelocation/cllocation/1423832-course). This option can be set in [`LocationOptions`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/locationoptions/).

## Location Tracking

To make the camera follow the location puck, you can use the Follow Puck Viewport.

-   In UIKit, you use [`ViewportManager`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/viewportmanager/) accessible as `MapView.viewport` property.
-   In SwiftUI, the [`Viewport`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/viewport/) configuration can be passed to the [`Map`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/map/) view.

### Viewport States

[`ViewportState`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/viewportstate/) produces camera updates based on implementation-specific rules (For example tracking a dynamic location data source or showing a static overview of a predefined region).

Two `ViewportState` implementations are provided by the SDK, both of which can be instantiated from `Viewport`:

-   `viewport.makeFollowPuckViewportState(options:) -> FollowPuckViewportState`: This state syncs the map camera with the location puck.
-   `viewport.makeOverviewViewportState(options:) -> OverviewViewportState`: This state makes the camera show a user-provided geometry.

Besides using these built-in implementations, you can also create your own and use them with `Viewport`.

### Viewport Transitions

[`ViewportTransition`](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxmaps/viewporttransition/) defines how to transition to a target `ViewportState`.

Two `ViewportTransition` implementations also provided by the SDK, both of which can be instantiated from `Viewport`:

-   `viewport.makeDefaultViewportTransition(options:) -> DefaultViewportTransition`: The default viewport transition uses sophisticated animations to move the camera to the target state.
-   `viewport.makeImmediateViewportTransition() -> ImmediateViewportTransition`: The immediate viewport transition moves the camera to the target state immediately without using animations.

Besides using these built-in implementations, you can also create your own and use them with `Viewport`.

### Example

**SwiftUI**

```swift

struct ViewportExample: View {
    // By default, camera settings come from style settings.
    @State var viewport = Viewport.styleDefault
    
    var body: some View {
        Map(viewport: $viewport)

        Button("Follow puck") {
            // An animated transition to the follow-puck viewport state.
            withViewportAnimation {
                viewport = .followPuck(zoom: 16.35, pitch: 45).padding(.top, 200)
            }
        }

        Button("Overview") {
            // An immediate transition to the overview state.
            viewport = .overview(geometry: routePoints).padding(.all, 100)
        }
    }
}
  
```

**UIKit**

```swift

import MapboxMaps
...
let followPuckViewportState = mapView.viewport.makeFollowPuckViewportState(
    options: FollowPuckViewportStateOptions(
        padding: UIEdgeInsets(top: 200, left: 0, bottom: 0, right: 0),
        bearing: .constant(0),
        animationDuration: 0.5))
let overviewViewportState = mapView.viewport.makeOverviewViewportState(
    options: OverviewViewportStateOptions(
        geometry: routePoints,
        padding: UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)))
let immediateTransition = mapView.viewport.makeImmediateViewportTransition()
// transition from idle (the default status) to the created followPuckViewportState with default transition
mapView.viewport.transition(to: followPuckViewportState) { success in
    // the transition has been completed with a flag indicating whether the transition succeeded
}
...
mapView.viewport.transition(to: overviewViewportState, transition: immediateTransition) { success in
    // the transition has been completed with a flag indicating whether the transition succeeded
}
  
```

> **Note (warning): Troubleshooting with the iOS simulator**
> 
> If you cannot see the location puck while testing in the iOS simulator, try the following:
> 
> -   Simulate a location in Xcode by going to **Debug > Simulate Location** and select a location. Then, return to the Simulator and the location puck should appear over the selected location.
> -   If you already declined location permissions for your application you can update permission in Settings. Go to **Settings > Privacy & Security > Location Services**. Then find your application and update the location access to "Always" or "While Using the App".