diff --git a/platform/ios/MapLibre.docc/LocationPrivacyExample.md b/platform/ios/MapLibre.docc/LocationPrivacyExample.md
index 65711794e..f78d403b3 100644
--- a/platform/ios/MapLibre.docc/LocationPrivacyExample.md
+++ b/platform/ios/MapLibre.docc/LocationPrivacyExample.md
@@ -6,14 +6,16 @@ Requesting precise location with ``MLNLocationManager``.
This example shows how to request a precise location with ``MLNLocationManager``.
-First of all you need to prepare your `Info.plist`. You need to provide a description why your app needs to access location:
+Let's prepare your `Info.plist`:
+
+First, provide a description why your app needs to access location:
```plist
NSLocationWhenInUseUsageDescription
Dummy Location When In Use Description
```
-As well as a description why your app needs precise location.
+Second, add a description why your app needs precise location:
```plist
NSLocationTemporaryUsageDescriptionDictionary
@@ -23,6 +25,13 @@ As well as a description why your app needs precise location.
```
+Third and finally, specify your app only needs reduced location access by default (until you request precise accuracy in the example):
+
+```plist
+NSLocationDefaultAccuracyReduced
+
+```
+
The `Coordinator` defined below is also the ``MLNMapViewDelegate``. When the location manager authorization changes it will call the relevant method. If precise location has not been granted, a button is shown at the bottom of the map.

