Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0d463d1
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
9c56409
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
c2874c3
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
ed9a106
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
56cdd84
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
8119da9
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 21, 2025
dd25a7d
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 22, 2025
bfbb0a5
fix(ios): implement new timeout logic for getCurrentPosition and watc…
OS-ruimoreiramendes Oct 22, 2025
44e4878
fix(ios): update plugin version 7.1.5-dev.2
OS-ruimoreiramendes Oct 22, 2025
73a11f0
fix(ios): remove empty spaces
OS-ruimoreiramendes Oct 22, 2025
a54221d
fix(ios): update native lib files
OS-ruimoreiramendes Oct 27, 2025
b15174e
fix(ios): update requestSingleLocation and startMonitoringLocation
OS-ruimoreiramendes Oct 27, 2025
dd83b52
fix(ios): added new native lib
OS-ruimoreiramendes Oct 28, 2025
818a8d0
Chore(iOS): update native library IONGeolocationLib to version 2.0.0
OS-ruimoreiramendes Oct 29, 2025
3e8a2ed
fix(ios): resolve conflicts
OS-ruimoreiramendes Oct 29, 2025
52be7a8
chore: clean gradle
OS-ruimoreiramendes Oct 29, 2025
597af24
chore: clean gradle
OS-ruimoreiramendes Oct 29, 2025
e49c797
fix(ios): remove release notes
OS-ruimoreiramendes Oct 29, 2025
0e20bc1
fix(ios): update README file
OS-ruimoreiramendes Oct 30, 2025
e369ccd
fix(ios): add timeout to Constants.Arguments
OS-ruimoreiramendes Oct 30, 2025
e27045b
fix(ios): manage timeout in CallbackManager
OS-ruimoreiramendes Oct 30, 2025
ae1bcf4
fix(ios): version 7.1.5-dev.7
OS-ruimoreiramendes Oct 30, 2025
88902a7
fix(ios): manage timeout in CallbackManager
OS-ruimoreiramendes Oct 30, 2025
2f621fb
fix(ios): added timeout implementation for both getCurrentPosition an…
OS-ruimoreiramendes Oct 30, 2025
b14deb0
fix(ios): remove timeout var
OS-ruimoreiramendes Oct 30, 2025
6f151c5
fix(ios): remove watch callbacks when timeout triggers
OS-ruimoreiramendes Oct 31, 2025
18fff23
fix(ios): remove watch callbacks when timeout triggers
OS-ruimoreiramendes Oct 31, 2025
3583623
fix(ios): fix lock files
OS-ruimoreiramendes Nov 3, 2025
1746507
fix(ios): fix lock files
OS-ruimoreiramendes Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ The following table list all the plugin errors:
| OS-PLUG-GLOC-0007 | Android, iOS | Location services are not enabled. |
| OS-PLUG-GLOC-0008 | iOS | Application's use of location services was restricted. |
| OS-PLUG-GLOC-0009 | Android | Request to enable location was denied. |
| OS-PLUG-GLOC-0010 | Android | Could not obtain location in time. Try with a higher timeout. |
| OS-PLUG-GLOC-0010 | Android, iOS | Could not obtain location in time. Try with a higher timeout. |
| OS-PLUG-GLOC-0011 | Android | Timeout needs to be a positive value. |
| OS-PLUG-GLOC-0012 | Android | WatchId not found. |
| OS-PLUG-GLOC-0013 | Android | WatchId needs to be provided. |
Expand Down
39 changes: 0 additions & 39 deletions package-lock.json

This file was deleted.

