Skip to content

Commit 978bd50

Browse files
authored
fix(ios): handle location watch callbacks recovery after backgrounding
1 parent 77ebe80 commit 978bd50

1 file changed

Lines changed: 43 additions & 8 deletions

File tree

packages/capacitor-plugin/ios/Sources/GeolocationPlugin/GeolocationPlugin.swift

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Capacitor
22
import IONGeolocationLib
3+
import UIKit
34

45
import Combine
56

@@ -17,13 +18,38 @@ public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
1718

1819
private var locationService: (any IONGLOCService)?
1920
private var cancellables = Set<AnyCancellable>()
21+
private var locationCancellable: AnyCancellable?
2022
private var callbackManager: GeolocationCallbackManager?
2123
private var statusInitialized = false
2224
private var locationInitialized: Bool = false
2325

2426
override public func load() {
2527
self.locationService = IONGLOCManagerWrapper()
2628
self.callbackManager = .init(capacitorBridge: bridge)
29+
30+
NotificationCenter.default.addObserver(
31+
self,
32+
selector: #selector(appDidBecomeActive),
33+
name: UIApplication.didBecomeActiveNotification,
34+
object: nil
35+
)
36+
}
37+
38+
@objc private func appDidBecomeActive() {
39+
if let watchCallbacksEmpty = callbackManager?.watchCallbacks.isEmpty, !watchCallbacksEmpty {
40+
print("App became active. Restarting location monitoring for watch callbacks.")
41+
locationCancellable?.cancel()
42+
locationCancellable = nil
43+
locationInitialized = false
44+
45+
locationService?.stopMonitoringLocation()
46+
locationService?.startMonitoringLocation()
47+
bindLocationPublisher()
48+
}
49+
}
50+
51+
deinit {
52+
NotificationCenter.default.removeObserver(self)
2753
}
2854

2955
@objc func getCurrentPosition(_ call: CAPPluginCall) {
@@ -49,6 +75,9 @@ public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
4975

5076
if (callbackManager?.watchCallbacks.isEmpty) ?? false {
5177
locationService?.stopMonitoringLocation()
78+
locationCancellable?.cancel()
79+
locationCancellable = nil
80+
locationInitialized = false
5281
}
5382

5483
callbackManager?.sendSuccess(call)
@@ -113,18 +142,24 @@ private extension GeolocationPlugin {
113142
func bindLocationPublisher() {
114143
guard !locationInitialized else { return }
115144
locationInitialized = true
116-
locationService?.currentLocationPublisher
117-
.sink(receiveCompletion: { [weak self] completion in
118-
if case .failure(let error) = completion {
119-
// publisher should be re-observed in the next plugin call
120-
self?.locationInitialized = false
121-
print("An error was found while retrieving the location: \(error)")
145+
locationCancellable = locationService?.currentLocationPublisher
146+
.catch { [weak self] error -> AnyPublisher<IONGLOCPositionModel, Never> in
147+
print("An error was found while retrieving the location: \(error)")
148+
149+
if case IONGLOCLocationError.locationUnavailable = error {
150+
print("Location unavailable (likely due to backgrounding). Keeping watch callbacks alive.")
122151
self?.callbackManager?.sendError(.positionUnavailable)
152+
return Empty<IONGLOCPositionModel, Never>()
153+
.eraseToAnyPublisher()
154+
} else {
155+
self?.callbackManager?.sendError(.positionUnavailable)
156+
return Empty<IONGLOCPositionModel, Never>()
157+
.eraseToAnyPublisher()
123158
}
124-
}, receiveValue: { [weak self] position in
159+
}
160+
.sink(receiveValue: { [weak self] position in
125161
self?.callbackManager?.sendSuccess(with: position)
126162
})
127-
.store(in: &cancellables)
128163
}
129164

130165
func requestLocationAuthorisation(type requestType: IONGLOCAuthorisationRequestType) {

0 commit comments

Comments
 (0)