Skip to content

Commit fe1a898

Browse files
persidskiygithub-actions[bot]
authored andcommitted
Enable use of MapboxCommon's location manager in MapView (#7769)
GitOrigin-RevId: 05997fe40cbe7eabff8df68b3e4e54c958548338
1 parent da8b091 commit fe1a898

File tree

21 files changed

+349
-223
lines changed

21 files changed

+349
-223
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,31 @@ let mapView = MapView(frame: view.bounds, mapInitOptions: options)
2020
```
2121
* Add `StyleReloadPolicy` to control style reload behavior. Use `reloadPolicy: .always` parameter in `loadStyle()` methods or `MapStyle` initializers to always reload the style even when the URI or JSON matches the currently loaded style. Defaults to `.onlyIfChanged` for optimal performance.
2222

23+
* Introduce the `LocationManager.locationDataModel` and make it possible to use location provider from MapboxCommon. Deprecate the `LocationManager.override*` methods.
24+
Now you can choose to use the location provider from MapboxCommon.
25+
```swift
26+
@_spi(Experimental) import MapboxMaps
27+
28+
// UIKit
29+
let initOptions = MapInitOptions(
30+
locationDataModel: .createCore()
31+
)
32+
let mapView = MapView(mapInitOptions: initOptions) // specify at init time (recommended)
33+
mapView.mapboxMap.locationDataModel = .createCore() // or, override it at runtime
34+
35+
36+
// SwiftUI
37+
struct MyView: View {
38+
@State var locationDataModel = LocationDataModel.createCore()
39+
var body: some View {
40+
Map(viewport: $viewport) {
41+
Puck2D(bearing: .heading)
42+
}
43+
.locationDataModel(locationDataModel)
44+
}
45+
}
46+
```
47+
2348
## 11.16.0 - 21 October, 2025
2449

2550
## 11.16.0-rc.2 - 14 October, 2025

Sources/Examples/All Examples/VoiceOverAccessibilityExample.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import UIKit
2+
import Combine
23
import CoreLocation
34
import MapboxMaps
45

@@ -51,7 +52,7 @@ final class VoiceOverAccessibilityExample: UIViewController, ExampleProtocol {
5152
mapView.accessibilityElements = []
5253

5354
let location = Location(coordinate: centerCoordinate)
54-
mapView.location.override(locationProvider: Signal(just: [location]))
55+
mapView.location.dataModel = LocationDataModel(location: Just([location]).eraseToAnyPublisher())
5556
mapView.location.options.puckType = .puck2D(.makeDefault())
5657

5758
// create point annotation manager to house point annotations

Sources/Examples/Info.plist

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,10 @@
100100
</array>
101101
<key>UISupportedInterfaceOrientations</key>
102102
<array>
103-
<string>UIInterfaceOrientationPortrait</string>
104103
<string>UIInterfaceOrientationLandscapeLeft</string>
105104
<string>UIInterfaceOrientationLandscapeRight</string>
106-
</array>
107-
<key>UISupportedInterfaceOrientations~ipad</key>
108-
<array>
109105
<string>UIInterfaceOrientationPortrait</string>
110106
<string>UIInterfaceOrientationPortraitUpsideDown</string>
111-
<string>UIInterfaceOrientationLandscapeLeft</string>
112-
<string>UIInterfaceOrientationLandscapeRight</string>
113107
</array>
114108
</dict>
115109
</plist>

Sources/Examples/SwiftUI Examples/LocateMeExample.swift

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,60 @@
11
import SwiftUI
2-
import MapboxMaps
2+
@_spi(Experimental) import MapboxMaps
3+
import CoreLocation
34

5+
/// The example demonstrates Puck and Viewport configuration that allow to follow user location.
46
struct LocateMeExample: View {
57
@State var viewport: Viewport = .followPuck(zoom: 13, bearing: .constant(0))
68

79
var body: some View {
8-
Map(viewport: $viewport) {
9-
Puck2D(bearing: .heading)
10+
MapReader { proxy in
11+
Map(viewport: $viewport) {
12+
Puck2D(bearing: .heading)
13+
.showsAccuracyRing(true)
14+
}
15+
.mapStyle(.standard)
16+
.ignoresSafeArea()
17+
.overlay(alignment: .trailing) {
18+
LocateMeButton(viewport: $viewport)
19+
}
1020
}
21+
}
22+
}
23+
24+
25+
/// The example demonstrates Puck and Viewport configuration that allow to follow user location.
26+
/// In this example the CoreLocationProvider is use instead of default `AppleLocationProvider`.
27+
struct LocateMeCoreLocationProviderExample: View {
28+
@State var locaionModel = LocationDataModel.createCore()
29+
@State var viewport: Viewport = .followPuck(zoom: 13, bearing: .constant(0))
30+
31+
var body: some View {
32+
MapReader { proxy in
33+
Map(viewport: $viewport) {
34+
Puck2D(bearing: .heading)
35+
.showsAccuracyRing(true)
36+
37+
}
1138
.mapStyle(.standard)
39+
.locationDataModel(locaionModel)
1240
.ignoresSafeArea()
1341
.overlay(alignment: .trailing) {
1442
LocateMeButton(viewport: $viewport)
1543
}
44+
.onAppear {
45+
/// The core location provider doesn't automatically initiate the location authorization request.
46+
/// Instead, the application is responsible for that.
47+
let locationManager = CLLocationManager()
48+
if locationManager.authorizationStatus == .notDetermined {
49+
locationManager.requestWhenInUseAuthorization()
50+
}
51+
}
52+
53+
}
1654
}
1755
}
1856

57+
1958
struct LocateMeButton: View {
2059
@Binding var viewport: Viewport
2160

Sources/Examples/SwiftUI Examples/LocationOverrideExample.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ struct LocationOverrideExample: View {
66
private class LocationProvider {
77
@Published var location = Location(coordinate: .zero)
88
@Published var heading = Heading(direction: 0, accuracy: 0)
9+
10+
lazy var model = {
11+
LocationDataModel(
12+
location: $location.map {[$0]}.eraseToAnyPublisher(),
13+
heading: $heading.eraseToAnyPublisher())
14+
}()
915
}
1016

1117
@State private var provider = LocationProvider()
@@ -26,12 +32,7 @@ struct LocationOverrideExample: View {
2632
return false
2733
}
2834
}
29-
.onAppear {
30-
/// Override the location and Heading provider with Combine publishers.
31-
proxy.location?.override(
32-
locationProvider: provider.$location.map {[$0]}.eraseToSignal(),
33-
headingProvider: provider.$heading.eraseToSignal())
34-
}
35+
.locationDataModel(provider.model)
3536
}
3637
.ignoresSafeArea()
3738
.overlay(alignment: .bottom) {

Sources/Examples/SwiftUI Examples/SwiftUIRoot.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct SwiftUIExamples {
4242
Example("Puck playground", note: "Display user location using puck.", destination: PuckPlayground())
4343
Example("Annotation Order", note: "Test the rendering order of annotations.", destination: AnnotationsOrderTestExample())
4444
Example("Snapshot Map", note: "Make a snapshot of the map.", destination: SnapshotMapExample())
45+
Example("Locate Me (Core Location Provider)", note: "Use Viewport to create user location control. This example uses Location Provider from MabpoxCommon", destination: LocateMeCoreLocationProviderExample())
4546

4647
Example("Attribution url via callback", note: "Works on iOS 13+", destination: AttributionManualURLOpen())
4748
Example("Raster particles", note: "Rendering of raster particles.", destination: RasterParticleExample())

Sources/MapboxMaps/Documentation.docc/API Catalogs/Location APIs.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Location
66

77
- ``LocationManager``
8+
- ``LocationDataModel``
89
- ``LocationOptions``
910
- ``PuckType``
1011
- ``Puck2DConfiguration``

Sources/MapboxMaps/Foundation/InterfaceOrientationProvider.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import Foundation
22
import UIKit
33
import CoreLocation
44

5-
#if swift(>=5.9)
6-
@available(visionOS, unavailable)
7-
#endif
5+
@available(visionOS, unavailable)
86
internal final class DefaultInterfaceOrientationProvider {
97
var onInterfaceOrientationChange: Signal<UIInterfaceOrientation> { subject.signal }
108

@@ -29,6 +27,11 @@ internal final class DefaultInterfaceOrientationProvider {
2927
self.notificationCenter = notificationCenter
3028
self.device = device
3129
}
30+
31+
convenience init() {
32+
self.init(notificationCenter: NotificationCenter.default, device: UIDevice.current)
33+
}
34+
3235

3336
private func startUpdatingInterfaceOrientation() {
3437
device.beginGeneratingDeviceOrientationNotifications()

Sources/MapboxMaps/Foundation/MapInitOptions.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public final class MapInitOptions: NSObject {
3737
/// - SeeAlso: [`Improving edge-rendering quality with multisample antialiasing (MSAA)`](https://developer.apple.com/documentation/metal/metal_sample_code_library/improving_edge-rendering_quality_with_multisample_antialiasing_msaa)
3838
public let antialiasingSampleCount: Int
3939

40+
public let locationDataModel: LocationDataModel?
41+
4042
/// Creates new instance of ``MapInitOptions``.
4143
///
4244
/// - Parameters:
@@ -53,7 +55,8 @@ public final class MapInitOptions: NSObject {
5355
cameraOptions: CameraOptions? = nil,
5456
styleURI: StyleURI? = .standard,
5557
styleJSON: String? = nil,
56-
antialiasingSampleCount: Int = 1
58+
antialiasingSampleCount: Int = 1,
59+
locationDataModel: LocationDataModel? = nil
5760
) {
5861
let mapStyle: MapStyle? = if let styleJSON {
5962
MapStyle(json: styleJSON)
@@ -65,7 +68,8 @@ public final class MapInitOptions: NSObject {
6568
self.init(mapStyle: mapStyle,
6669
mapOptions: mapOptions,
6770
cameraOptions: cameraOptions,
68-
antialiasingSampleCount: antialiasingSampleCount)
71+
antialiasingSampleCount: antialiasingSampleCount,
72+
locationDataModel: locationDataModel)
6973
}
7074

7175
/// Creates new map init options.
@@ -79,12 +83,14 @@ public final class MapInitOptions: NSObject {
7983
mapStyle: MapStyle?,
8084
mapOptions: MapOptions = MapOptions(),
8185
cameraOptions: CameraOptions? = nil,
82-
antialiasingSampleCount: Int = 1
86+
antialiasingSampleCount: Int = 1,
87+
locationDataModel: LocationDataModel? = nil
8388
) {
8489
self.mapOptions = mapOptions
8590
self.cameraOptions = cameraOptions
8691
self.mapStyle = mapStyle
8792
self.antialiasingSampleCount = antialiasingSampleCount
93+
self.locationDataModel = locationDataModel
8894
}
8995

9096
/// :nodoc:
@@ -144,7 +150,8 @@ extension MapInitOptions {
144150
return MapInitOptions(
145151
mapStyle: resolvedStyle,
146152
mapOptions: resolvedMapOptions,
147-
cameraOptions: cameraOptions)
153+
cameraOptions: cameraOptions,
154+
locationDataModel: locationDataModel)
148155
} else {
149156
return self
150157
}

Sources/MapboxMaps/Foundation/MapView.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
439439
sendInitialTelemetryEvents()
440440

441441
// Set up managers
442-
setupManagers()
442+
setupManagers(initOptions: resolvedMapInitOptions)
443443
}
444444

445445
private func makeMapboxMap(resolvedMapInitOptions: MapInitOptions) -> MapboxMap {
@@ -456,7 +456,7 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
456456
}
457457

458458
// swiftlint:disable:next function_body_length
459-
internal func setupManagers() {
459+
internal func setupManagers(initOptions: MapInitOptions) {
460460

461461
// Initialize/Configure camera manager first since Gestures needs it as dependency
462462
cameraAnimatorsRunner = dependencyProvider.makeCameraAnimatorsRunner(
@@ -501,9 +501,11 @@ open class MapView: UIView, SizeTrackingLayerDelegate {
501501
// Initialize/Configure location source and location manager
502502
location = LocationManager(
503503
interfaceOrientationView: .weakRef(self),
504-
displayLink: displayLinkSignalSubject.signal,
505504
styleManager: mapboxMap,
506-
mapboxMap: mapboxMap
505+
mapboxMap: mapboxMap,
506+
displayLink: displayLinkSignalSubject.signal,
507+
dataModel: initOptions.locationDataModel ?? .createDefault(),
508+
nowTimestamp: .now
507509
)
508510

509511
// Initialize/Configure view annotations manager

0 commit comments

Comments
 (0)