Binary file modified packages/.DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/capacitor-plugin/CapacitorGeolocation.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ Pod::Spec.new do |s|
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
s.ios.deployment_target = '15.0'
s.dependency 'Capacitor'
s.dependency 'IONGeolocationLib', spec='1.0.1'
s.dependency 'IONGeolocationLib', spec='2.0.0'
s.swift_version = '5.1'
end
2 changes: 1 addition & 1 deletion packages/capacitor-plugin/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0"),
.package(url: "https://github.com/ionic-team/ion-ios-geolocation.git", from: "1.0.2")
.package(url: "https://github.com/ionic-team/ion-ios-geolocation.git", from: "2.0.0")
],
targets: [
.target(
Expand Down
2 changes: 1 addition & 1 deletion packages/capacitor-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ The following table list all the plugin errors:
| OS-PLUG-GLOC-0007 | Android, iOS | Location services are not enabled. |
| OS-PLUG-GLOC-0008 | iOS | Application's use of location services was restricted. |
| OS-PLUG-GLOC-0009 | Android | Request to enable location was denied. |
| OS-PLUG-GLOC-0010 | Android | Could not obtain location in time. Try with a higher timeout. |
| OS-PLUG-GLOC-0010 | Android, iOS | Could not obtain location in time. Try with a higher timeout. |
| OS-PLUG-GLOC-0011 | Android | Timeout needs to be a positive value. |
| OS-PLUG-GLOC-0012 | Android | WatchId not found. |
| OS-PLUG-GLOC-0013 | Android | WatchId needs to be provided. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class GeolocationCallbackManager {
private(set) var requestPermissionsCallbacks: [CAPPluginCall]
private(set) var locationCallbacks: [CAPPluginCall]
private(set) var watchCallbacks: [String: CAPPluginCall]
private(set) var timeout: Int?
private let capacitorBridge: CAPBridgeProtocol?

private var allCallbackGroups: [GeolocationCallbackGroup] {
Expand Down Expand Up @@ -52,11 +53,15 @@ final class GeolocationCallbackManager {
func addLocationCallback(capacitorCall call: CAPPluginCall) {
capacitorBridge?.saveCall(call)
locationCallbacks.append(call)
let timeout = call.getInt(Constants.Arguments.timeout)
self.timeout = timeout
}

func addWatchCallback(_ watchId: String, capacitorCall call: CAPPluginCall) {
capacitorBridge?.saveCall(call)
watchCallbacks[watchId] = call
let timeout = call.getInt(Constants.Arguments.timeout)
self.timeout = timeout
}

func clearRequestPermissionsCallbacks() {
Expand Down Expand Up @@ -109,6 +114,10 @@ final class GeolocationCallbackManager {

func sendError(_ error: GeolocationError) {
createPluginResult(status: .error(error.toCodeMessagePair()))

if case .timeout = error {
watchCallbacks.keys.forEach { clearWatchCallbackIfExists($0) }
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ enum Constants {
enum Arguments {
static let enableHighAccuracy = "enableHighAccuracy"
static let id = "id"
static let timeout = "timeout"
}

enum AuthorisationStatus {
Expand Down
Copy link
Contributor

@OS-pedrogustavobilro OS-pedrogustavobilro Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing I'm observing this behavior in the example app in this repo:

  1. I receive a timeout in watchPosition (right now by setting a timeout of 1ms)
  2. I try a get current position with timeout of 1ms. I receive two timeout errors - I believe 1 for this request and one for watch.
  3. I increase the timeout and call get current position. I start receiving locations in the watch.

All this leads me to believe that perhaps there needs to be logic in place to remove the watch callbacks in case of timeout error? Or to generalize the question: Which GeolocationError's are recoverable for a watch and which are not? I think the code assumes right now that all are, and that's not necessarily the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, let me take look.
I'll try to replicate it and see if the issue is related to the watch callbacks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With your change now, I'm having this issue: I have a watch in progress, and I trigger a second one (or a get current position) that times out, it also stops receiving updates for the first one.

This and the previous issue are all tied to the fact that timeouts are not specific to one single watch or location request.

Copy link
Contributor Author

@OS-ruimoreiramendes OS-ruimoreiramendes Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve have figured out the cause in onLocationPermissionGranted()

let shouldRequestCurrentPosition = callbackManager?.locationCallbacks.isEmpty == false
let shouldRequestLocationMonitoring = callbackManager?.watchCallbacks.isEmpty == false

When a watch is already active and a getCurrentPosition is triggered, both flags are true. The current position itself doesn’t time out because we return the last known location from the watch.
However, startMonitoringLocation is also called again due to shouldRequestLocationMonitoring being true, which starts a new timer.

This issue existed before the current changes, so it will not be addressed in this PR.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum GeolocationError: Error {
case permissionRestricted
case positionUnavailable
case inputArgumentsIssue(target: GeolocationMethod)
case timeout

func toCodeMessagePair() -> (String, String) {
("OS-PLUG-GLOC-\(String(format: "%04d", code))", description)
Expand All @@ -29,16 +30,18 @@ private extension GeolocationError {
case .watchPosition: 5
case .clearWatch: 6
}
case .timeout: 10
}
}

var description: String {
switch self {
case .positionUnavailable: "There was en error trying to obtain the location."
case .positionUnavailable: "There was an error trying to obtain the location."
case .permissionDenied: "Location permission request was denied."
case .locationServicesDisabled: "Location services are not enabled."
case .permissionRestricted: "Application's use of location services was restricted."
case .inputArgumentsIssue(let target): "The '\(target.rawValue)' input parameters aren't valid."
case .timeout: "Could not obtain location in time. Try with a higher timeout."
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Capacitor
import IONGeolocationLib
import UIKit

import Combine

@objc(GeolocationPlugin)
Expand All @@ -19,14 +18,15 @@ public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
private var locationService: (any IONGLOCService)?
private var cancellables = Set<AnyCancellable>()
private var locationCancellable: AnyCancellable?
private var timeoutCancellable: AnyCancellable?
private var callbackManager: GeolocationCallbackManager?
private var statusInitialized = false
private var locationInitialized: Bool = false

override public func load() {
self.locationService = IONGLOCManagerWrapper()
self.callbackManager = .init(capacitorBridge: bridge)

NotificationCenter.default.addObserver(
self,
selector: #selector(appDidBecomeActive),
Expand All @@ -40,8 +40,10 @@ public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
print("App became active. Restarting location monitoring for watch callbacks.")
locationCancellable?.cancel()
locationCancellable = nil
timeoutCancellable?.cancel()
timeoutCancellable = nil
locationInitialized = false

locationService?.stopMonitoringLocation()
locationService?.startMonitoringLocation()
bindLocationPublisher()
Expand Down Expand Up @@ -77,6 +79,8 @@ public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
locationService?.stopMonitoringLocation()
locationCancellable?.cancel()
locationCancellable = nil
timeoutCancellable?.cancel()
timeoutCancellable = nil
locationInitialized = false
}

Expand Down Expand Up @@ -145,7 +149,7 @@ private extension GeolocationPlugin {
locationCancellable = locationService?.currentLocationPublisher
.catch { [weak self] error -> AnyPublisher<IONGLOCPositionModel, Never> in
print("An error was found while retrieving the location: \(error)")

if case IONGLOCLocationError.locationUnavailable = error {
print("Location unavailable (likely due to backgrounding). Keeping watch callbacks alive.")
self?.callbackManager?.sendError(.positionUnavailable)
Expand All @@ -160,6 +164,15 @@ private extension GeolocationPlugin {
.sink(receiveValue: { [weak self] position in
self?.callbackManager?.sendSuccess(with: position)
})

timeoutCancellable = locationService?.locationTimeoutPublisher
.sink(receiveValue: { [weak self] error in
if case .timeout = error {
self?.callbackManager?.sendError(.timeout)
} else {
self?.callbackManager?.sendError(.positionUnavailable)
}
})
}

func requestLocationAuthorisation(type requestType: IONGLOCAuthorisationRequestType) {
Expand Down Expand Up @@ -200,10 +213,10 @@ private extension GeolocationPlugin {
callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.granted)
}
if shouldRequestCurrentPosition {
locationService?.requestSingleLocation()
locationService?.requestSingleLocation(options: IONGLOCRequestOptionsModel(timeout: callbackManager?.timeout))
}
if shouldRequestLocationMonitoring {
locationService?.startMonitoringLocation()
locationService?.startMonitoringLocation(options: IONGLOCRequestOptionsModel(timeout: callbackManager?.timeout))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/android/capacitor')
project(':capacitor-android').projectDir = new File('../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/android/capacitor')

include ':capacitor-camera'
project(':capacitor-camera').projectDir = new File('../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/camera/android')
project(':capacitor-camera').projectDir = new File('../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/camera/android')

include ':capacitor-splash-screen'
project(':capacitor-splash-screen').projectDir = new File('../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/splash-screen/android')
project(':capacitor-splash-screen').projectDir = new File('../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/splash-screen/android')

include ':capacitor-geolocation'
project(':capacitor-geolocation').projectDir = new File('../../capacitor-plugin/android')
10 changes: 5 additions & 5 deletions packages/example-app-capacitor/ios/App/Podfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require_relative '../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios/scripts/pods_helpers'
require_relative '../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios/scripts/pods_helpers'

platform :ios, '15.0'
use_frameworks!
Expand All @@ -9,10 +9,10 @@ use_frameworks!
install! 'cocoapods', :disable_input_output_paths => true

def capacitor_pods
pod 'Capacitor', :path => '../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios'
pod 'CapacitorCamera', :path => '../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/camera'
pod 'CapacitorSplashScreen', :path => '../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/splash-screen'
pod 'Capacitor', :path => '../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios'
pod 'CapacitorCamera', :path => '../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/camera'
pod 'CapacitorSplashScreen', :path => '../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/splash-screen'
pod 'CapacitorGeolocation', :path => '../../../capacitor-plugin'
end

Expand Down
36 changes: 18 additions & 18 deletions packages/example-app-capacitor/ios/App/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
PODS:
- Capacitor (8.0.0-alpha.2):
- Capacitor (8.0.0-alpha.3):
- CapacitorCordova
- CapacitorCamera (8.0.0-alpha.1):
- Capacitor
- CapacitorCordova (8.0.0-alpha.2)
- CapacitorGeolocation (8.0.0-next.2):
- CapacitorCordova (8.0.0-alpha.3)
- CapacitorGeolocation (8.0.0-next.3):
- Capacitor
- IONGeolocationLib (= 1.0.1)
- IONGeolocationLib (= 2.0.0)
- CapacitorSplashScreen (8.0.0-alpha.1):
- Capacitor
- IONGeolocationLib (1.0.1)
- IONGeolocationLib (2.0.0)

DEPENDENCIES:
- "Capacitor (from `../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios`)"
- "CapacitorCamera (from `../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/camera`)"
- "CapacitorCordova (from `../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios`)"
- "Capacitor (from `../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios`)"
- "CapacitorCamera (from `../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/camera`)"
- "CapacitorCordova (from `../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios`)"
- CapacitorGeolocation (from `../../../capacitor-plugin`)
- "CapacitorSplashScreen (from `../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/splash-screen`)"
- "CapacitorSplashScreen (from `../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/splash-screen`)"

SPEC REPOS:
trunk:
- IONGeolocationLib

EXTERNAL SOURCES:
Capacitor:
:path: "../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios"
:path: "../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios"
CapacitorCamera:
:path: "../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/camera"
:path: "../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/camera"
CapacitorCordova:
:path: "../../../../node_modules/.pnpm/@[email protected].2_@[email protected].2/node_modules/@capacitor/ios"
:path: "../../../../node_modules/.pnpm/@[email protected].3_@[email protected].3/node_modules/@capacitor/ios"
CapacitorGeolocation:
:path: "../../../capacitor-plugin"
CapacitorSplashScreen:
:path: "../../../../node_modules/.pnpm/@[email protected]_@[email protected].2/node_modules/@capacitor/splash-screen"
:path: "../../../../node_modules/.pnpm/@[email protected]_@[email protected].3/node_modules/@capacitor/splash-screen"

SPEC CHECKSUMS:
Capacitor: f88db94b173c6d2c97003248197f749674d42dc8
Capacitor: 91ac12cf2ebfb294c72ad1f7e5b71103a9af6254
CapacitorCamera: f072b76519f1a5981becb6caa3ab10c79622ae66
CapacitorCordova: 9b60d7dd7f5035cefe9b5f7f3edf11ccd93b6ae6
CapacitorGeolocation: ed8dbf1b8b4f3bc415c1407333199c383cefa960
CapacitorCordova: beaf46c43cfd3d28e09c2a8bfcb40d8387e6dd8a
CapacitorGeolocation: a7b46178fece0f49a7f856e9a678f02adb40d347
CapacitorSplashScreen: 6a9a07f9b1313faad49dde7bb8f12b7c4fcc3acf
IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a
IONGeolocationLib: a5e40b54edc2ee9902036eda5aaa41ddf07bb68d

PODFILE CHECKSUM: 4965d688d87bbc9772caec9b620016902fb41d32
PODFILE CHECKSUM: 9f3aa02b123df21b0390efa217179df8854cdaff

COCOAPODS: 1.16.2
Loading
Loading