From 412f92cdc20d7abec564066da67ef537c94517fd Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Tue, 30 Sep 2025 15:51:15 +0100 Subject: [PATCH 1/8] feat: Fallback for no network or Play Services Via a future version of native library --- .../cordova-plugin/android/OSGeolocation.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/cordova-plugin/android/OSGeolocation.kt b/packages/cordova-plugin/android/OSGeolocation.kt index 8252821..2a9e901 100644 --- a/packages/cordova-plugin/android/OSGeolocation.kt +++ b/packages/cordova-plugin/android/OSGeolocation.kt @@ -1,9 +1,16 @@ package com.outsystems.plugins.geolocation -import com.google.android.gms.location.LocationServices +import android.Manifest +import android.content.pm.PackageManager +import androidx.activity.result.contract.ActivityResultContracts import com.google.gson.Gson +import io.ionic.libs.iongeolocationlib.controller.IONGLOCController +import io.ionic.libs.iongeolocationlib.model.IONGLOCException +import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationOptions import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch import org.apache.cordova.CallbackContext import org.apache.cordova.CordovaInterface @@ -13,14 +20,6 @@ import org.apache.cordova.PermissionHelper import org.apache.cordova.PluginResult import org.json.JSONArray import org.json.JSONObject -import android.Manifest -import android.content.pm.PackageManager -import androidx.activity.result.contract.ActivityResultContracts -import io.ionic.libs.iongeolocationlib.controller.IONGLOCController -import io.ionic.libs.iongeolocationlib.model.IONGLOCException -import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationOptions -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.MutableSharedFlow /** * Cordova bridge, inherits from CordovaPlugin @@ -40,6 +39,7 @@ class OSGeolocation : CordovaPlugin() { private const val TIMEOUT = "timeout" private const val MAXIMUM_AGE = "maximumAge" private const val ENABLE_HIGH_ACCURACY = "enableHighAccuracy" + private const val ENABLE_FALLBACK = "enableLocationFallback" } override fun initialize(cordova: CordovaInterface, webView: CordovaWebView) { @@ -54,10 +54,7 @@ class OSGeolocation : CordovaPlugin() { } } - this.controller = IONGLOCController( - LocationServices.getFusedLocationProviderClient(cordova.context), - activityLauncher - ) + this.controller = IONGLOCController(cordova.context, activityLauncher) } override fun onDestroy() { @@ -103,7 +100,9 @@ class OSGeolocation : CordovaPlugin() { val locationOptions = IONGLOCLocationOptions( options.getLong(TIMEOUT), options.getLong(MAXIMUM_AGE), - options.getBoolean(ENABLE_HIGH_ACCURACY)) + options.getBoolean(ENABLE_HIGH_ACCURACY), + enableLocationManagerFallback = options.optBoolean(ENABLE_FALLBACK, true) + ) val locationResult = controller.getCurrentPosition(cordova.activity, locationOptions) @@ -137,6 +136,7 @@ class OSGeolocation : CordovaPlugin() { timeout = options.getLong(TIMEOUT), maximumAge = options.getLong(MAXIMUM_AGE), enableHighAccuracy = options.getBoolean(ENABLE_HIGH_ACCURACY), + enableLocationManagerFallback = options.optBoolean(ENABLE_FALLBACK, true) ) controller.addWatch(cordova.activity, locationOptions, watchId).collect { result -> From 31a03d6f3e15dfe7367eec3bb3434a188c269edb Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Wed, 1 Oct 2025 10:38:37 +0100 Subject: [PATCH 2/8] chore: Add additional error code For network and location turned off Referneces: https://outsystemsrd.atlassian.net/browse/RMET-2991 --- packages/cordova-plugin/android/OSGeolocation.kt | 4 ++++ packages/cordova-plugin/android/OSGeolocationErrors.kt | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/packages/cordova-plugin/android/OSGeolocation.kt b/packages/cordova-plugin/android/OSGeolocation.kt index 2a9e901..e8830c9 100644 --- a/packages/cordova-plugin/android/OSGeolocation.kt +++ b/packages/cordova-plugin/android/OSGeolocation.kt @@ -175,6 +175,10 @@ class OSGeolocation : CordovaPlugin() { callbackContext.sendError(OSGeolocationErrors.LOCATION_SETTINGS_ERROR) } + is IONGLOCException.IONGLOCLocationAndNetworkDisabledException -> { + callbackContext.sendError(OSGeolocationErrors.NETWORK_LOCATION_DISABLED_ERROR) + } + is IONGLOCException.IONGLOCInvalidTimeoutException -> { callbackContext.sendError(OSGeolocationErrors.INVALID_TIMEOUT) } diff --git a/packages/cordova-plugin/android/OSGeolocationErrors.kt b/packages/cordova-plugin/android/OSGeolocationErrors.kt index 5ec6a16..b96aaba 100644 --- a/packages/cordova-plugin/android/OSGeolocationErrors.kt +++ b/packages/cordova-plugin/android/OSGeolocationErrors.kt @@ -78,4 +78,9 @@ object OSGeolocationErrors { 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 From 040b4d5044a409749aa79ef5004e79a7479fafb0 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 14:43:29 +0100 Subject: [PATCH 3/8] chore(web): Add `enableLocationFallback` param to interface --- packages/cordova-plugin/src/defaults.ts | 3 ++- packages/cordova-plugin/src/definitions.ts | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/cordova-plugin/src/defaults.ts b/packages/cordova-plugin/src/defaults.ts index 2a626d0..d2204be 100644 --- a/packages/cordova-plugin/src/defaults.ts +++ b/packages/cordova-plugin/src/defaults.ts @@ -4,7 +4,8 @@ export const CurrentPositionOptionsDefault: CurrentPositionOptions = { enableHighAccuracy: false, timeout: 1000, maximumAge: 0, - minimumUpdateInterval: 5000 + minimumUpdateInterval: 5000, + enableLocationFallback: true } export const ClearWatchOptionsDefault: ClearWatchOptions = { diff --git a/packages/cordova-plugin/src/definitions.ts b/packages/cordova-plugin/src/definitions.ts index 005cd87..d447629 100644 --- a/packages/cordova-plugin/src/definitions.ts +++ b/packages/cordova-plugin/src/definitions.ts @@ -86,9 +86,19 @@ export type CurrentPositionOptions = { * This parameter is only available for Android. It has no effect on iOS or Web platforms. * * @default 5000 - * @since 6.1.0 + * @since 1.0.0 */ minimumUpdateInterval?: number; + + /** + * This option applies to Android only. + * + * TODO document + * + * @default true + * @since 1.1.0 + */ + enableLocationFallback?: boolean } export type ClearWatchOptions = { From d4c4ce98cbb95d5fb0d6659916488c70edd0290c Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 14:45:25 +0100 Subject: [PATCH 4/8] chore(outsystems-wrapper): Remove .gitignore The reason being that dist/outsystems.js is used directly in OutSystems Wrapper, and as such should be in source control. Plus, it can be helpful to automate updating the wrapper --- packages/outsystems-wrapper/.gitignore | 3 +- .../dist/outsystems-wrapper/src/index.d.ts | 12 + .../outsystems-wrapper/dist/outsystems.cjs | 247 +++++++++++++++++ .../outsystems-wrapper/dist/outsystems.js | 251 ++++++++++++++++++ .../outsystems-wrapper/dist/outsystems.mjs | 247 +++++++++++++++++ 5 files changed, 758 insertions(+), 2 deletions(-) create mode 100644 packages/outsystems-wrapper/dist/outsystems-wrapper/src/index.d.ts create mode 100644 packages/outsystems-wrapper/dist/outsystems.cjs create mode 100644 packages/outsystems-wrapper/dist/outsystems.js create mode 100644 packages/outsystems-wrapper/dist/outsystems.mjs diff --git a/packages/outsystems-wrapper/.gitignore b/packages/outsystems-wrapper/.gitignore index 890a2a5..8c75a42 100644 --- a/packages/outsystems-wrapper/.gitignore +++ b/packages/outsystems-wrapper/.gitignore @@ -23,5 +23,4 @@ node_modules/ # Generated by Cordova /plugins/ -/platforms/ -dist/ \ No newline at end of file +/platforms/ \ No newline at end of file diff --git a/packages/outsystems-wrapper/dist/outsystems-wrapper/src/index.d.ts b/packages/outsystems-wrapper/dist/outsystems-wrapper/src/index.d.ts new file mode 100644 index 0000000..6198df3 --- /dev/null +++ b/packages/outsystems-wrapper/dist/outsystems-wrapper/src/index.d.ts @@ -0,0 +1,12 @@ +import { ClearWatchOptions, PluginError, Position, CurrentPositionOptions, WatchPositionOptions } from '../../cordova-plugin/src/definitions'; +declare class OSGeolocation { + #private; + getCurrentPosition(success: (position: Position) => void, error: (err: PluginError | GeolocationPositionError) => void, options: CurrentPositionOptions): void; + watchPosition(success: (result: Position) => void, error: (error: PluginError | GeolocationPositionError) => void, options: WatchPositionOptions): string | number; + /** + * Clears the specified heading watch. + */ + clearWatch(options: ClearWatchOptions, success?: () => void, error?: (error: PluginError | GeolocationPositionError) => void): void; +} +export declare const OSGeolocationInstance: OSGeolocation; +export {}; diff --git a/packages/outsystems-wrapper/dist/outsystems.cjs b/packages/outsystems-wrapper/dist/outsystems.cjs new file mode 100644 index 0000000..e2ded32 --- /dev/null +++ b/packages/outsystems-wrapper/dist/outsystems.cjs @@ -0,0 +1,247 @@ +"use strict"; +var __typeError = (msg) => { + throw TypeError(msg); +}; +var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); +var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); +var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); +var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); +var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); +var _lastPosition, _timers, _callbackIdsMap, _OSGeolocation_instances, createTimeout_fn, convertFromLegacy_fn, isLegacyPosition_fn, shouldUseWebApi_fn, isCapacitorPluginDefined_fn, isSynapseDefined_fn; +Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); +const byteToHex = []; +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 256).toString(16).slice(1)); +} +function unsafeStringify(arr, offset = 0) { + return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); +} +let getRandomValues; +const rnds8 = new Uint8Array(16); +function rng() { + if (!getRandomValues) { + if (typeof crypto === "undefined" || !crypto.getRandomValues) { + throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"); + } + getRandomValues = crypto.getRandomValues.bind(crypto); + } + return getRandomValues(rnds8); +} +const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto); +const native = { randomUUID }; +function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + options = options || {}; + const rnds = options.random || (options.rng || rng)(); + rnds[6] = rnds[6] & 15 | 64; + rnds[8] = rnds[8] & 63 | 128; + return unsafeStringify(rnds); +} +class OSGeolocation { + constructor() { + __privateAdd(this, _OSGeolocation_instances); + __privateAdd(this, _lastPosition, null); + __privateAdd(this, _timers, {}); + __privateAdd(this, _callbackIdsMap, {}); + } + getCurrentPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.getCurrentPosition(success, error, options); + return; + } + let id = v4(); + let timeoutID; + const successCallback = (position) => { + if (typeof __privateGet(this, _timers)[id] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, position)) { + position = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, position); + } + clearTimeout(timeoutID); + __privateSet(this, _lastPosition, position); + success(position); + }; + const errorCallback = (e) => { + if (typeof __privateGet(this, _timers)[id] !== "undefined") { + clearTimeout(__privateGet(this, _timers)[id]); + } + error(e); + }; + if (__privateGet(this, _lastPosition) && options.maximumAge && (/* @__PURE__ */ new Date()).getTime() - __privateGet(this, _lastPosition).timestamp <= options.maximumAge) { + success(__privateGet(this, _lastPosition)); + } else if (options.timeout === 0) { + error({ + code: "OS-PLUG-GLOC-0017", + message: "The Timeout value in CurrentPositionOptions is set to 0 and: (1) no cached Position object available, or (2) cached Position object's age exceeds provided CurrentPositionOptions' maximumAge parameter." + }); + } else { + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, false, id); + __privateGet(this, _timers)[id] = timeoutID; + } + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.getCurrentPosition(options, successCallback, errorCallback); + } else { + Capacitor.Plugins.Geolocation.getCurrentPosition(options).then(successCallback).catch(errorCallback); + } + } + } + watchPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + return navigator.geolocation.watchPosition(success, error, options); + } + let watchId = v4(); + let timeoutID; + const successCallback = (res) => { + if (typeof __privateGet(this, _timers)[watchId] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, res)) { + res = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, res); + } + clearTimeout(__privateGet(this, _timers)[watchId]); + __privateSet(this, _lastPosition, res); + success(res); + }; + const errorCallback = (e) => { + if (typeof timeoutID !== "undefined") { + clearTimeout(timeoutID); + } + error(e); + }; + const watchAddedCallback = (callbackId) => { + __privateGet(this, _callbackIdsMap)[watchId] = callbackId; + }; + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, true, watchId); + __privateGet(this, _timers)[watchId] = timeoutID; + } + options.id = watchId; + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + Capacitor.Plugins.Geolocation.watchPosition( + options, + (position, err) => { + if (err) { + errorCallback(err); + } else if (position) { + successCallback(position); + } + } + ).then(watchAddedCallback); + } else { + cordova.plugins.Geolocation.watchPosition(options, successCallback, errorCallback); + } + return watchId; + } + /** + * Clears the specified heading watch. + */ + clearWatch(options, success = () => { + }, error = () => { + }) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.clearWatch(options.id); + success(); + return; + } + clearTimeout(__privateGet(this, _timers)[options.id]); + delete __privateGet(this, _timers)[options.id]; + let optionsWithCorrectId = options; + if (__privateGet(this, _callbackIdsMap)[options.id]) { + optionsWithCorrectId = { id: __privateGet(this, _callbackIdsMap)[options.id] }; + } + const successCallback = () => { + delete __privateGet(this, _callbackIdsMap)[options.id]; + success(); + }; + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.clearWatch(optionsWithCorrectId, successCallback, error); + } else { + Capacitor.Plugins.Geolocation.clearWatch(optionsWithCorrectId).then(successCallback).catch(error); + } + } +} +_lastPosition = new WeakMap(); +_timers = new WeakMap(); +_callbackIdsMap = new WeakMap(); +_OSGeolocation_instances = new WeakSet(); +/** + * Returns a timeout failure, closed over a specified timeout value and error callback. + * @param onError the error callback + * @param timeout timeout in ms + * @param isWatch returns `true` if the caller of this function was the from the watch flow + * @param id the watch ID + * @returns the timeout's ID + */ +createTimeout_fn = function(onError, timeout, isWatch, id) { + let t = setTimeout(() => { + if (isWatch === true) { + this.clearWatch({ id }); + } + onError({ + code: "OS-PLUG-GLOC-0010", + message: "Could not obtain location in time. Try with a higher timeout." + }); + }, timeout); + return t; +}; +/** + * + * @param lPosition the position in its' legacy + * @returns new Position instance + */ +convertFromLegacy_fn = function(lPosition) { + return { + coords: { + latitude: lPosition.latitude, + longitude: lPosition.longitude, + altitude: lPosition.altitude, + accuracy: lPosition.accuracy, + heading: lPosition.heading, + speed: lPosition.velocity, + altitudeAccuracy: lPosition.altitudeAccuracy + }, + timestamp: lPosition.timestamp + }; +}; +/** + * In previous versions of the plugin, the native side would return speed as `velocity` + * From now on, it returns the same value under `speed` + * @param position the position to verify + * @returns true if the object contains the `velocity` property + */ +isLegacyPosition_fn = function(position) { + return position.velocity !== void 0; +}; +/** + * @returns true if should use web API, false otherwise + */ +shouldUseWebApi_fn = function() { + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + return false; + } + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + const platform = Capacitor.getPlatform(); + return platform === "web"; + } + return true; +}; +/** + * Checks if @capacitor/geolocation plugin is defined + * + * @returns true if geolocation capacitor plugin is available; false otherwise + */ +isCapacitorPluginDefined_fn = function() { + return typeof Capacitor !== "undefined" && typeof Capacitor.Plugins !== "undefined" && typeof Capacitor.Plugins.Geolocation !== "undefined"; +}; +/** + * @returns true if synapse is defined, false otherwise + */ +isSynapseDefined_fn = function() { + return typeof CapacitorUtils !== "undefined" && typeof CapacitorUtils.Synapse !== "undefined" && typeof CapacitorUtils.Synapse.Geolocation !== "undefined"; +}; +const OSGeolocationInstance = new OSGeolocation(); +exports.OSGeolocationInstance = OSGeolocationInstance; diff --git a/packages/outsystems-wrapper/dist/outsystems.js b/packages/outsystems-wrapper/dist/outsystems.js new file mode 100644 index 0000000..b09a377 --- /dev/null +++ b/packages/outsystems-wrapper/dist/outsystems.js @@ -0,0 +1,251 @@ +(function(global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.OSGeolocationWrapper = {})); +})(this, function(exports2) { + "use strict";var __typeError = (msg) => { + throw TypeError(msg); +}; +var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); +var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); +var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); +var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); +var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); + + var _lastPosition, _timers, _callbackIdsMap, _OSGeolocation_instances, createTimeout_fn, convertFromLegacy_fn, isLegacyPosition_fn, shouldUseWebApi_fn, isCapacitorPluginDefined_fn, isSynapseDefined_fn; + const byteToHex = []; + for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 256).toString(16).slice(1)); + } + function unsafeStringify(arr, offset = 0) { + return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); + } + let getRandomValues; + const rnds8 = new Uint8Array(16); + function rng() { + if (!getRandomValues) { + if (typeof crypto === "undefined" || !crypto.getRandomValues) { + throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"); + } + getRandomValues = crypto.getRandomValues.bind(crypto); + } + return getRandomValues(rnds8); + } + const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto); + const native = { randomUUID }; + function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + options = options || {}; + const rnds = options.random || (options.rng || rng)(); + rnds[6] = rnds[6] & 15 | 64; + rnds[8] = rnds[8] & 63 | 128; + return unsafeStringify(rnds); + } + class OSGeolocation { + constructor() { + __privateAdd(this, _OSGeolocation_instances); + __privateAdd(this, _lastPosition, null); + __privateAdd(this, _timers, {}); + __privateAdd(this, _callbackIdsMap, {}); + } + getCurrentPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.getCurrentPosition(success, error, options); + return; + } + let id = v4(); + let timeoutID; + const successCallback = (position) => { + if (typeof __privateGet(this, _timers)[id] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, position)) { + position = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, position); + } + clearTimeout(timeoutID); + __privateSet(this, _lastPosition, position); + success(position); + }; + const errorCallback = (e) => { + if (typeof __privateGet(this, _timers)[id] !== "undefined") { + clearTimeout(__privateGet(this, _timers)[id]); + } + error(e); + }; + if (__privateGet(this, _lastPosition) && options.maximumAge && (/* @__PURE__ */ new Date()).getTime() - __privateGet(this, _lastPosition).timestamp <= options.maximumAge) { + success(__privateGet(this, _lastPosition)); + } else if (options.timeout === 0) { + error({ + code: "OS-PLUG-GLOC-0017", + message: "The Timeout value in CurrentPositionOptions is set to 0 and: (1) no cached Position object available, or (2) cached Position object's age exceeds provided CurrentPositionOptions' maximumAge parameter." + }); + } else { + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, false, id); + __privateGet(this, _timers)[id] = timeoutID; + } + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.getCurrentPosition(options, successCallback, errorCallback); + } else { + Capacitor.Plugins.Geolocation.getCurrentPosition(options).then(successCallback).catch(errorCallback); + } + } + } + watchPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + return navigator.geolocation.watchPosition(success, error, options); + } + let watchId = v4(); + let timeoutID; + const successCallback = (res) => { + if (typeof __privateGet(this, _timers)[watchId] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, res)) { + res = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, res); + } + clearTimeout(__privateGet(this, _timers)[watchId]); + __privateSet(this, _lastPosition, res); + success(res); + }; + const errorCallback = (e) => { + if (typeof timeoutID !== "undefined") { + clearTimeout(timeoutID); + } + error(e); + }; + const watchAddedCallback = (callbackId) => { + __privateGet(this, _callbackIdsMap)[watchId] = callbackId; + }; + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, true, watchId); + __privateGet(this, _timers)[watchId] = timeoutID; + } + options.id = watchId; + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + Capacitor.Plugins.Geolocation.watchPosition( + options, + (position, err) => { + if (err) { + errorCallback(err); + } else if (position) { + successCallback(position); + } + } + ).then(watchAddedCallback); + } else { + cordova.plugins.Geolocation.watchPosition(options, successCallback, errorCallback); + } + return watchId; + } + /** + * Clears the specified heading watch. + */ + clearWatch(options, success = () => { + }, error = () => { + }) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.clearWatch(options.id); + success(); + return; + } + clearTimeout(__privateGet(this, _timers)[options.id]); + delete __privateGet(this, _timers)[options.id]; + let optionsWithCorrectId = options; + if (__privateGet(this, _callbackIdsMap)[options.id]) { + optionsWithCorrectId = { id: __privateGet(this, _callbackIdsMap)[options.id] }; + } + const successCallback = () => { + delete __privateGet(this, _callbackIdsMap)[options.id]; + success(); + }; + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.clearWatch(optionsWithCorrectId, successCallback, error); + } else { + Capacitor.Plugins.Geolocation.clearWatch(optionsWithCorrectId).then(successCallback).catch(error); + } + } + } + _lastPosition = new WeakMap(); + _timers = new WeakMap(); + _callbackIdsMap = new WeakMap(); + _OSGeolocation_instances = new WeakSet(); + /** + * Returns a timeout failure, closed over a specified timeout value and error callback. + * @param onError the error callback + * @param timeout timeout in ms + * @param isWatch returns `true` if the caller of this function was the from the watch flow + * @param id the watch ID + * @returns the timeout's ID + */ + createTimeout_fn = function(onError, timeout, isWatch, id) { + let t = setTimeout(() => { + if (isWatch === true) { + this.clearWatch({ id }); + } + onError({ + code: "OS-PLUG-GLOC-0010", + message: "Could not obtain location in time. Try with a higher timeout." + }); + }, timeout); + return t; + }; + /** + * + * @param lPosition the position in its' legacy + * @returns new Position instance + */ + convertFromLegacy_fn = function(lPosition) { + return { + coords: { + latitude: lPosition.latitude, + longitude: lPosition.longitude, + altitude: lPosition.altitude, + accuracy: lPosition.accuracy, + heading: lPosition.heading, + speed: lPosition.velocity, + altitudeAccuracy: lPosition.altitudeAccuracy + }, + timestamp: lPosition.timestamp + }; + }; + /** + * In previous versions of the plugin, the native side would return speed as `velocity` + * From now on, it returns the same value under `speed` + * @param position the position to verify + * @returns true if the object contains the `velocity` property + */ + isLegacyPosition_fn = function(position) { + return position.velocity !== void 0; + }; + /** + * @returns true if should use web API, false otherwise + */ + shouldUseWebApi_fn = function() { + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + return false; + } + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + const platform = Capacitor.getPlatform(); + return platform === "web"; + } + return true; + }; + /** + * Checks if @capacitor/geolocation plugin is defined + * + * @returns true if geolocation capacitor plugin is available; false otherwise + */ + isCapacitorPluginDefined_fn = function() { + return typeof Capacitor !== "undefined" && typeof Capacitor.Plugins !== "undefined" && typeof Capacitor.Plugins.Geolocation !== "undefined"; + }; + /** + * @returns true if synapse is defined, false otherwise + */ + isSynapseDefined_fn = function() { + return typeof CapacitorUtils !== "undefined" && typeof CapacitorUtils.Synapse !== "undefined" && typeof CapacitorUtils.Synapse.Geolocation !== "undefined"; + }; + const OSGeolocationInstance = new OSGeolocation(); + exports2.OSGeolocationInstance = OSGeolocationInstance; + Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); +}); diff --git a/packages/outsystems-wrapper/dist/outsystems.mjs b/packages/outsystems-wrapper/dist/outsystems.mjs new file mode 100644 index 0000000..ec3ae24 --- /dev/null +++ b/packages/outsystems-wrapper/dist/outsystems.mjs @@ -0,0 +1,247 @@ +var __typeError = (msg) => { + throw TypeError(msg); +}; +var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); +var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); +var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); +var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); +var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method); +var _lastPosition, _timers, _callbackIdsMap, _OSGeolocation_instances, createTimeout_fn, convertFromLegacy_fn, isLegacyPosition_fn, shouldUseWebApi_fn, isCapacitorPluginDefined_fn, isSynapseDefined_fn; +const byteToHex = []; +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 256).toString(16).slice(1)); +} +function unsafeStringify(arr, offset = 0) { + return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); +} +let getRandomValues; +const rnds8 = new Uint8Array(16); +function rng() { + if (!getRandomValues) { + if (typeof crypto === "undefined" || !crypto.getRandomValues) { + throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"); + } + getRandomValues = crypto.getRandomValues.bind(crypto); + } + return getRandomValues(rnds8); +} +const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto); +const native = { randomUUID }; +function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + options = options || {}; + const rnds = options.random || (options.rng || rng)(); + rnds[6] = rnds[6] & 15 | 64; + rnds[8] = rnds[8] & 63 | 128; + return unsafeStringify(rnds); +} +class OSGeolocation { + constructor() { + __privateAdd(this, _OSGeolocation_instances); + __privateAdd(this, _lastPosition, null); + __privateAdd(this, _timers, {}); + __privateAdd(this, _callbackIdsMap, {}); + } + getCurrentPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.getCurrentPosition(success, error, options); + return; + } + let id = v4(); + let timeoutID; + const successCallback = (position) => { + if (typeof __privateGet(this, _timers)[id] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, position)) { + position = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, position); + } + clearTimeout(timeoutID); + __privateSet(this, _lastPosition, position); + success(position); + }; + const errorCallback = (e) => { + if (typeof __privateGet(this, _timers)[id] !== "undefined") { + clearTimeout(__privateGet(this, _timers)[id]); + } + error(e); + }; + if (__privateGet(this, _lastPosition) && options.maximumAge && (/* @__PURE__ */ new Date()).getTime() - __privateGet(this, _lastPosition).timestamp <= options.maximumAge) { + success(__privateGet(this, _lastPosition)); + } else if (options.timeout === 0) { + error({ + code: "OS-PLUG-GLOC-0017", + message: "The Timeout value in CurrentPositionOptions is set to 0 and: (1) no cached Position object available, or (2) cached Position object's age exceeds provided CurrentPositionOptions' maximumAge parameter." + }); + } else { + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, false, id); + __privateGet(this, _timers)[id] = timeoutID; + } + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.getCurrentPosition(options, successCallback, errorCallback); + } else { + Capacitor.Plugins.Geolocation.getCurrentPosition(options).then(successCallback).catch(errorCallback); + } + } + } + watchPosition(success, error, options) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + return navigator.geolocation.watchPosition(success, error, options); + } + let watchId = v4(); + let timeoutID; + const successCallback = (res) => { + if (typeof __privateGet(this, _timers)[watchId] == "undefined") { + return; + } + if (__privateMethod(this, _OSGeolocation_instances, isLegacyPosition_fn).call(this, res)) { + res = __privateMethod(this, _OSGeolocation_instances, convertFromLegacy_fn).call(this, res); + } + clearTimeout(__privateGet(this, _timers)[watchId]); + __privateSet(this, _lastPosition, res); + success(res); + }; + const errorCallback = (e) => { + if (typeof timeoutID !== "undefined") { + clearTimeout(timeoutID); + } + error(e); + }; + const watchAddedCallback = (callbackId) => { + __privateGet(this, _callbackIdsMap)[watchId] = callbackId; + }; + if (options.timeout !== Infinity) { + timeoutID = __privateMethod(this, _OSGeolocation_instances, createTimeout_fn).call(this, errorCallback, options.timeout, true, watchId); + __privateGet(this, _timers)[watchId] = timeoutID; + } + options.id = watchId; + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + Capacitor.Plugins.Geolocation.watchPosition( + options, + (position, err) => { + if (err) { + errorCallback(err); + } else if (position) { + successCallback(position); + } + } + ).then(watchAddedCallback); + } else { + cordova.plugins.Geolocation.watchPosition(options, successCallback, errorCallback); + } + return watchId; + } + /** + * Clears the specified heading watch. + */ + clearWatch(options, success = () => { + }, error = () => { + }) { + if (__privateMethod(this, _OSGeolocation_instances, shouldUseWebApi_fn).call(this)) { + navigator.geolocation.clearWatch(options.id); + success(); + return; + } + clearTimeout(__privateGet(this, _timers)[options.id]); + delete __privateGet(this, _timers)[options.id]; + let optionsWithCorrectId = options; + if (__privateGet(this, _callbackIdsMap)[options.id]) { + optionsWithCorrectId = { id: __privateGet(this, _callbackIdsMap)[options.id] }; + } + const successCallback = () => { + delete __privateGet(this, _callbackIdsMap)[options.id]; + success(); + }; + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + CapacitorUtils.Synapse.Geolocation.clearWatch(optionsWithCorrectId, successCallback, error); + } else { + Capacitor.Plugins.Geolocation.clearWatch(optionsWithCorrectId).then(successCallback).catch(error); + } + } +} +_lastPosition = new WeakMap(); +_timers = new WeakMap(); +_callbackIdsMap = new WeakMap(); +_OSGeolocation_instances = new WeakSet(); +/** + * Returns a timeout failure, closed over a specified timeout value and error callback. + * @param onError the error callback + * @param timeout timeout in ms + * @param isWatch returns `true` if the caller of this function was the from the watch flow + * @param id the watch ID + * @returns the timeout's ID + */ +createTimeout_fn = function(onError, timeout, isWatch, id) { + let t = setTimeout(() => { + if (isWatch === true) { + this.clearWatch({ id }); + } + onError({ + code: "OS-PLUG-GLOC-0010", + message: "Could not obtain location in time. Try with a higher timeout." + }); + }, timeout); + return t; +}; +/** + * + * @param lPosition the position in its' legacy + * @returns new Position instance + */ +convertFromLegacy_fn = function(lPosition) { + return { + coords: { + latitude: lPosition.latitude, + longitude: lPosition.longitude, + altitude: lPosition.altitude, + accuracy: lPosition.accuracy, + heading: lPosition.heading, + speed: lPosition.velocity, + altitudeAccuracy: lPosition.altitudeAccuracy + }, + timestamp: lPosition.timestamp + }; +}; +/** + * In previous versions of the plugin, the native side would return speed as `velocity` + * From now on, it returns the same value under `speed` + * @param position the position to verify + * @returns true if the object contains the `velocity` property + */ +isLegacyPosition_fn = function(position) { + return position.velocity !== void 0; +}; +/** + * @returns true if should use web API, false otherwise + */ +shouldUseWebApi_fn = function() { + if (__privateMethod(this, _OSGeolocation_instances, isSynapseDefined_fn).call(this)) { + return false; + } + if (__privateMethod(this, _OSGeolocation_instances, isCapacitorPluginDefined_fn).call(this)) { + const platform = Capacitor.getPlatform(); + return platform === "web"; + } + return true; +}; +/** + * Checks if @capacitor/geolocation plugin is defined + * + * @returns true if geolocation capacitor plugin is available; false otherwise + */ +isCapacitorPluginDefined_fn = function() { + return typeof Capacitor !== "undefined" && typeof Capacitor.Plugins !== "undefined" && typeof Capacitor.Plugins.Geolocation !== "undefined"; +}; +/** + * @returns true if synapse is defined, false otherwise + */ +isSynapseDefined_fn = function() { + return typeof CapacitorUtils !== "undefined" && typeof CapacitorUtils.Synapse !== "undefined" && typeof CapacitorUtils.Synapse.Geolocation !== "undefined"; +}; +const OSGeolocationInstance = new OSGeolocation(); +export { + OSGeolocationInstance +}; From 05d24ef89ca569b9246163bcff92cd34134d1277 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 15:04:58 +0100 Subject: [PATCH 5/8] docs: Document new `enableLocationFallback` parameter --- packages/cordova-plugin/src/definitions.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/cordova-plugin/src/definitions.ts b/packages/cordova-plugin/src/definitions.ts index d447629..5ee90cc 100644 --- a/packages/cordova-plugin/src/definitions.ts +++ b/packages/cordova-plugin/src/definitions.ts @@ -93,7 +93,12 @@ export type CurrentPositionOptions = { /** * This option applies to Android only. * - * TODO document + * 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 1.1.0 From 8b8d99cb4c025b20760e95865ff8ac7392b32b85 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 15:06:38 +0100 Subject: [PATCH 6/8] chore(android): update native library --- packages/cordova-plugin/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cordova-plugin/android/build.gradle b/packages/cordova-plugin/android/build.gradle index 9b57d02..74715e8 100644 --- a/packages/cordova-plugin/android/build.gradle +++ b/packages/cordova-plugin/android/build.gradle @@ -17,7 +17,7 @@ allprojects { } dependencies{ - implementation("io.ionic.libs:iongeolocation-android:1.0.0") + implementation("io.ionic.libs:iongeolocation-android:2.0.0") implementation("androidx.browser:browser:1.8.0") implementation("com.google.android.gms:play-services-auth:21.2.0") implementation("com.google.android.gms:play-services-location:21.3.0") From d16241fbe873da2aa857a4421cb4c64ef64c7841 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 15:22:11 +0100 Subject: [PATCH 7/8] chore(web): run build script --- packages/cordova-plugin/README.md | 14 ++++++++- packages/cordova-plugin/dist/definitions.d.ts | 16 +++++++++- packages/cordova-plugin/dist/plugin.cjs | 31 ++++++++++--------- packages/cordova-plugin/dist/plugin.js | 31 ++++++++++--------- packages/cordova-plugin/dist/plugin.mjs | 31 ++++++++++--------- 5 files changed, 76 insertions(+), 47 deletions(-) diff --git a/packages/cordova-plugin/README.md b/packages/cordova-plugin/README.md index 3b0a813..9bcd16b 100644 --- a/packages/cordova-plugin/README.md +++ b/packages/cordova-plugin/README.md @@ -15,6 +15,7 @@ cordova plugin add * [`getCurrentPosition(...)`](#getcurrentposition) * [`watchPosition(...)`](#watchposition) * [`clearWatch(...)`](#clearwatch) +* [Interfaces](#interfaces) * [Type Aliases](#type-aliases) @@ -80,12 +81,23 @@ Clear a given watch -------------------- +### Interfaces + + +#### Position + +| Prop | Type | Description | +| ------------ | ------------------- | ----------- | +| **`line`** | number | >= 1 | +| **`column`** | number | >= 0 | + + ### Type Aliases #### CurrentPositionOptions -{ /** * 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). * * @default false * @since 1.0.0 */ enableHighAccuracy?: boolean; /** * The maximum wait time in milliseconds for location updates. * * In Android, since version 4.0.0 of the plugin, timeout gets ignored for getCurrentPosition. * * @default 10000 * @since 1.0.0 */ timeout?: number; /** * The maximum age in milliseconds of a possible cached position that is acceptable to return * * @default 0 * @since 1.0.0 */ maximumAge?: 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. * * @default 5000 * @since 6.1.0 */ minimumUpdateInterval?: number; } +{ /** * 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). * * @default false * @since 1.0.0 */ enableHighAccuracy?: boolean; /** * The maximum wait time in milliseconds for location updates. * * In Android, since version 4.0.0 of the plugin, timeout gets ignored for getCurrentPosition. * * @default 10000 * @since 1.0.0 */ timeout?: number; /** * The maximum age in milliseconds of a possible cached position that is acceptable to return * * @default 0 * @since 1.0.0 */ maximumAge?: 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. * * @default 5000 * @since 1.0.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 1.1.0 */ enableLocationFallback?: boolean } #### Position diff --git a/packages/cordova-plugin/dist/definitions.d.ts b/packages/cordova-plugin/dist/definitions.d.ts index 240d7e2..c0ef31e 100644 --- a/packages/cordova-plugin/dist/definitions.d.ts +++ b/packages/cordova-plugin/dist/definitions.d.ts @@ -74,9 +74,23 @@ export type CurrentPositionOptions = { * This parameter is only available for Android. It has no effect on iOS or Web platforms. * * @default 5000 - * @since 6.1.0 + * @since 1.0.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 1.1.0 + */ + enableLocationFallback?: boolean; }; export type ClearWatchOptions = { id: string; diff --git a/packages/cordova-plugin/dist/plugin.cjs b/packages/cordova-plugin/dist/plugin.cjs index 9da0bd1..4efb021 100644 --- a/packages/cordova-plugin/dist/plugin.cjs +++ b/packages/cordova-plugin/dist/plugin.cjs @@ -4,25 +4,25 @@ function s(t) { t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { + get(e, n) { return new Proxy({}, { - get(w, r) { - return (c, p, n) => { - const i = t.Capacitor.Plugins[o]; + get(w, o) { + return (c, p, r) => { + const i = t.Capacitor.Plugins[n]; if (i === void 0) { - n(new Error(`Capacitor plugin ${o} not found`)); + r(new Error(`Capacitor plugin ${n} not found`)); return; } - if (typeof i[r] != "function") { - n(new Error(`Method ${r} not found in Capacitor plugin ${o}`)); + if (typeof i[o] != "function") { + r(new Error(`Method ${o} not found in Capacitor plugin ${n}`)); return; } (async () => { try { - const a = await i[r](c); + const a = await i[o](c); p(a); } catch (a) { - n(a); + r(a); } })(); }; @@ -36,20 +36,21 @@ function u(t) { t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { - return t.cordova.plugins[o]; + get(e, n) { + return t.cordova.plugins[n]; } } ); } -function y(t = false) { - window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window); +function f(t = false) { + typeof window > "u" || (window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window)); } const CurrentPositionOptionsDefault = { enableHighAccuracy: false, timeout: 1e3, maximumAge: 0, - minimumUpdateInterval: 5e3 + minimumUpdateInterval: 5e3, + enableLocationFallback: true }; const ClearWatchOptionsDefault = { id: "-1" @@ -106,4 +107,4 @@ module.exports = { watchPosition, clearWatch }; -y(true); +f(true); diff --git a/packages/cordova-plugin/dist/plugin.js b/packages/cordova-plugin/dist/plugin.js index 0ff78fa..9da7229 100644 --- a/packages/cordova-plugin/dist/plugin.js +++ b/packages/cordova-plugin/dist/plugin.js @@ -6,25 +6,25 @@ t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { + get(e, n) { return new Proxy({}, { - get(w, r) { - return (c, p, n) => { - const i = t.Capacitor.Plugins[o]; + get(w, o) { + return (c, p, r) => { + const i = t.Capacitor.Plugins[n]; if (i === void 0) { - n(new Error(`Capacitor plugin ${o} not found`)); + r(new Error(`Capacitor plugin ${n} not found`)); return; } - if (typeof i[r] != "function") { - n(new Error(`Method ${r} not found in Capacitor plugin ${o}`)); + if (typeof i[o] != "function") { + r(new Error(`Method ${o} not found in Capacitor plugin ${n}`)); return; } (async () => { try { - const a = await i[r](c); + const a = await i[o](c); p(a); } catch (a) { - n(a); + r(a); } })(); }; @@ -38,20 +38,21 @@ t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { - return t.cordova.plugins[o]; + get(e, n) { + return t.cordova.plugins[n]; } } ); } - function y(t = false) { - window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window); + function f(t = false) { + typeof window > "u" || (window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window)); } const CurrentPositionOptionsDefault = { enableHighAccuracy: false, timeout: 1e3, maximumAge: 0, - minimumUpdateInterval: 5e3 + minimumUpdateInterval: 5e3, + enableLocationFallback: true }; const ClearWatchOptionsDefault = { id: "-1" @@ -108,5 +109,5 @@ watchPosition, clearWatch }; - y(true); + f(true); }); diff --git a/packages/cordova-plugin/dist/plugin.mjs b/packages/cordova-plugin/dist/plugin.mjs index 7560592..82bd3cd 100644 --- a/packages/cordova-plugin/dist/plugin.mjs +++ b/packages/cordova-plugin/dist/plugin.mjs @@ -3,25 +3,25 @@ function s(t) { t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { + get(e, n) { return new Proxy({}, { - get(w, r) { - return (c, p, n) => { - const i = t.Capacitor.Plugins[o]; + get(w, o) { + return (c, p, r) => { + const i = t.Capacitor.Plugins[n]; if (i === void 0) { - n(new Error(`Capacitor plugin ${o} not found`)); + r(new Error(`Capacitor plugin ${n} not found`)); return; } - if (typeof i[r] != "function") { - n(new Error(`Method ${r} not found in Capacitor plugin ${o}`)); + if (typeof i[o] != "function") { + r(new Error(`Method ${o} not found in Capacitor plugin ${n}`)); return; } (async () => { try { - const a = await i[r](c); + const a = await i[o](c); p(a); } catch (a) { - n(a); + r(a); } })(); }; @@ -35,20 +35,21 @@ function u(t) { t.CapacitorUtils.Synapse = new Proxy( {}, { - get(e, o) { - return t.cordova.plugins[o]; + get(e, n) { + return t.cordova.plugins[n]; } } ); } -function y(t = false) { - window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window); +function f(t = false) { + typeof window > "u" || (window.CapacitorUtils = window.CapacitorUtils || {}, window.Capacitor !== void 0 && !t ? s(window) : window.cordova !== void 0 && u(window)); } const CurrentPositionOptionsDefault = { enableHighAccuracy: false, timeout: 1e3, maximumAge: 0, - minimumUpdateInterval: 5e3 + minimumUpdateInterval: 5e3, + enableLocationFallback: true }; const ClearWatchOptionsDefault = { id: "-1" @@ -105,4 +106,4 @@ module.exports = { watchPosition, clearWatch }; -y(true); +f(true); From e21258bde3de9d9658914a04eedc857e7fab2c73 Mon Sep 17 00:00:00 2001 From: OS-pedrogustavobilro Date: Fri, 3 Oct 2025 15:25:04 +0100 Subject: [PATCH 8/8] chore(release): prepare to release plugin version 1.1.0 --- CHANGELOG.md | 4 ++++ package.json | 2 +- packages/cordova-plugin/package.json | 2 +- plugin.xml | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4b07b..735b1f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.0] +## 2025-10-03 + +- Feature(android): Location fallback in case of Play Services failure or airplane mode. ## [1.0.3] diff --git a/package.json b/package.json index 937e5c1..5417d4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.outsystems.plugins.geolocation", - "version": "1.0.3", + "version": "1.1.0", "private": true, "dependencies": {}, "scripts": { diff --git a/packages/cordova-plugin/package.json b/packages/cordova-plugin/package.json index 4b234b1..20a6f78 100644 --- a/packages/cordova-plugin/package.json +++ b/packages/cordova-plugin/package.json @@ -1,7 +1,7 @@ { "name": "com.outsystems.plugins.geolocation", "displayName": "Geolocation", - "version": "1.0.1", + "version": "1.1.0", "description": "Geolocation plugin for Cordova", "scripts": { "lint": "npm run eslint && npm run prettier -- --check", diff --git a/plugin.xml b/plugin.xml index 69aa817..0d978e8 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,5 +1,5 @@ - + OSGeolocationPlugin OutSystems' cordova geolocation plugin OutSystems Inc