From a14de9ff81a01994455c93ec5570fb2cb7d041f9 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 15:58:02 +0100 Subject: [PATCH 1/4] feat(android): Fallback option for no network or Play Services --- README.md | 13 ++++++----- packages/capacitor-plugin/README.md | 13 ++++++----- .../capacitor-plugin/android/build.gradle | 2 +- .../plugins/geolocation/GeolocationErrors.kt | 5 +++++ .../plugins/geolocation/GeolocationPlugin.kt | 22 ++++++++++++------- packages/capacitor-plugin/src/definitions.ts | 15 +++++++++++++ 6 files changed, 49 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index bd6ab92..24402ab 100644 --- a/README.md +++ b/README.md @@ -167,12 +167,13 @@ Not available on web. #### PositionOptions -| Prop | Type | Description | Default | Since | -| --------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | -| **`enableHighAccuracy`** | boolean | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | false | 1.0.0 | -| **`timeout`** | number | The maximum wait time in milliseconds for location updates. In Android, since version 7.1.0 of the plugin, it is also used to determine the interval of location updates for `watchPosition`. | 10000 | 1.0.0 | -| **`maximumAge`** | number | The maximum age in milliseconds of a possible cached position that is acceptable to return | 0 | 1.0.0 | -| **`minimumUpdateInterval`** | number | The minumum update interval for location updates. If location updates are available faster than this interval then an update will only occur if the minimum update interval has expired since the last location update. This parameter is only available for Android. It has no effect on iOS or Web platforms. | 5000 | 6.1.0 | +| Prop | Type | Description | Default | Since | +| ---------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----- | +| **`enableHighAccuracy`** | boolean | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | false | 1.0.0 | +| **`timeout`** | number | The maximum wait time in milliseconds for location updates. In Android, since version 7.1.0 of the plugin, it is also used to determine the interval of location updates for `watchPosition`. | 10000 | 1.0.0 | +| **`maximumAge`** | number | The maximum age in milliseconds of a possible cached position that is acceptable to return | 0 | 1.0.0 | +| **`minimumUpdateInterval`** | number | The minumum update interval for location updates. If location updates are available faster than this interval then an update will only occur if the minimum update interval has expired since the last location update. This parameter is only available for Android. It has no effect on iOS or Web platforms. | 5000 | 6.1.0 | +| **`enableLocationFallback`** | boolean | This option applies to Android only. Whether to fall back to the Android framework's `LocationManager` in case Google Play Service's location settings checks fail. This can happen for multiple reasons - e.g. device has no Play Services or device has no network connection (Airplane Mode) If set to `false`, failures are propagated to the caller. Note that `LocationManager` may not be as effective as Google Play Services implementation. If the device's in airplane mode, only the GPS provider is used, which may take longer to return a location, depending on GPS signal. This means that to receive location in such circumstances, you may need to provide a higher timeout. | true | 8.0.0 | #### ClearWatchOptions diff --git a/packages/capacitor-plugin/README.md b/packages/capacitor-plugin/README.md index bd6ab92..24402ab 100644 --- a/packages/capacitor-plugin/README.md +++ b/packages/capacitor-plugin/README.md @@ -167,12 +167,13 @@ Not available on web. #### PositionOptions -| Prop | Type | Description | Default | Since | -| --------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- | -| **`enableHighAccuracy`** | boolean | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | false | 1.0.0 | -| **`timeout`** | number | The maximum wait time in milliseconds for location updates. In Android, since version 7.1.0 of the plugin, it is also used to determine the interval of location updates for `watchPosition`. | 10000 | 1.0.0 | -| **`maximumAge`** | number | The maximum age in milliseconds of a possible cached position that is acceptable to return | 0 | 1.0.0 | -| **`minimumUpdateInterval`** | number | The minumum update interval for location updates. If location updates are available faster than this interval then an update will only occur if the minimum update interval has expired since the last location update. This parameter is only available for Android. It has no effect on iOS or Web platforms. | 5000 | 6.1.0 | +| Prop | Type | Description | Default | Since | +| ---------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----- | +| **`enableHighAccuracy`** | boolean | High accuracy mode (such as GPS, if available) On Android 12+ devices it will be ignored if users didn't grant ACCESS_FINE_LOCATION permissions (can be checked with location alias). | false | 1.0.0 | +| **`timeout`** | number | The maximum wait time in milliseconds for location updates. In Android, since version 7.1.0 of the plugin, it is also used to determine the interval of location updates for `watchPosition`. | 10000 | 1.0.0 | +| **`maximumAge`** | number | The maximum age in milliseconds of a possible cached position that is acceptable to return | 0 | 1.0.0 | +| **`minimumUpdateInterval`** | number | The minumum update interval for location updates. If location updates are available faster than this interval then an update will only occur if the minimum update interval has expired since the last location update. This parameter is only available for Android. It has no effect on iOS or Web platforms. | 5000 | 6.1.0 | +| **`enableLocationFallback`** | boolean | This option applies to Android only. Whether to fall back to the Android framework's `LocationManager` in case Google Play Service's location settings checks fail. This can happen for multiple reasons - e.g. device has no Play Services or device has no network connection (Airplane Mode) If set to `false`, failures are propagated to the caller. Note that `LocationManager` may not be as effective as Google Play Services implementation. If the device's in airplane mode, only the GPS provider is used, which may take longer to return a location, depending on GPS signal. This means that to receive location in such circumstances, you may need to provide a higher timeout. | true | 8.0.0 | #### ClearWatchOptions diff --git a/packages/capacitor-plugin/android/build.gradle b/packages/capacitor-plugin/android/build.gradle index 5a03599..4da4902 100644 --- a/packages/capacitor-plugin/android/build.gradle +++ b/packages/capacitor-plugin/android/build.gradle @@ -58,7 +58,7 @@ repositories { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation("io.ionic.libs:iongeolocation-android:1.0.0") + implementation("io.ionic.libs:iongeolocation-android:2.0.0") implementation project(':capacitor-android') implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" diff --git a/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt b/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt index 23532ab..7a606c6 100644 --- a/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt +++ b/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt @@ -68,4 +68,9 @@ object GeolocationErrors { code = formatErrorCode(16), message = "Location settings error." ) + + val NETWORK_LOCATION_DISABLED_ERROR = ErrorInfo( + code = formatErrorCode(17), + message = "Unable to retrieve location because device has both Network and Location turned off." + ) } \ No newline at end of file diff --git a/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt b/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt index 5a21393..9be4186 100644 --- a/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt +++ b/packages/capacitor-plugin/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt @@ -54,11 +54,7 @@ class GeolocationPlugin : Plugin() { } } - this.controller = IONGLOCController( - LocationServices.getFusedLocationProviderClient(context), - activityLauncher - ) - + this.controller = IONGLOCController(context, activityLauncher) } override fun handleOnDestroy() { @@ -82,7 +78,7 @@ class GeolocationPlugin : Plugin() { * @param onLocationEnabled lambda function to use in case location services are enabled */ private fun checkLocationState(call: PluginCall, onLocationEnabled: () -> Unit) { - if (controller.areLocationServicesEnabled(context)) { + if (controller.areLocationServicesEnabled()) { onLocationEnabled() } else { call.sendError(GeolocationErrors.LOCATION_DISABLED) @@ -279,6 +275,9 @@ class GeolocationPlugin : Plugin() { is IONGLOCException.IONGLOCSettingsException -> { call.sendError(GeolocationErrors.LOCATION_SETTINGS_ERROR) } + is IONGLOCException.IONGLOCLocationAndNetworkDisabledException -> { + call.sendError(GeolocationErrors.NETWORK_LOCATION_DISABLED_ERROR) + } is IONGLOCException.IONGLOCInvalidTimeoutException -> { call.sendError(GeolocationErrors.INVALID_TIMEOUT) } @@ -330,8 +329,15 @@ class GeolocationPlugin : Plugin() { val maximumAge = call.getNumber("maximumAge", 0) val enableHighAccuracy = call.getBoolean("enableHighAccuracy", false) ?: false val minimumUpdateInterval = call.getNumber("minimumUpdateInterval", 5000) - - val locationOptions = IONGLOCLocationOptions(timeout, maximumAge, enableHighAccuracy, minimumUpdateInterval) + val enableLocationFallback = call.getBoolean("enableLocationFallback", true) ?: true + + val locationOptions = IONGLOCLocationOptions( + timeout, + maximumAge, + enableHighAccuracy, + enableLocationFallback, + minimumUpdateInterval + ) return locationOptions } diff --git a/packages/capacitor-plugin/src/definitions.ts b/packages/capacitor-plugin/src/definitions.ts index 93d3a4c..6cfb5af 100644 --- a/packages/capacitor-plugin/src/definitions.ts +++ b/packages/capacitor-plugin/src/definitions.ts @@ -191,6 +191,21 @@ export interface PositionOptions { * @since 6.1.0 */ minimumUpdateInterval?: number; + + /** + * This option applies to Android only. + * + * Whether to fall back to the Android framework's `LocationManager` in case Google Play Service's location settings checks fail. + * This can happen for multiple reasons - e.g. device has no Play Services or device has no network connection (Airplane Mode) + * If set to `false`, failures are propagated to the caller. + * Note that `LocationManager` may not be as effective as Google Play Services implementation. + * If the device's in airplane mode, only the GPS provider is used, which may take longer to return a location, depending on GPS signal. + * This means that to receive location in such circumstances, you may need to provide a higher timeout. + * + * @default true + * @since 8.0.0 + */ + enableLocationFallback?: boolean } export type WatchPositionCallback = (position: Position | null, err?: any) => void; From 55c1438482f1a0a420eed4b14312f2684540ea28 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 16:10:10 +0100 Subject: [PATCH 2/4] docs: Add additional error code --- README.md | 1 + packages/capacitor-plugin/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 24402ab..47e8966 100644 --- a/README.md +++ b/README.md @@ -245,3 +245,4 @@ The following table list all the plugin errors: | OS-PLUG-GLOC-0014 | Android | Google Play Services error user resolvable. | | OS-PLUG-GLOC-0015 | Android | Google Play Services error. | | OS-PLUG-GLOC-0016 | Android | Location settings error. | +| OS-PLUG-GLOC-0017 | Android | Unable to retrieve location because device has both Network and Location turned off. | diff --git a/packages/capacitor-plugin/README.md b/packages/capacitor-plugin/README.md index 24402ab..47e8966 100644 --- a/packages/capacitor-plugin/README.md +++ b/packages/capacitor-plugin/README.md @@ -245,3 +245,4 @@ The following table list all the plugin errors: | OS-PLUG-GLOC-0014 | Android | Google Play Services error user resolvable. | | OS-PLUG-GLOC-0015 | Android | Google Play Services error. | | OS-PLUG-GLOC-0016 | Android | Location settings error. | +| OS-PLUG-GLOC-0017 | Android | Unable to retrieve location because device has both Network and Location turned off. | From 80de562d48109ab954cb95774c262a317fb4bd56 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 16:26:50 +0100 Subject: [PATCH 3/4] chore: update example app --- packages/example-app-capacitor/ios/App/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/example-app-capacitor/ios/App/Podfile.lock b/packages/example-app-capacitor/ios/App/Podfile.lock index f992c1b..ae5e7c0 100644 --- a/packages/example-app-capacitor/ios/App/Podfile.lock +++ b/packages/example-app-capacitor/ios/App/Podfile.lock @@ -4,7 +4,7 @@ PODS: - CapacitorCamera (8.0.0-alpha.1): - Capacitor - CapacitorCordova (8.0.0-alpha.2) - - CapacitorGeolocation (7.1.5): + - CapacitorGeolocation (8.0.0-next.2): - Capacitor - IONGeolocationLib (= 1.0.1) - CapacitorSplashScreen (8.0.0-alpha.1): @@ -38,7 +38,7 @@ SPEC CHECKSUMS: Capacitor: f88db94b173c6d2c97003248197f749674d42dc8 CapacitorCamera: f072b76519f1a5981becb6caa3ab10c79622ae66 CapacitorCordova: 9b60d7dd7f5035cefe9b5f7f3edf11ccd93b6ae6 - CapacitorGeolocation: ea967ba560d9e9fd721ea588e9667203a6b1b67c + CapacitorGeolocation: ed8dbf1b8b4f3bc415c1407333199c383cefa960 CapacitorSplashScreen: 6a9a07f9b1313faad49dde7bb8f12b7c4fcc3acf IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a From 9ade03f9e506a01e5ed2030bef8b31b54407a5f0 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 16:52:38 +0100 Subject: [PATCH 4/4] chore: fix lint issues --- packages/capacitor-plugin/src/definitions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/capacitor-plugin/src/definitions.ts b/packages/capacitor-plugin/src/definitions.ts index 6cfb5af..3a50c50 100644 --- a/packages/capacitor-plugin/src/definitions.ts +++ b/packages/capacitor-plugin/src/definitions.ts @@ -194,18 +194,18 @@ export interface PositionOptions { /** * This option applies to Android only. - * + * * Whether to fall back to the Android framework's `LocationManager` in case Google Play Service's location settings checks fail. * This can happen for multiple reasons - e.g. device has no Play Services or device has no network connection (Airplane Mode) * If set to `false`, failures are propagated to the caller. * Note that `LocationManager` may not be as effective as Google Play Services implementation. * If the device's in airplane mode, only the GPS provider is used, which may take longer to return a location, depending on GPS signal. * This means that to receive location in such circumstances, you may need to provide a higher timeout. - * + * * @default true * @since 8.0.0 */ - enableLocationFallback?: boolean + enableLocationFallback?: boolean; } export type WatchPositionCallback = (position: Position | null, err?: any) => void;