Migrate to v11
The Mapbox Maps SDK v11 introduces improvements to how Mapbox works on iOS platforms, as well as changes to how developers use the SDK. This document summarizes the most important changes - such as new features, deprecated APIs, and breaking changes - and walks you through how to upgrade an application using v10 of the Mapbox Maps SDK to v11.
Version Compatibility
Version | Xcode Version | Swift Version | iOS Version |
---|---|---|---|
11.0.0 | 14.1+ | 5.7.1+ | 12+ |
1. Update Dependencies
Update your app's dependencies to use versions 11+ of the Mapbox Maps SDK for iOS. We distribute the SDK through Swift Package Manager (SPM), CocoaPods, and Direct Download. Full instructions are available in the Installation Guide.
2. Explore New Features
2.1 The Mapbox Standard and Mapbox Standard Satellite Styles
With the Mapbox Maps SDK v11 we are introducing Mapbox Standard and Mapbox Standard Satellite, our latest Mapbox styles. The new Mapbox Standard core style enables a highly performant and elegant 3D mapping experience with powerful dynamic lighting capabilities, landmark 3D buildings, and an expertly crafted symbolic aesthetic. With Mapbox Standard and Mapbox Standard Satellite Styles, we are also introducing a new paradigm for how to interact with map styles based around style importing (see below section for more details).
To set Mapbox Standard as the style for your map in v11 you can use the same StyleURI
convenience variables from v10 like below. Mapbox Standard is the new default style, so not setting a StyleManager/styleURI
means your map will use Mapbox Standard.
let mapView = MapView()
mapView.mapboxMap.styleURI = .standard
To set Mapbox Standard Satellite.
let mapView = MapView()
mapView.mapboxMap.styleURI = .standardSatellite
The Mapbox Standard and Mapbox Standard Satellite style features 4 light presets: day
, dusk
, dawn
, and night
. The style light preset can be changed from the default, day
, to another preset with a single line of code. Here you identify which imported style (basemap
) you want to change the lightPresent
configuration on, as well as the value (dusk
) you want to change it to.
mapView.mapboxMap.setStyleImportConfigProperty(for: "basemap", config: "lightPreset", value: "dusk")
Changing the light preset will alter the colors and shadows on your map to reflect the time of day. For more information, have a look at the New 3D Lighting API section.
Similarly, you can set other configuration properties on the Standard or Standard Satellite style such as showing POIs, place labels, or specific fonts:
mapView.mapboxMap.setStyleImportConfigProperty(for: "basemap", config: "showPointOfInterestLabels", value: false)
The Standard style offers 8 configuration properties for developers to change when they import it into their own style:
Property | Type | Description |
---|---|---|
showPlaceLabels | Bool | Shows and hides place label layers. |
showRoadLabels | Bool | Shows and hides all road labels, including road shields. |
showPointOfInterestLabels | Bool | Shows or hides all POI icons and text. |
showTransitLabels | Bool | Shows or hides all transit icons and text. |
show3dObjects | Bool | Shows or hides all 3d layers (3D buildings, landmarks, trees, etc.) including shadows, ambient occlusion, and flood lights. Important: configuration available starting from v11.5.2 SDK |
theme | String | Switches between 3 themes: default , faded and monochrome . Important: configuration available starting from v11.5.2 SDK |
lightPreset | String | Switches between 4 time-of-day states: dusk , dawn , day , and night . |
font | String | Defines font family for the style from predefined options. |
The Standard Satellite Style (mapbox://styles/mapbox/standard-satellite
) combines updated satellite imagery and vector layers to offer users improved clarity and detail. Similarly to Standard style, the Satellite Style receives all updates automatically and also supports light presets. Additionally, it introduces two new configurations showRoadsAndTransit
and showPedestrianRoads
. Users can now choose to hide roads, simplifying the map style for a better focus on specific areas or features.
The Standard Satellite style offers 8 configuration properties for developers to change when they import it into their own style:
Property | Type | Description |
---|---|---|
showRoadsAndTransit | Bool | Shows and hides all roads and transit networks. |
showPedestrianRoads | Bool | Shows and hides all pedestrian roads, paths, trails. |
showPlaceLabels | Bool | Shows and hides place label layers. |
showRoadLabels | Bool | Shows and hides all road labels, including road shields. |
showPointOfInterestLabels | Bool | Shows or hides all POI icons and text. |
showTransitLabels | Bool | Shows or hides all transit icons and text. |
lightPreset | String | Switches between 4 time-of-day states: dusk , dawn , day , and night . |
font | String | Defines font family for the style from predefined options. |
Important: Standard satellite style doesn't support theme and show3dObjects configuration. |
Mapbox Standard and Mapbox Standard Satellite are making adding your own data layers easier for you through the concept of slot
s. Slot
s are predefined locations in the style where your layer will be added to (such as on top of existing land layers, but below all labels). To do this, we've added a new slot
property to each Layer
. This property allows you to identify which slot
in the Mapbox Standard your new layer should be placed in. To add custom layers in the appropriate location in the Standard or Standard Satellite style layer stack, we added 3 carefully designed slots that you can leverage to place your layer. These slots won't change, so you can be sure that your own map won't break even as the basemap evolves automatically.
Slot | Description |
---|---|
bottom | Above polygons (land, landuse, water, etc.) |
middle | Above lines (roads, etc.) and behind 3D buildings |
top | Above POI labels and behind Place and Transit labels. Designed to be used with the symbol layers. |
not specified | Above all existing layers in the style |
var layer = LineLayer(id: "line-layer", source: "line-source")
layer.slot = "middle"
mapView.mapboxMap.addLayer(layer)
For the new Standard and Standard Satellite styles, you can only add layers to these three slots
(bottom
, middle
, top
) within the Standard and Standard Satellite style basemap.
When a layer type such as background
, fill
, line
, circle
, hillshade
or heatmap
is added to the top
slot in the Standard or Standard Satellite Style, it will be
positioned below all labels. This behavior is due to the design of the top
slot in the Standard Style, which is primarily intended for use with symbol
layers.
Like with the classic Mapbox styles, you can still use the layer position in StyleManager/addLayer(_:layerPosition:)
method when importing the Standard or Standard Satellite Style. Note that this method is only applicable to custom layers you have added yourself. If you add two layers to the same slot with a specified layer position the latter will define the order of the layers in that slot.
Standard is aware of the map lighting configuration using the measure-light
expression, which returns you an aggregated value of your light settings. This returns a value which ranges from 0 (darkest) to 1 (brightest). In darker lights, you make the individual layers light up by using the new *-emissive-stength
expressions, which allow you to add emissive light to different layer types and for example keep texts legible in all light settings. If your custom layers seem too dark, try adjusting the emissive strength of these layers. Read more about light-driven styling in Mapbox Standard in our documentation.
Customizing Standard
The underlying design paradigm to the Standard style is different from what you know from the classic core styles. Mapbox manages the basemap experience and surfaces key global styling configurations - in return, you get a cohesive visual experience and an evergreen map, always featuring the latest data, styling and rendering features compatible with your SDK. The configuration options make interactions with the basemap simpler than before. During the beta phase, we are piloting these configurations - we welcome feedback on the beta configurations. If you have feedback or questions about the Standard beta style reach out to: hey-map-design@mapbox.com.
You can customize the color set of your Standard or Standard Satellite experience by adjusting the 3D light settings. Individual basemap layers and/or color values can’t be adjusted, but all the flexibility offered by the style specification can be applied to custom layers while keeping interaction with the basemap easy through slot
s.
2.1.1 Style Imports
To work with styles like Mapbox Standard or Standard Satellite, we've introduced new Style APIs that allow you to import other styles into the main style you display to your users. These styles will be imported by reference, so updates to them will be reflected in your main style without additional work needed on your side. For example, imagine you have style A and style B. The Style API will allow you to import A into B. Upon importing, you can set configurations that apply to A and adjust them at runtime. The configuration properties for the imported style A will depend on what the creator of style A chooses to be configurable. For the Standard style, 8 configuration properties are available for setting lighting, fonts, and label display options (see The Mapbox Standard Style section above).
To import a style, you should add an "imports" section to your Style JSON. In the above example, you would add this "imports" section to your Style JSON for B to import style A and set various configurations such as Montserrat
for the font
and dusk
for the lightPreset
.
...
"imports": [
{
"id": "A",
"url": "STYLE_URL_FOR_A",
"config": {
"font": "Montserrat",
"lightPreset": "dusk",
"theme": "faded",
"show3dObjects: true,
"showPointOfInterestLabels": true,
"showTransitLabels": false,
"showPlaceLabels": true,
"showRoadLabels": false
}
}
],
...
For a full example of importing a style, have a look at our Standard Style Example. This example imports the Standard style into another style Real Estate New York. It then modifies the configurations for the imported Standard style at runtime using the following APIs we've introduced on the StyleManager
object:
StyleManager/styleImports
, which returns all the styles you have imported into your main styleStyleManager/removeStyleImport(for:)
, which removes the style import with the passed IdStyleManager/getStyleImportSchema(for:)
, which returns the full schema describing the style import with the passed IdStyleManager/getStyleImportConfigProperties(for:)
, which returns all the configuration properties of the style import with the passed IdStyleManager/getStyleImportConfigProperty(for:config:)
, which returns the specified configuration property of the style import with the passed IdStyleManager/setStyleImportConfigProperties(for:configs:)
, which sets all the configuration properties of the style import with the passed IdStyleManager/setStyleImportConfigProperty(for:config:value:)
, which sets the specified configuration property of the style import with the passed Id
Besides modifying the configuration properties of the imported styles, you can add your own layers to the imported style through the concept of slot
s. Slot
s are predefined locations in the imported style where your layer will be added to (such as on top of existing land layers, but below all labels). To do this, we've added a new slot
property to each Layer
. This property allows you to identify which slot
in the imported style your new layer should be placed in.
var layer = LineLayer(id: "line-layer", source: "line-source")
layer.slot = "middle"
mapView.mapboxMap.addLayer(layer)
2.2 SwiftUI support
We're excited to announce the launch of SwiftUI support in Mapbox Maps SDK. SwiftUI makes it even easier to integrate Mapbox Maps in your application.
v11:
import SwiftUI
import MapboxMaps
struct ContentView: View {
var body: some View {
Map()
.ignoresSafeArea()
}
}
For more details, read the SwiftUI User Guide.
2.3 Type-safe Events API
The events lifecycle reporting for MapboxMap
and Snapshotter
have been reworked. The new event system is serialization-free, which brings more type safety and eliminates possible deserialization errors that could take place in v10 Mapbox Maps SDK.
As a bonus, this new type system supports the Combine
framework out-of-the box.
v10:
// Observe every camera change
mapView.mapboxMap.onEvery(.cameraChange) { [weak self] _ in
guard let self = self else { return }
self.handleCameraChange(self.mapView.mapboxMap.cameraState)
}
// Observe only the next style loading event
mapView.mapboxMap.onNext(event: .styleLoaded) { [weak self] _ in
self?.setupStyle()
}
v11:
var cancelables = Set<AnyCancelable>()
// Observe every camera change
mapView.mapboxMap.onCameraChanged.observe { [weak self] event in
self?.handleCameraChange(event.cameraState)
}.store(in: &cancelables)
// Observe only the next style loading event
mapView.mapboxMap.onStyleLoaded.observeNext { [weak self] _ in
self?.setupStyle()
}.store(in: &cancelables)
The new event endpoints such as MapboxMap/onCameraChanged
are exposed as Signal
s that allow you to be notified of any events over time. While you are interested in receiving updates corresponding to these events you store the cancellation tokens returned from Signal/observe(_:)
or Signal/observeNext(_:)
methods. When the token is deallocated, the subscription will be automatically canceled and you will stop receiving updates.
Additionally, Signal
implements Combine.Publisher
, so Combine usage in iOS 13+ targets is recommended:
v11:
mapboxMap.onCameraChanged
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
.map(\.cameraState)
.sink { [weak self] cameraState in
self?.handleCameraChange(cameraState)
}.store(in: &cancellables)
Following these changes, methods MapboxMap.onEvery
, MapboxMap.onNext
, Snapshotter.onEvery
, Snapshotter.onNext
have been deprecated while methods MapboxMap.observe
and Snapshotter.observe
have been removed.
2.4 New View Annotations API
We introduce support for Dynamic View Annotations that automatically position themselves at any geometry (Point
, Polyline
, or Polygon
). For example, you can visualize ETA labels attached to the route line that is rendered by LineLayer
.
To make View Annotations simpler to use, we introduce new ViewAnnotation
object, that helps create an annotation from any UIView:
v11
// Create annotation
let view = CustomView(text: "🏠")
let annotation = ViewAnnotation(coordinate: coordinate, view: view)
annotation.allowOverlap = true
mapView.viewAnnotations.add(annotation)
// Update annotation
annotation.visible = false
// Remove annotation
annotation.remove()
The following example uses a dynamic ViewAnnotation
to display route details:
v11
let view = ETAView(text: "55 min")
let annotation = ViewAnnotation(layerId: "route", view: view)
annotation.variableAnchors = .all // Allow anchor to be displayed in all directions.
annotation.onAnchorChanged = { config in
// Update anchor position.
etaView.anchor = config.anchor
}
mapView.viewAnnotations.add(annotation)
// When annotation content is changed, call `setNeedsUpdateSize()` for proper positioning.
view.text = "1h 05min"
annotation.setNeedsUpdateSize()
The new Dynamic View Annotations are supported in SwiftUI, have a look at the SwiftUI-User-Guide guide.
2.5 Map Content Gesture System
The new API allows you to assign Tap and Long Press gestures handlers to Annotations, Layers, and the Map. The handlers are called according to the rendered layer position starting from the top-most. The map handler is called when neither annotation nor layer handle the gesture.
v11
let annotationManager = mapView.annotations.makePolygonAnnotationManager()
var annotation = PolygonAnnotation(...)
annotation.tapHandler = { context in
print("tapped point annotation at \(context.coordinate)")
return true // the polygon handled the tap, do not propagate
}
annotationManager.annotations = [annotation]
mapView.gestures.onLayerTap("my-layer") { queriedFeature, context in
print("tapped feature \(queriedFeature) of my-layer at \(context.coordinate)")
return true // layer handled the tap, do not propagate
}.store(in: &cancelables)
mapView.gestures.onMapTap.observe { context in
// this handler is called when neither annotation nor layer handled the tap.
print("map tapped at \(context.coordinate)")
}.store(in: &cancelables)
For more details, read the Map Content Gestures User Guide.
2.6 Access Token and Map Options management
You can now set the access token for every Mapbox SDK via single call of MapboxOptions/accessToken
. By default, Mapbox SDKs will try to initialize it upon framework initialization time from:
MBXAccessToken
property list value in the app bundle;MapboxAccessToken
file in the app bundle.
If you wish to set access token programmatically, it is highly recommended to set it before initializing a MapView
.
v11:
import MapboxMaps
MapboxOptions.accessToken = accessToken
Set configurations for the external resources used by Maps API through the MapboxMapsOptions
:
v11:
import MapboxMaps
MapboxMapsOptions.dataPath = customDataPathURL
MapboxMapsOptions.assetPath = customAssetPathURL
MapboxMapsOptions.tileStoreUsageMode = .readOnly
MapboxMapsOptions.tileStore = tileStore
To remove the temporary map data, use the MapboxMap/clearData(completion:)
method.
As part of this change ResourceOptions
and ResourceOptionsManager
have been removed.
The TileStore
also no longer accepts access token as part of its options.
2.7 New 3D Lighting API
In v11 we've introduced new lighting APIs to give you control of lighting and shadows in your map when using 3D objects: AmbientLight
and DirectionalLight
. We've also added new APIs on FillExtrusionLayer
and LineLayer
s to support this 3D lighting styling and enhance your ability to work with 3D model layers. Together, these properties can illuminate your 3D objects such as buildings and terrain to provide a more realistic and immersive map experience for your users. You can set these properties at runtime to follow the time of day, a particular mood, or other lighting goals in your map. See our 3D Lights example for implementation recommendations.
2.8 Location API
We introduced several changes to the location-related classes and protocols that will make working with location easier.
The old LocationProvider
and Location
were significantly simplified:
-
The
LocationProvider
andLocation
are now only responsible for providing location updates. TheLocationProvider
doesn't manage the permissions, accuracy authorization, or heading anymore. -
Heading (compass) data doesn't take part in
Location
. -
The new
HeadingProvider
andHeading
are now responsible for providing the heading (compass) updates. TheHeadingProvider
is optional and only needed if you usePuckBearing/heading
as a puck bearing type. -
Note:
Location
andHeading
have been separated because their updates can come from the different sources. This also allows us to animate the heading quicker than the location which results in more responsive puck behavior.
In case you need to drive the puck with custom location data, the LocationProvider
protocol is easy to implement in v11:
class CustomLocationProvider: LocationProvider {
private let observers: NSHashTable<AnyObject> = .weakObjects()
var location: Location? {
didSet {
guard let location else { return }
for observer in observers.allObjects {
(observer as? LocationObserver)?.onLocationUpdateReceived(for: [location])
}
}
}
public func getLastObservedLocation() -> Location? {
location
}
public func addLocationObserver(for observer: LocationObserver) {
observers.add(observer)
}
public func removeLocationObserver(for observer: LocationObserver) {
observers.remove(observer)
}
}
// Override the location provider with the custom one.
let locationProvider = CustomLocationProvider()
mapView.location.override(locationProvider: locationProvider)
In case you also need to supply a custom heading (compass) data, implement the HeadingProvider
and override it too:
let headingProvider = CustomHeadingProvider()
mapView.location.override(locationProvider: locationProvider, headingProvider: headingProvider)
The LocationManager
was simplified too. Now it only manages the location puck, not the LocationProvider
. For example, its LocationManager/options
only determine the puck appearance. If you need to fine-tune the location provider itself, do it directly via the default AppleLocationProvider
or your own custom provider implementation.
v10
mapView.location.options.distanceFilter = 100
v11
let locationProvider = AppleLocationProvider()
locationProvider.options.distanceFilter = 100
mapView.location.override(provider: locationProvider)
The LocationManager
now provides Signal
endpoints such as LocationManager/onPuckRender
, LocationManager/onLocationChange
, LocationManager/onHeadingChange
. You can use them to observe puck in the same way, as Map Events (see section 2.2).
v10
mapView.location.addPuckLocationConsumer(self)
v11
mapView.location.onPuckRender.observe { renderingData in
// Adjust puck-connected elements (route line, annotations) here.
}.store(in: &cancelables)
As a bonus, you now can use a Combine Publisher
to drive the puck location updates:
v11
class Example {
@Published
private var locations = [Location(coordinate: .init(latitude: 0, longitude: 0))]
@Published
private var heading = Heading(direction: 0, accuracy: 0)
func setup() {
mapView.location.override(
locationProvider: $location.eraseToSignal(),
headingProvider: $heading.eraseToSignal())
}
func update() {
locations = /* new locations update */
heading = /* new heading */
}
See a more detailed example.
2.9 Camera API
In v11, we have refined the Camera API introduced in v10 to improve developer ergonomics. These changes include several minor updates to usability:
- The SDK now exposes the owner property on
CameraAnimator
, allowing you to identify the owner in an easier way. - The
cameraFor methods
(cameraForCoordinatesArray
,cameraForLocationArray
, andcameraForCoordinateBounds
) have been simplified and aligned with our Android and Web SDKs. Passing a padding parameter is now optional, and additional optional maxZoom and offset parameters are available forcameraForCoordinateBounds
. - Finally,
cameraState
can now be accessed throughmapboxMap
rather than directly on mapView.
v10:
mapView.cameraState.center
v11:
mapView.mapboxMap.cameraState.center
2.10 Tracing
The Maps SDK introduces signpost recording support. Signposts are important instruments for analyzing performance and detecting bottlenecks in your code.
How to enable tracing
Tracing.status = .enabled
Or you can set the MAPBOX_MAPS_SIGNPOSTS_ENABLED
environment variable to 1
in your application scheme.
Note that these options will enable all available Maps SDK components for tracing.
Configure tracing components
Signposts in the Maps SDK are currently separated into two components:
Tracing component | Description |
---|---|
core | Rendering engine (responsible for almost every rendering aspect in the MapView and Snapshotter ). |
platform | Maps SDK functionality like gestures, animations, view annotations, and so on. |
Important: SDK generates a lot of event for each frame, so Instruments might skip some of them in
Immediate
record mode. EnableLast N seconds
mode to preserve full signpost data (see more).
To limit signposts generation for a single component, use the following API:
Tracing.status = .platform
To configure tracing components through environment variable use comma separator like:
MAPBOX_MAPS_SIGNPOSTS_ENABLED=core,platform
Pass 0
or disabled
to disable tracing through environment variable.
Tracing.status
API takes precedence over environment variable value. All values are case-insensitive.
2.11 Mapbox Maps Recorder
MapRecorder
provides an experimental API to record and replay map interaction sessions. Such recordings can be used to debug issues which require multiple steps to reproduce. See a usage example in the MapRecorder
example.
2.12 Other minor ergonomic improvements
2.12.1 MapboxMap
We added an experimental tileCover
method to MapboxMap
that returns tile Ids covering the map. Use TileCoverOptions-swift.struct
to identify which tile range to return tile Ids for.
let tileCoverOptions = TileCoverOptions(tileSize: 512, minZoom: 4, maxZoom: 8, roundZoom: true)
let tileIds = mapView.mapboxMap.tileCover(for: tileCoverOptions)
2.12.2 Sources
Sources are now required to specify Source/id
upon creation for easier reference later.
v10:
let terrainSource = RasterDemSource()
mapView.mapboxMap.style.addSource(terrainSource, id: "terrain-source")
v11:
let terrainSource = RasterDemSource(id: "terrain-source")
mapView.mapboxMap.addSource(terrainSource)
The GeoJSONSource
now supports configuration with a GeoJSON string as well as a URL, Feature, Feature Collection, or Geometry:
v11:
let poiGeoJSON = """
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -151.5129, 63.1016 ] } }
]
}
"""
var poiSource = GeoJSONSource(id: "poi")
poiSource.data = .string(poiGeoJSON)
mapView.mapboxMap.addSource(poiSource)
2.12.3
Most layers (such as LineLayer
, CircleLayer
, and others) now require the source
parameter in the initializer. It will make style manipulation code less error-prone.
v10
var lineLayer = LineLayer(id: "route-line")
lineLayer.source = "route-data"
mapView.mapboxMap.style.addLayer(lineLayer)
v11
let lineLayer = LineLayer(id: "route-line", source: "route-data")
mapView.mapboxMap.addLayer(lineLayer)
Contrary to that, some layers (such as BackgroundLayer
, SkyLayer
, and LocationIndicatorLayer
) don't need source
, sourceLayer
, and filter
properties. To clean up the code we removed them from those layers and from the Layer
protocol.
2.12.4 Support of GeoJSON partial updates.
Instead of setting the whole new GeoJSON object anew every time a single feature has changed, now you can apply more granular, partial GeoJSON updates.
If your features have associated identifiers - you can add, update and remove them on individual basis in your GeoJSONSource
.
This is especially beneficial for GeoJSONSource
s hosting a large amount of features - in this case adding a feature can be up to four times faster with partial update API.
try mapView.mapboxMap.addGeoJSONSourceFeatures(forSourceId: sourceId, features: features)
try mapView.mapboxMap.updateGeoJSONSourceFeatures(forSourceId: sourceId, features: features)
try mapView.mapboxMap.removeGeoJSONSourceFeatures(forSourceId: sourceId, featureIds: featureIds)
2.12.5 Gestures
Breaking change
MapboxMap.dragStart()
and MapboxMap.dragEnd()
are not in use anymore and got removed, instead use MapboxMap.beginGesture()
and MapboxMap.endGesture()
respectively.
While maintaining the existing gesture approach we made minor improvements. In v11 we now:
- allow animation during any ongoing gestures
- enable zoom during a drag gesture
- added a
rotation
case toGestureType
to be able to detect rotation separately from other gestures.
2.12.6 Expressions
- Introduced
hsl
,hsla
color expression - Introduced
random
expression - Introduced
measureLight
expression lights configuration property
2.12.7 Cache Management
Experimental API MapboxMap/setMemoryBudget(_:)
was renamed to MapboxMap/setTileCacheBudget(_:)
and promoted to stable.
2.12.8 Puck3D
's scaling behavior
To further improve the performance of 3D model layer, we have replaced Puck 3D's default model-scale
expression with a new API Puck3DConfiguration/modelScaleMode
. By default this property is ModelScaleMode/viewport
, which will keep the 3D model size constant across different zoom levels.
While this means that Puck 3D's size should render similarly to v10, it does introduces a behavior breaking change - that Puck3DConfiguration/modelScale
needs to be adjusted to correctly render the puck (in testing we found the adjustment to be around 100 times of v10 model-scale
value, but that could vary depending on other properties etc.).
3. Replace Deprecated APIs and Address Breaking Changes
Check for any deprecated APIs in your code and replace them with the recommended alternatives. Deprecated APIs may be removed in future releases.
3.1 Replace deprecated MapboxMap/style
and Snapshot/style
We've simplified MapboxMap
and Snapshot so you can now access Style APIs directly from MapboxMap
and Snapshotter
instance rather than going through the deprecated Style object. For example:
v10:
mapView.mapboxMap.style.updateGeoJSONSource(withId: "route", geoJSON: route)
...
let projection = snapshot.style.projection
v11:
mapView.mapboxMap.updateGeoJSONSource(withId: "route", geoJSON: route)
...
let projection = snapshot.projection
3.2 Replace deprecated Annotations properties for iconTextFit
and iconTextFitPadding
In v11, you can update iconTextFit
and iconTextFitPadding
directly on the PointAnnotation
rather than through the PointAnnotationManager
. This allows for control over these values for each annotation.
v10:
pointAnnotationManager.iconTextFit = .width
pointAnnotationManager.iconTextFitPadding = [1, 2.3, 4, 5]
v11:
pointAnnotation.iconTextFit = .width
pointAnnotation.iconTextFitPadding = [1, 2.3, 4, 5]
As a result, PointAnnotationManager/iconTextFit
and PointAnnotationManager/iconTextFitPadding
are deprecated in v11 and will be removed in v12.
3.3 Replace deprecated Events methods
In v11, mapView.mapboxMap.onEvery(<eventType>)
and mapView.mapboxMap.onNext(event: <eventType>)
have been deprecated in favor of mapboxMap.on<eventType>.observeNext
and mapboxMap.on<eventType>.observe
.
For more context, see the type-safe Events API section above.
3.4 Replace deprecated MapView properties
In v11 mapView.cameraState
has been moved to mapboxMap
, so the mapView property has been deprecated. Update your implementation like so:
v10:
let center = mapView.cameraState.center
v11:
let center = mapView.mapboxMap.cameraState.center
3.5 Replace deprecated LocationManager
properties
We've made several changes and renamed parts of LocationManager
. See the above Location API section for more details.
3.6 Replace deprecated MapboxMap
properties
Several properties on MapboxMap
were renamed in v11 for clarity. Update your implementation:
v10:
mapboxMap.uri = .standard
mapboxMap.JSON = "Your style JSON"
mapboxMap.transition = TransitionOptions(
duration: 3,
delay: 2,
enablePlacementTransitions: true)
mapboxMap.isLoaded = true
let defaultCamera = mapboxMap.defaultCamera
v11:
mapboxMap.styleURI = .standard
mapboxMap.styleJSON = "Your style JSON"
mapboxMap.styleTransition = TransitionOptions(
duration: 3,
delay: 2,
enablePlacementTransitions: true)
mapboxMap.isStyleLoaded = true
let defaultCamera = mapboxMap.styleDefaultCamera
3.7 Maps SDK no longer reexport MetalKit
and UIKit
Mapbox Maps SDK no longer reexports MetalKit
and UIKit
frameworks, so you will need to import them as needed for your code. In v10 version you could omit import UIKit
if you already had an import MapboxMaps
statement, but that is no longer possible.
v10:
import MapboxMaps
class ViewController: UIViewController { }
v11:
import UIKit
import MapboxMaps
class ViewController: UIViewController { }
3.8 HTTP Stack changes
3.8.1 HttpServiceFactory
and HttpInterceptor
changes
HTTPServiceFactory.reset
, HttpServiceFactory.setUserDefinedForCustom
and HttpServiceInterface
have been removed from public visibility. It is thus no longer possible to override the HTTP stack.
If you need to set a HTTP interceptor you can do it via the HttpServiceFactory.setHttpServiceInterceptorInterface
function. The HttpServiceInterceptorInterface
has been changed: the onDownload
function no longer exists and the signature of onRequest
and onResponse
have been changed to return a value through a continuation.
v10
class Interceptor: HttpServiceInterceptorInterface {
func onRequest(for request: HttpRequest) -> HttpRequest {
return request
}
func onResponse(for response: HttpResponse) -> HttpResponse {
return response
}
func onDownload(forDownload download: DownloadOptions) -> DownloadOptions {
return download
}
}
v11
class Interceptor: HttpServiceInterceptorInterface {
func onRequest(for request: HttpRequest, continuation: @escaping HttpServiceInterceptorRequestContinuation) {
continuation(HttpRequestOrResponse.fromHttpRequest(request))
}
func onResponse(for response: HttpResponse, continuation: @escaping HttpServiceInterceptorResponseContinuation) {
continuation(response)
}
}
3.8.2 HttpRequest
changes
Introduce HttpRequestFlags
constants to set additional HttpRequest
parameters.
HttpRequest.keepCompression
moved to HttpRequest.flags
.
v10
let httpRequest = HttpRequest(method: HttpMethod.get, url: "", headers: [:], keepCompression: false, timeout: 0,
networkRestriction: NetworkRestriction.none, sdkInformation: sdkInformation, body: nil)
v11
let httpRequest = HttpRequest(method: HttpMethod.get, url: "", headers: [:], timeout: 0, networkRestriction: NetworkRestriction.none,
sdkInformation: sdkInformation, body: nil, flags: HttpRequestFlags.none)
3.9 Offline API
3.9.1 OfflineManager
API changes
- Due to changes documented in Access Token and Map Options management, you no longer need to provide a resource options when initializing an instance of
OfflineManager
. TilesetDescriptorOptionsForTilesets
andOfflineManager/createTilesetDescriptorForTilesetDescriptorOptions(_:)
has been removed. Instead you can provide an optional list oftilesets
when initializing an instance ofTilesetDescriptorOptions
and use it to create aTilesetDescriptor
usingOfflineManager/createTilesetDescriptor(_:)
.- You can now be notified when a style pack is removed with a completion handler.
v10
let offlineManager = OfflineManager(resourceOptions: aResourceOptions)
let tilesetDescriptorOptions = TilesetDescriptorOptionsForTilesets(
tilesets: ["mapbox://mapbox.mapbox-streets-v8"],
zoomRange: 0...5)
let tilesetDescriptor = offlineManager.createTilesetDescriptorForTilesetDescriptorOptions(tilesetDescriptorOptions)
offlineManager.removeStylePack(for: .streets)
v11
let offlineManager = OfflineManager()
let tileSetDescriptorOptions = TilesetDescriptorOptions(
styleURI: .outdoors,
zoomRange: 0...16,
tilesets: ["mapbox://mapbox.mapbox-streets-v8"])
let tilesetDescriptor = offlineManager.createTilesetDescriptor(for: tileSetDescriptorOptions)
offlineManager.removeStylePack(for: .streets) { result in
// handle style pack removal result
}
3.9.2 Legacy OfflineRegionManager
changes
- Due to changes documented in Access Token and Map Options management, you no longer need to provide a resource options when initializing an instance of
OfflineRegionManager
. ResponseError
has been renamed toOfflineRegionError
, with new flag namedisFatal
indicating that the error is fatal, in other words the region cannot download any resources and it will transition to the inactive state.OfflineRegionObserver
no longer requires functionresponseError(forError:)
, instead you can implement functionerrorOccurred(forError:)
to be notified of errors encountered while downloading regional resources.ResponseErrorReason
is renamed toOfflineRegionErrorType
.- The
OfflineRegionErrorType.diskFull
is introduced as a specific error code for shortage of the available space to store the resources. - The
OfflineRegionErrorType.tileCountLimitExceeded
is introduced as a specific error code indicating that the limit on the number of Mapbox tiles stored for offline regions has been reached. As a result, functiontileCountLimitExceeded()
is no longer required for conformers ofOfflineRegionObserver
.
- The
v10
let offlineRegionManager = OfflineRegionManager(resourceOptions: aResourceOptions)
let observer = OfflineRegionObserver()
offlineRegionManager.setOfflineRegionObserverFor(observer)
class OfflineRegionObserver: MapboxCoreMaps.OfflineRegionObserver {
func responseError(forError error: ResponseError) {
// handle error
}
func tileCountLimitExceeded() {
// handle tile count limit exceeded
}
}
v11
let offlineRegionManager = OfflineRegionManager()
let observer = OfflineRegionObserver()
offlineRegionManager.setOfflineRegionObserverFor(observer)
class OfflineRegionObserver: MapboxCoreMaps.OfflineRegionObserver {
func errorOccurred(forError error: OfflineRegionError) {
if case error.type == .tileCountLimitExceeded {
// handle tile count limit exceed
}
...
}
}
3.10 OverviewViewportStateOptions
changes.
The OverviewViewportStateOptions.padding
parameter is renamed to OverviewViewportStateOptions/geometryPadding
. It adds padding for every coordinate before fitting the geometry. The OverviewViewportStateOptions/padding
now adds camera padding, like FollowPuckViewportStateOptions/padding
.
3.11 Bearing updates are disabled by default.
The default value for LocationOptions/puckBearingEnabled
option has changed from true
to false
. That practically means that
MapView wouldn't redraw on each device compass update and should significantly reduce CPU usage for applications that only display user location without bearing/heading indication. If your application still need to rotate puck image according to device heading or location course, enable the option as:
mapView.location.options.puckBearingEnabled = true
3.12 TileRegionLoadOptions
changes.
TileRegionLoadOptions.startLocation
property type changed from CLLocation
to Coordinate2D
.
4. Update APIs deprecated in v10 which have been removed in v11
textLineHeight
property has been removed fromPointAnnotationManager
. Instead, use the data-drivenPointAnnotation/textLineHeight
.PuckBearingSource
has been renamed toPuckBearing
and removed in v11. Along with this, constructorLocationOptions.init(distanceFilter:desiredAccuracy:activityType:puckType:puckBearingSource:puckBearingEnabled:)
has also been removed, instead useLocationOptions/init(puckType:puckBearing:puckBearingEnabled:)
pinchRotateEnabled
property has been removed fromGestureOptions
. Instead, use the renamedGestureOptions/rotateEnabled
.- Experimental
MapboxMap.setRenderCache(_:)
has been removed. MapEvents.EventKind
andMapEvents.Event
have been removed, however, we have provided a shim to make the migration process from v10 to v11 smoother. Refer to the Type-safe Events API section to update your events code.- The following transition properties have been removed from our layers:
backgroundPatternTransition
has been removed fromBackgroundLayer
fillExtrusionPatternTransition
has been removed fromFillExtrusionLayer
fillPatternTransition
has been removed fromFillLayer
lineDasharrayTransition
,linePatternTransition
have been removed fromLineLayer
5. Review other changes
- For all
Layer
types, theLayer/visibility
property now only supports a constant value, instead ofExpression
. - Protocol
LocationProvider
now requires class semantic for implementation. - Map size is now synced to the size of the Metal view
- The
easeTo/flyTo
APIs return non-optional cancelable token. - The following
GeoJsonSource
cluster APIs now returnCancelable
:getGeoJsonClusterLeaves
,getGeoJsonClusterChildren
,getGeoJsonClusterExpansionZoom
. - The
MapOptions/optimizeForTerrain
option was removed, whenever terrain is present layer order is now automatically adjusted for better performance. Before, optimization was the default.
7. Test Your App
Test your app thoroughly after making the changes to make sure that everything is working as expected.
8. Conclusion
Following the above steps will help you migrate your app to the latest version of the Mapbox Maps SDK for Android. If you run into any issues during the migration process, refer to the Mapbox Maps SDK for iOS documentation or reach out to the Mapbox support team for help.
Upgrade your application from the Mapbox Maps SDK for iOS v6 to v10.