Skip to content

Commit 8189ccc

Browse files
feat(ios): add location permission row and enable background updates
- Add Location row to Privacy & Access section showing current OS authorization (Always / While Using / Not Set / Not Allowed) with an action button to upgrade or open Settings - Enable allowsBackgroundLocationUpdates on the CLLocationManager when starting significant-change monitoring so the system delivers location events after the app is suspended - Treat "While Using" as a warning tone in the permission UI to nudge users toward Always for reliable automations Co-authored-by: Cursor <[email protected]>
1 parent bb03d00 commit 8189ccc

2 files changed

Lines changed: 48 additions & 4 deletions

File tree

apps/ios/Sources/Location/LocationService.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ final class LocationService: NSObject, CLLocationManagerDelegate, LocationServic
8686
self.significantLocationCallback = onUpdate
8787
guard !self.isMonitoringSignificantChanges else { return }
8888
self.isMonitoringSignificantChanges = true
89+
// Required when UIBackgroundModes includes "location" so the
90+
// system delivers updates after the app is suspended.
91+
self.manager.allowsBackgroundLocationUpdates = true
8992
self.manager.startMonitoringSignificantLocationChanges()
9093
}
9194

apps/ios/Sources/Settings/PrivacyAccessSectionView.swift

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Contacts
2+
import CoreLocation
23
import EventKit
34
import SwiftUI
45
import UIKit
@@ -7,11 +8,20 @@ struct PrivacyAccessSectionView: View {
78
@State private var contactsStatus: CNAuthorizationStatus = CNContactStore.authorizationStatus(for: .contacts)
89
@State private var calendarStatus: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: .event)
910
@State private var remindersStatus: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: .reminder)
11+
@State private var locationStatus: CLAuthorizationStatus = CLLocationManager().authorizationStatus
1012

1113
@Environment(\.scenePhase) private var scenePhase
1214

1315
var body: some View {
1416
DisclosureGroup("Privacy & Access") {
17+
self.permissionRow(
18+
title: "Location",
19+
icon: "location",
20+
status: self.locationStatusText,
21+
detail: "Share location with gateway tools and automations.",
22+
actionTitle: self.locationActionTitle,
23+
action: self.handleLocationAction)
24+
1525
self.permissionRow(
1626
title: "Contacts",
1727
icon: "person.crop.circle",
@@ -78,13 +88,43 @@ struct PrivacyAccessSectionView: View {
7888
.padding(.vertical, 2)
7989
}
8090

91+
private var locationStatusText: String {
92+
switch self.locationStatus {
93+
case .authorizedAlways:
94+
"Always"
95+
case .authorizedWhenInUse:
96+
"While Using"
97+
case .notDetermined:
98+
"Not Set"
99+
case .denied, .restricted:
100+
"Not Allowed"
101+
@unknown default:
102+
"Unknown"
103+
}
104+
}
105+
106+
private var locationActionTitle: String? {
107+
switch self.locationStatus {
108+
case .authorizedAlways:
109+
nil
110+
case .authorizedWhenInUse:
111+
"Upgrade to Always"
112+
case .notDetermined, .denied, .restricted:
113+
"Open Settings"
114+
@unknown default:
115+
nil
116+
}
117+
}
118+
119+
private func handleLocationAction() {
120+
self.openSettings()
121+
}
122+
81123
private func statusTone(for status: String) -> OpenClawStatusTone {
82124
switch status {
83-
case "Allowed":
125+
case "Allowed", "Always":
84126
.ok
85-
case "Not Set":
86-
.warn
87-
case "Add-Only":
127+
case "Not Set", "Add-Only", "While Using":
88128
.warn
89129
default:
90130
.danger
@@ -280,6 +320,7 @@ struct PrivacyAccessSectionView: View {
280320
self.contactsStatus = CNContactStore.authorizationStatus(for: .contacts)
281321
self.calendarStatus = EKEventStore.authorizationStatus(for: .event)
282322
self.remindersStatus = EKEventStore.authorizationStatus(for: .reminder)
323+
self.locationStatus = CLLocationManager().authorizationStatus
283324
}
284325

285326
private func requestCalendarWriteOnly() async -> Bool {

0 commit comments

Comments
 (0)