@@ -40,75 +49,85 @@ enum LocationAccuracyState {
case fullAccuracy
}
-class Coordinator: NSObject, MLNMapViewDelegate {
- @Binding var mapView: MLNMapView
- @Binding var locationAccuracy: LocationAccuracyState
- var pannedToUserLocation = false
+@MainActor
+class PrivacyExampleViewModel: NSObject, ObservableObject {
+ @Published var locationAccuracy: LocationAccuracyState = .unknown
+ @Published var showTemporaryLocationAuthorization = false
+}
- init(mapView: Binding, locationAccuracy: Binding) {
- _mapView = mapView
- _locationAccuracy = locationAccuracy
+class PrivacyExampleCoordinator: NSObject, MLNMapViewDelegate {
+ @ObservedObject private var mapViewModel: PrivacyExampleViewModel
+ private var pannedToUserLocation = false
+
+ init(mapViewModel: PrivacyExampleViewModel) {
+ self.mapViewModel = mapViewModel
+ super.init()
}
-
- func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) {
+
+ @MainActor func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) {
guard let accuracySetting = manager.accuracyAuthorization else {
return
}
-
+
switch accuracySetting() {
case .fullAccuracy:
- locationAccuracy = .fullAccuracy
+ mapViewModel.locationAccuracy = .fullAccuracy
case .reducedAccuracy:
- locationAccuracy = .reducedAccuracy
+ mapViewModel.locationAccuracy = .reducedAccuracy
@unknown default:
- locationAccuracy = .unknown
+ mapViewModel.locationAccuracy = .unknown
}
}
// when a location is available for the first time, we fly to it
func mapView(_ mapView: MLNMapView, didUpdate _: MLNUserLocation?) {
- if pannedToUserLocation {
- return
- }
+ guard !pannedToUserLocation else { return }
guard let userLocation = mapView.userLocation else {
print("User location is currently not available.")
return
}
mapView.fly(to: MLNMapCamera(lookingAtCenter: userLocation.coordinate, altitude: 100_000, pitch: 0, heading: 0))
+ pannedToUserLocation = true
}
}
-struct LocationPrivacyExample: UIViewRepresentable {
- @Binding var mapView: MLNMapView
- @Binding var locationAccuracy: LocationAccuracyState
-
- func makeCoordinator() -> Coordinator {
- Coordinator(mapView: $mapView, locationAccuracy: $locationAccuracy)
+struct PrivacyExampleRepresentable: UIViewRepresentable {
+ @ObservedObject var mapViewModel: PrivacyExampleViewModel
+
+ func makeCoordinator() -> PrivacyExampleCoordinator {
+ PrivacyExampleCoordinator(mapViewModel: mapViewModel)
}
func makeUIView(context: Context) -> MLNMapView {
let mapView = MLNMapView()
- mapView.showsUserLocation = true
+
mapView.delegate = context.coordinator
-
+ mapView.showsUserLocation = true
return mapView
}
- func updateUIView(_: MLNMapView, context _: Context) {}
+ func updateUIView(_ mapView: MLNMapView, context _: Context) {
+ if mapViewModel.showTemporaryLocationAuthorization {
+ let purposeKey = "MLNAccuracyAuthorizationDescription"
+ mapView.locationManager.requestTemporaryFullAccuracyAuthorization?(withPurposeKey: purposeKey)
+ DispatchQueue.main.async {
+ mapViewModel.showTemporaryLocationAuthorization = false
+ }
+ }
+ }
}
struct LocationPrivacyExampleView: View {
- @State private var mapView = MLNMapView()
- @State var locationAccuracy: LocationAccuracyState = .unknown
-
+ @StateObject private var viewModel = PrivacyExampleViewModel()
+
var body: some View {
VStack {
- LocationPrivacyExample(mapView: $mapView, locationAccuracy: $locationAccuracy)
+ PrivacyExampleRepresentable(mapViewModel: viewModel)
.edgesIgnoringSafeArea(.all)
- if locationAccuracy == LocationAccuracyState.reducedAccuracy {
+ if viewModel.locationAccuracy == LocationAccuracyState.reducedAccuracy {
Button("Request Precise Location") {
- handleButtonPress(mapView: mapView)
+ viewModel.showTemporaryLocationAuthorization.toggle()
}
.padding()
.background(Color.blue)
@@ -117,16 +136,5 @@ struct LocationPrivacyExampleView: View {
}
}
}
-
- private func handleButtonPress(mapView: MLNMapView) {
- print("Requesting precice location")
- switch locationAccuracy {
- case .reducedAccuracy:
- let purposeKey = "MLNAccuracyAuthorizationDescription"
- mapView.locationManager.requestTemporaryFullAccuracyAuthorization!(withPurposeKey: purposeKey)
- default:
- break
- }
- }
}
```
\ No newline at end of file
diff --git a/platform/ios/app-swift/Sources/LocationPrivacyExample.swift b/platform/ios/app-swift/Sources/LocationPrivacyExample.swift
index 8b65a5c05..481bc8985 100644
--- a/platform/ios/app-swift/Sources/LocationPrivacyExample.swift
+++ b/platform/ios/app-swift/Sources/LocationPrivacyExample.swift
@@ -9,75 +9,85 @@ enum LocationAccuracyState {
case fullAccuracy
}
-class Coordinator: NSObject, MLNMapViewDelegate {
- @Binding var mapView: MLNMapView
- @Binding var locationAccuracy: LocationAccuracyState
- var pannedToUserLocation = false
+@MainActor
+class PrivacyExampleViewModel: NSObject, ObservableObject {
+ @Published var locationAccuracy: LocationAccuracyState = .unknown
+ @Published var showTemporaryLocationAuthorization = false
+}
- init(mapView: Binding, locationAccuracy: Binding) {
- _mapView = mapView
- _locationAccuracy = locationAccuracy
+class PrivacyExampleCoordinator: NSObject, MLNMapViewDelegate {
+ @ObservedObject private var mapViewModel: PrivacyExampleViewModel
+ private var pannedToUserLocation = false
+
+ init(mapViewModel: PrivacyExampleViewModel) {
+ self.mapViewModel = mapViewModel
+ super.init()
}
- func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) {
+ @MainActor func mapView(_: MLNMapView, didChangeLocationManagerAuthorization manager: MLNLocationManager) {
guard let accuracySetting = manager.accuracyAuthorization else {
return
}
switch accuracySetting() {
case .fullAccuracy:
- locationAccuracy = .fullAccuracy
+ mapViewModel.locationAccuracy = .fullAccuracy
case .reducedAccuracy:
- locationAccuracy = .reducedAccuracy
+ mapViewModel.locationAccuracy = .reducedAccuracy
@unknown default:
- locationAccuracy = .unknown
+ mapViewModel.locationAccuracy = .unknown
}
}
// when a location is available for the first time, we fly to it
func mapView(_ mapView: MLNMapView, didUpdate _: MLNUserLocation?) {
- if pannedToUserLocation {
- return
- }
+ guard !pannedToUserLocation else { return }
guard let userLocation = mapView.userLocation else {
print("User location is currently not available.")
return
}
mapView.fly(to: MLNMapCamera(lookingAtCenter: userLocation.coordinate, altitude: 100_000, pitch: 0, heading: 0))
+ pannedToUserLocation = true
}
}
-struct LocationPrivacyExample: UIViewRepresentable {
- @Binding var mapView: MLNMapView
- @Binding var locationAccuracy: LocationAccuracyState
+struct PrivacyExampleRepresentable: UIViewRepresentable {
+ @ObservedObject var mapViewModel: PrivacyExampleViewModel
- func makeCoordinator() -> Coordinator {
- Coordinator(mapView: $mapView, locationAccuracy: $locationAccuracy)
+ func makeCoordinator() -> PrivacyExampleCoordinator {
+ PrivacyExampleCoordinator(mapViewModel: mapViewModel)
}
func makeUIView(context: Context) -> MLNMapView {
let mapView = MLNMapView()
- mapView.showsUserLocation = true
- mapView.delegate = context.coordinator
+ mapView.delegate = context.coordinator
+ mapView.showsUserLocation = true
return mapView
}
- func updateUIView(_: MLNMapView, context _: Context) {}
+ func updateUIView(_ mapView: MLNMapView, context _: Context) {
+ if mapViewModel.showTemporaryLocationAuthorization {
+ let purposeKey = "MLNAccuracyAuthorizationDescription"
+ mapView.locationManager.requestTemporaryFullAccuracyAuthorization?(withPurposeKey: purposeKey)
+ DispatchQueue.main.async {
+ mapViewModel.showTemporaryLocationAuthorization = false
+ }
+ }
+ }
}
struct LocationPrivacyExampleView: View {
- @State private var mapView = MLNMapView()
- @State var locationAccuracy: LocationAccuracyState = .unknown
+ @StateObject private var viewModel = PrivacyExampleViewModel()
var body: some View {
VStack {
- LocationPrivacyExample(mapView: $mapView, locationAccuracy: $locationAccuracy)
+ PrivacyExampleRepresentable(mapViewModel: viewModel)
.edgesIgnoringSafeArea(.all)
- if locationAccuracy == LocationAccuracyState.reducedAccuracy {
+ if viewModel.locationAccuracy == LocationAccuracyState.reducedAccuracy {
Button("Request Precise Location") {
- handleButtonPress(mapView: mapView)
+ viewModel.showTemporaryLocationAuthorization.toggle()
}
.padding()
.background(Color.blue)
@@ -86,17 +96,6 @@ struct LocationPrivacyExampleView: View {
}
}
}
-
- private func handleButtonPress(mapView: MLNMapView) {
- print("Requesting precice location")
- switch locationAccuracy {
- case .reducedAccuracy:
- let purposeKey = "MLNAccuracyAuthorizationDescription"
- mapView.locationManager.requestTemporaryFullAccuracyAuthorization!(withPurposeKey: purposeKey)
- default:
- break
- }
- }
}
// #-end-example-code