Skip to content

Commit 864b8dc

Browse files
maiosactions-user
authored andcommitted
[common][ios] location regions monitoring (#7597)
Introduces a Location Regions Monitoring system to the iOS location's component of Common SDK, enabling its client to monitor geographical regions and receive notifications when a device enters or exits specified areas. - When the app is terminated and a region is entered/exited, the system will wake the app up and geofence will be restarted and resumes checking the location against its features. cc @mapbox/core-sdk cc @mapbox/maps-ios --------- Co-authored-by: Changelog autocreator bot <[email protected]> GitOrigin-RevId: c3851a16807837d4714c545f59dfb77db74e0431
1 parent ab47520 commit 864b8dc

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

Sources/Examples/SwiftUI Examples/GeofencingUserLocation.swift

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,57 @@ import SwiftUI
55

66
/// This is an Example for Experimental API that is subject to change.
77
struct GeofencingUserLocation: View {
8-
@State private var initialLocation: CLLocationCoordinate2D?
8+
@State private var region: CircularRegion?
99
@ObservedObject private var geofencing = Geofencing()
1010
private let initialLocationProvider = InitialLocationProvider()
1111

1212
var body: some View {
1313
MapReader { proxy in
14-
Map(initialViewport: .followPuck(zoom: 16)) {
14+
Map(initialViewport: .followPuck(zoom: 13)) {
1515
Puck2D(bearing: .heading)
16-
if let initialLocation = initialLocation {
17-
GeofenceCircle(id: "circle", location: initialLocation, event: geofencing.lastEvent)
16+
if let region {
17+
GeofenceCircle(id: "circle", region: region, event: geofencing.lastEvent)
1818
}
1919
}
2020
.onMapLoaded { _ in startGeofencing(proxy.location) }
21+
.ignoresSafeArea()
22+
.overlay(alignment: .bottom) {
23+
PermissionView()
24+
}
2125
}
22-
.ignoresSafeArea()
2326
}
2427

2528
func startGeofencing(_ locationManager: LocationManager?) {
2629
geofencing.start {
2730
initialLocationProvider.start(locationManager: locationManager) { initialLocation in
28-
var feature = Feature(geometry: .geofenceCircle(initialLocation))
31+
let _region = CircularRegion(center: Point(initialLocation), radius: .random(in: 200...300))
32+
var feature = Feature(geometry: _region.center)
2933
feature.identifier = .string("geofence-source-circle")
30-
feature = feature.properties([GeofencingPropertiesKeys.dwellTimeKey: 1])
31-
geofencing.add(feature: feature, onSuccess: { _initialLocation.wrappedValue = initialLocation })
34+
feature = feature.properties([
35+
GeofencingPropertiesKeys.dwellTimeKey: 1,
36+
GeofencingPropertiesKeys.pointRadiusKey: .number(_region.radius)
37+
])
38+
geofencing.add(feature: feature) {
39+
region = _region
40+
}
3241
}
3342
}
3443
}
3544
}
3645

46+
private struct CircularRegion {
47+
let center: Turf.Point
48+
let radius: CLLocationDistance
49+
}
50+
3751
private struct GeofenceCircle: MapStyleContent {
3852
var id: String
39-
var location: CLLocationCoordinate2D
53+
var region: CircularRegion
4054
var event: GeofenceEvent?
4155

4256
var body: some MapStyleContent {
4357
GeoJSONSource(id: "geofence-source-\(id)")
44-
.data(.geofenceCircle(location))
58+
.data(.geometry(Polygon(center: region.center.coordinates, radius: region.radius, vertices: 64).geometry))
4559

4660
FillLayer(id: "geofence-layer-\(id)", source: "geofence-source-\(id)")
4761
.fillColor(color(for: event))
@@ -62,6 +76,30 @@ private struct GeofenceCircle: MapStyleContent {
6276
}
6377
}
6478

79+
private struct PermissionView: View {
80+
var body: some View {
81+
HStack {
82+
OvalButton(title: "Enable Pushes") {
83+
Task {
84+
// Request notifications (alert, badge) once via async/await.
85+
do {
86+
let granted = try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge])
87+
print("Notification permission request finished. Granted: \(granted)")
88+
} catch {
89+
print("Notification permission request failed with error: \(error)")
90+
}
91+
}
92+
}
93+
#if !os(visionOS)
94+
OvalButton(title: "Enable Location") {
95+
CLLocationManager().requestAlwaysAuthorization()
96+
}
97+
#endif
98+
}
99+
.padding(30)
100+
}
101+
}
102+
65103
private final class InitialLocationProvider {
66104
private var cancellables = Set<AnyCancelable>()
67105

@@ -138,15 +176,3 @@ private struct GeofenceEvent {
138176
var type: GeofenceEventType
139177
var feature: Turf.Feature
140178
}
141-
142-
private extension GeoJSONSourceData {
143-
static func geofenceCircle(_ center: LocationCoordinate2D) -> GeoJSONSourceData {
144-
.geometry(.geofenceCircle(center))
145-
}
146-
}
147-
148-
private extension Turf.Geometry {
149-
static func geofenceCircle(_ center: LocationCoordinate2D) -> Turf.Geometry {
150-
.polygon(Polygon(center: center, radius: 30, vertices: 64))
151-
}
152-
}

0 commit comments

Comments
 (0)