Skip to main content

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:
    Info.plist
    ...
     
    <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>
    ...
  • 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:
    Info.plist
    ...
     
    <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>
    ...

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 protocol has a set of delegate methods that will be called when the user makes changes to location permissions.

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.

<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 in the Maps SDK manages location puck and the location-tracking viewport.

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

  • Location data, represented by a sequence of Location updates.
  • Heading (compass) data, represented by a sequence of 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 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.

// 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 and HeadingProvider protocols:

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

In SwiftUI, use MapReader and Combine publishers to override the location providers.

/// 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 in the example above converts any Publisher to the internal Signal, which is used internally by the Maps SDK.

Permissions

When implementing a custom location providers, be sure you ask user permissions for location data.

Location puck

Enabling user location puck in 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:


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

EXAMPLE
Show the user's location on the map

Show the user's location on a map using the default location puck.

Set puck style options

There are several options to customize the appearance of the location puck using LocationOptions. Using the PuckType enum, you can set whether to use a 2D or 3D puck.

Set Puck Bearing Source

On iOS, the user location can track bearing using the device heading or device course. This option can be set in LocationOptions.

Location Tracking

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

  • In UIKit, you use ViewportManager accessible as MapView.viewport property.
  • In SwiftUI, the Viewport configuration can be passed to the Map view.

Viewport States

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


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

Was this page helpful?