This commit is contained in:
metacryst
2026-01-09 11:14:27 -06:00
parent cf03c95664
commit 637c9e4674
2149 changed files with 527743 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
Pod::Spec.new do |s|
s.name = 'CapacitorGeolocation'
s.version = package['version']
s.summary = package['description']
s.license = package['license']
s.homepage = package['repository']['url']
s.author = package['author']
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
s.ios.deployment_target = '14.0'
s.dependency 'Capacitor'
s.dependency 'IONGeolocationLib', spec='1.0.1'
s.swift_version = '5.1'
end

21
node_modules/@capacitor/geolocation/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Ionic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

34
node_modules/@capacitor/geolocation/Package.swift generated vendored Normal file
View File

@@ -0,0 +1,34 @@
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "CapacitorGeolocation",
platforms: [.iOS(.v14)],
products: [
.library(
name: "CapacitorGeolocation",
targets: ["GeolocationPlugin"])
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
],
targets: [
.binaryTarget(
name: "IONGeolocationLib",
url: "https://github.com/ionic-team/ion-ios-geolocation/releases/download/1.0.1/IONGeolocationLib.zip",
checksum: "80e0283964bce3c5d05f61ff4acf4e029305f58d1699a7f16453058ba876bc21" // sha-256
),
.target(
name: "GeolocationPlugin",
dependencies: [
.product(name: "Capacitor", package: "capacitor-swift-pm"),
.product(name: "Cordova", package: "capacitor-swift-pm"),
"IONGeolocationLib"
],
path: "ios/Sources/GeolocationPlugin"),
.testTarget(
name: "GeolocationPluginTests",
dependencies: ["GeolocationPlugin"],
path: "ios/Tests/GeolocationTests")
]
)

246
node_modules/@capacitor/geolocation/README.md generated vendored Normal file
View File

@@ -0,0 +1,246 @@
# @capacitor/geolocation
The Geolocation API provides simple methods for getting and tracking the current position of the device using GPS, along with altitude, heading, and speed information if available.
## Install
```bash
npm install @capacitor/geolocation
npx cap sync
```
## iOS
Apple requires privacy descriptions to be specified in `Info.plist` for location information:
- `NSLocationAlwaysAndWhenInUseUsageDescription` (`Privacy - Location Always and When In Use Usage Description`)
- `NSLocationWhenInUseUsageDescription` (`Privacy - Location When In Use Usage Description`)
> [!NOTE]
> This Capacitor plugin does not support background geolocation directly. However, it relies on
> [`ion-ios-geolocation`](https://github.com/ionic-team/ion-ios-geolocation), which can report
> location in the background. As a result, Apple requires you to include a
> `NSLocationAlwaysAndWhenInUseUsageDescription` entry in your `Info.plist`. Since this permission
> prompt wont appear to users, you can safely use the same description string as for
> `NSLocationWhenInUseUsageDescription`.
Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode
## Android
This plugin requires the following permissions be added to your `AndroidManifest.xml`:
```xml
<!-- Geolocation Plugin -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
```
The first two permissions ask for location data, both fine and coarse, and the last line is optional but necessary if your app _requires_ GPS to function. You may leave it out, though keep in mind that this may mean your app is installed on devices lacking GPS hardware.
Read about [Setting Permissions](https://capacitorjs.com/docs/android/configuration#setting-permissions) in the [Android Guide](https://capacitorjs.com/docs/android) for more information on setting Android permissions.
## API
<docgen-index>
* [`getCurrentPosition(...)`](#getcurrentposition)
* [`watchPosition(...)`](#watchposition)
* [`clearWatch(...)`](#clearwatch)
* [`checkPermissions()`](#checkpermissions)
* [`requestPermissions(...)`](#requestpermissions)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
</docgen-index>
For list of error codes, see [Errors](#errors)
<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
### getCurrentPosition(...)
```typescript
getCurrentPosition(options?: PositionOptions | undefined) => Promise<Position>
```
Get the current GPS location of the device
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| **`options`** | <code><a href="#positionoptions">PositionOptions</a></code> |
**Returns:** <code>Promise&lt;<a href="#position">Position</a>&gt;</code>
**Since:** 1.0.0
--------------------
### watchPosition(...)
```typescript
watchPosition(options: PositionOptions, callback: WatchPositionCallback) => Promise<CallbackID>
```
Set up a watch for location changes. Note that watching for location changes
can consume a large amount of energy. Be smart about listening only when you need to.
| Param | Type |
| -------------- | ----------------------------------------------------------------------- |
| **`options`** | <code><a href="#positionoptions">PositionOptions</a></code> |
| **`callback`** | <code><a href="#watchpositioncallback">WatchPositionCallback</a></code> |
**Returns:** <code>Promise&lt;string&gt;</code>
**Since:** 1.0.0
--------------------
### clearWatch(...)
```typescript
clearWatch(options: ClearWatchOptions) => Promise<void>
```
Clear a given watch
| Param | Type |
| ------------- | --------------------------------------------------------------- |
| **`options`** | <code><a href="#clearwatchoptions">ClearWatchOptions</a></code> |
**Since:** 1.0.0
--------------------
### checkPermissions()
```typescript
checkPermissions() => Promise<PermissionStatus>
```
Check location permissions. Will throw if system location services are disabled.
**Returns:** <code>Promise&lt;<a href="#permissionstatus">PermissionStatus</a>&gt;</code>
**Since:** 1.0.0
--------------------
### requestPermissions(...)
```typescript
requestPermissions(permissions?: GeolocationPluginPermissions | undefined) => Promise<PermissionStatus>
```
Request location permissions. Will throw if system location services are disabled.
Not available on web.
| Param | Type |
| ----------------- | ------------------------------------------------------------------------------------- |
| **`permissions`** | <code><a href="#geolocationpluginpermissions">GeolocationPluginPermissions</a></code> |
**Returns:** <code>Promise&lt;<a href="#permissionstatus">PermissionStatus</a>&gt;</code>
**Since:** 1.0.0
--------------------
### Interfaces
#### Position
| Prop | Type | Description | Since |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----- |
| **`timestamp`** | <code>number</code> | Creation timestamp for coords | 1.0.0 |
| **`coords`** | <code>{ latitude: number; longitude: number; accuracy: number; altitudeAccuracy: number \| null; altitude: number \| null; speed: number \| null; heading: number \| null; }</code> | The GPS coordinates along with the accuracy of the data | 1.0.0 |
#### PositionOptions
| Prop | Type | Description | Default | Since |
| --------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
| **`enableHighAccuracy`** | <code>boolean</code> | 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). | <code>false</code> | 1.0.0 |
| **`timeout`** | <code>number</code> | 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`. | <code>10000</code> | 1.0.0 |
| **`maximumAge`** | <code>number</code> | The maximum age in milliseconds of a possible cached position that is acceptable to return | <code>0</code> | 1.0.0 |
| **`minimumUpdateInterval`** | <code>number</code> | 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. | <code>5000</code> | 6.1.0 |
#### ClearWatchOptions
| Prop | Type |
| -------- | ------------------------------------------------- |
| **`id`** | <code><a href="#callbackid">CallbackID</a></code> |
#### PermissionStatus
| Prop | Type | Description | Since |
| -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
| **`location`** | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for location alias. On Android it requests/checks both ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permissions. On iOS and web it requests/checks location permission. | 1.0.0 |
| **`coarseLocation`** | <code><a href="#permissionstate">PermissionState</a></code> | Permission state for coarseLocation alias. On Android it requests/checks ACCESS_COARSE_LOCATION. On Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) or Precise location (ACCESS_FINE_LOCATION), so this alias can be used if the app doesn't need high accuracy. On iOS and web it will have the same value as location alias. | 1.2.0 |
#### GeolocationPluginPermissions
| Prop | Type |
| ----------------- | ---------------------------------------- |
| **`permissions`** | <code>GeolocationPermissionType[]</code> |
### Type Aliases
#### WatchPositionCallback
<code>(position: <a href="#position">Position</a> | null, err?: any): void</code>
#### CallbackID
<code>string</code>
#### PermissionState
<code>'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'</code>
#### GeolocationPermissionType
<code>'location' | 'coarseLocation'</code>
</docgen-api>
### Errors
The plugin returns specific errors with specific codes on native Android and iOS. Web does not follow this standard for errors.
The following table list all the plugin errors:
| Error code | Platform(s) | Message |
| -------------------- | ------------ | ---------------------------------------- |
| OS-PLUG-GLOC-0002 | Android, iOS | There was en error trying to obtain the location. |
| OS-PLUG-GLOC-0003 | Android, iOS | Location permission request was denied. |
| OS-PLUG-GLOC-0004 | iOS | The 'getCurrentPosition' input parameters aren't valid. |
| OS-PLUG-GLOC-0005 | iOS | The 'watchPosition' input parameters aren't valid. |
| OS-PLUG-GLOC-0006 | iOS | The 'clearWatch' input parameters aren't valid. |
| 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-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. |
| 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. |

View File

@@ -0,0 +1,72 @@
ext {
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.3.0'
}
buildscript {
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.25'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
namespace "com.capacitorjs.plugins.geolocation"
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
defaultConfig {
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
kotlin {
jvmToolchain(21)
}
repositories {
google()
mavenCentral()
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation("io.ionic.libs:iongeolocation-android:1.0.0")
implementation project(':capacitor-android')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation 'com.google.code.gson:gson:2.10.1'
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4")
implementation "com.google.android.gms:play-services-location:$playServicesLocationVersion"
testImplementation "junit:junit:$junitVersion"
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
}

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,71 @@
package com.capacitorjs.plugins.geolocation
/**
* Object with plugin errors
*/
object GeolocationErrors {
private fun formatErrorCode(number: Int): String {
return "OS-PLUG-GLOC-" + number.toString().padStart(4, '0')
}
data class ErrorInfo(
val code: String,
val message: String
)
val POSITION_UNAVAILABLE = ErrorInfo(
code = formatErrorCode(2),
message = "There was en error trying to obtain the location."
)
val LOCATION_PERMISSIONS_DENIED = ErrorInfo(
code = formatErrorCode(3),
message = "Location permission request was denied."
)
val LOCATION_DISABLED = ErrorInfo(
code = formatErrorCode(7),
message = "Location services are not enabled."
)
val LOCATION_ENABLE_REQUEST_DENIED = ErrorInfo(
code = formatErrorCode(9),
message = "Request to enable location was denied."
)
val GET_LOCATION_TIMEOUT = ErrorInfo(
code = formatErrorCode(10),
message = "Could not obtain location in time. Try with a higher timeout."
)
val INVALID_TIMEOUT = ErrorInfo(
code = formatErrorCode(11),
message = "Timeout needs to be a positive value."
)
val WATCH_ID_NOT_FOUND = ErrorInfo(
code = formatErrorCode(12),
message = "WatchId not found."
)
val WATCH_ID_NOT_PROVIDED = ErrorInfo(
code = formatErrorCode(13),
message = "WatchId needs to be provided."
)
val GOOGLE_SERVICES_RESOLVABLE = ErrorInfo(
code = formatErrorCode(14),
message = "Google Play Services error user resolvable."
)
val GOOGLE_SERVICES_ERROR = ErrorInfo(
code = formatErrorCode(15),
message = "Google Play Services error."
)
val LOCATION_SETTINGS_ERROR = ErrorInfo(
code = formatErrorCode(16),
message = "Location settings error."
)
}

View File

@@ -0,0 +1,341 @@
package com.capacitorjs.plugins.geolocation
import android.Manifest
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import com.getcapacitor.JSObject
import com.getcapacitor.PermissionState
import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
import com.getcapacitor.annotation.Permission
import com.getcapacitor.annotation.PermissionCallback
import com.google.android.gms.location.LocationServices
import io.ionic.libs.iongeolocationlib.controller.IONGLOCController
import io.ionic.libs.iongeolocationlib.model.IONGLOCException
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationOptions
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
@CapacitorPlugin(
name = "Geolocation",
permissions = [Permission(
strings = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION],
alias = GeolocationPlugin.LOCATION_ALIAS
), Permission(
strings = [Manifest.permission.ACCESS_COARSE_LOCATION],
alias = GeolocationPlugin.COARSE_LOCATION_ALIAS
)]
)
class GeolocationPlugin : Plugin() {
private lateinit var controller: IONGLOCController
private lateinit var coroutineScope: CoroutineScope
private val watchingCalls: MutableMap<String, PluginCall> = mutableMapOf()
companion object {
const val LOCATION_ALIAS: String = "location"
const val COARSE_LOCATION_ALIAS: String = "coarseLocation"
}
override fun load() {
super.load()
coroutineScope = CoroutineScope(Dispatchers.Main)
val activityLauncher = activity.registerForActivityResult(
ActivityResultContracts.StartIntentSenderForResult()
) { result ->
CoroutineScope(Dispatchers.Main).launch {
controller.onResolvableExceptionResult(result.resultCode)
}
}
this.controller = IONGLOCController(
LocationServices.getFusedLocationProviderClient(context),
activityLauncher
)
}
override fun handleOnDestroy() {
super.handleOnDestroy()
coroutineScope.cancel()
}
@PluginMethod
override fun checkPermissions(call: PluginCall) {
checkLocationState(call) { super.checkPermissions(call) }
}
@PluginMethod
override fun requestPermissions(call: PluginCall) {
checkLocationState(call) { super.requestPermissions(call) }
}
/**
* Helper function to determine if location services are enabled or not
* @param call the PluginCall to use in case we want to send an error
* @param onLocationEnabled lambda function to use in case location services are enabled
*/
private fun checkLocationState(call: PluginCall, onLocationEnabled: () -> Unit) {
if (controller.areLocationServicesEnabled(context)) {
onLocationEnabled()
} else {
call.sendError(GeolocationErrors.LOCATION_DISABLED)
}
}
/**
* Checks location permission state, requesting them if necessary.
* If not, calls getPosition to get the device's position
* @param call the plugin call
*/
@PluginMethod
fun getCurrentPosition(call: PluginCall) {
handlePermissionRequest(call, "completeCurrentPosition") { getPosition(call) }
}
/**
* Checks location permission state, requesting them if necessary.
* If not, calls startWatch to start getting location updates
* @param call the plugin call
*/
@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
fun watchPosition(call: PluginCall) {
handlePermissionRequest(call, "completeWatchPosition") { startWatch(call) }
}
/**
* Helper function to determine if a permission is granted or not and request it if necessary
* @param call the PluginCall to use in case we want to send an error
* @param callbackName a string identifying the callback to call once the permission prompt is answered
* @param onPermissionGranted lambda function to use in case the permission is enabled
*/
private fun handlePermissionRequest(
call: PluginCall,
callbackName: String,
onPermissionGranted: () -> Unit
) {
val alias = getAlias(call)
if (getPermissionState(alias) != PermissionState.GRANTED) {
requestPermissionForAlias(alias, call, callbackName)
} else {
onPermissionGranted()
}
}
/**
* Completes the getCurrentPosition plugin call after a permission request
* @see .getCurrentPosition
* @param call the plugin call
*/
@PermissionCallback
private fun completeCurrentPosition(call: PluginCall) {
handlePermissionResult(call) { getPosition(call) }
}
/**
* Completes the watchPosition plugin call after a permission request
* @see .startWatch
* @param call the plugin call
*/
@PermissionCallback
private fun completeWatchPosition(call: PluginCall) {
handlePermissionResult(call) { startWatch(call) }
}
/**
* Helper function to handle the result of a location permission request
* @param call the PluginCall to use in case we want to send an error
* @param onPermissionGranted lambda function to use in case the permission was granted
*/
private fun handlePermissionResult(call: PluginCall, onPermissionGranted: () -> Unit) {
if (getPermissionState(COARSE_LOCATION_ALIAS) == PermissionState.GRANTED) {
onPermissionGranted()
} else {
call.sendError(GeolocationErrors.LOCATION_PERMISSIONS_DENIED)
}
}
/**
* Clears the watch, removing location updates.
* @param call the plugin call
*/
@PluginMethod
fun clearWatch(call: PluginCall) {
val id = call.getString("id")
if (id.isNullOrBlank()) {
call.sendError(GeolocationErrors.WATCH_ID_NOT_PROVIDED)
} else {
watchingCalls.remove(id)?.release(bridge)
val watchCleared = controller.clearWatch(id)
if (watchCleared) {
call.sendSuccess()
} else {
call.sendError(GeolocationErrors.WATCH_ID_NOT_FOUND)
}
}
}
/**
* Gets the appropriate permission alias
* @param call the plugin call
* @return String with correct alias
*/
private fun getAlias(call: PluginCall): String {
var alias = LOCATION_ALIAS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val enableHighAccuracy = call.getBoolean("enableHighAccuracy") ?: false
if (!enableHighAccuracy) {
alias = COARSE_LOCATION_ALIAS
}
}
return alias
}
/**
* Gets the current position
* @param call the plugin call
*/
private fun getPosition(call: PluginCall) {
coroutineScope.launch {
val locationOptions = createOptions(call)
// call getCurrentPosition method from controller
val locationResult = controller.getCurrentPosition(activity, locationOptions)
locationResult
.onSuccess { location ->
call.sendSuccess(getJSObjectForLocation(location))
}
.onFailure { exception ->
onLocationError(exception, call)
}
}
}
/**
* Starts watching the device's location by requesting location updates
* @param call the plugin call
*/
private fun startWatch(call: PluginCall) {
coroutineScope.launch {
val watchId = call.callbackId
val locationOptions = createOptions(call)
// call addWatch method from controller
controller.addWatch(activity, locationOptions, watchId).collect { result ->
result.onSuccess { locationList ->
locationList.forEach { locationResult ->
call.sendSuccess(
result = getJSObjectForLocation(locationResult),
keepCallback = true)
}
}
result.onFailure { exception ->
onLocationError(exception, call)
}
}
}
watchingCalls[call.callbackId] = call
}
/**
* Helper function to convert IONGLOCLocationResult object into the format accepted by the Capacitor bridge
* @param locationResult IONGLOCLocationResult object with the location to convert
* @return JSObject with converted JSON object
*/
private fun getJSObjectForLocation(locationResult: IONGLOCLocationResult): JSObject {
val coords = JSObject().apply {
put("latitude", locationResult.latitude)
put("longitude", locationResult.longitude)
put("accuracy", locationResult.accuracy)
put("altitude", locationResult.altitude)
locationResult.altitudeAccuracy?.let { put("altitudeAccuracy", it) }
put("speed", locationResult.speed)
put("heading", locationResult.heading)
}
return JSObject().apply {
put("timestamp", locationResult.timestamp)
put("coords", coords)
}
}
/**
* Helper function to handle error cases
* @param exception Throwable to handle as an error
* @param call the plugin call
*/
private fun onLocationError(exception: Throwable?, call: PluginCall) {
when (exception) {
is IONGLOCException.IONGLOCRequestDeniedException -> {
call.sendError(GeolocationErrors.LOCATION_ENABLE_REQUEST_DENIED)
}
is IONGLOCException.IONGLOCSettingsException -> {
call.sendError(GeolocationErrors.LOCATION_SETTINGS_ERROR)
}
is IONGLOCException.IONGLOCInvalidTimeoutException -> {
call.sendError(GeolocationErrors.INVALID_TIMEOUT)
}
is IONGLOCException.IONGLOCGoogleServicesException -> {
if (exception.resolvable) {
call.sendError(GeolocationErrors.GOOGLE_SERVICES_RESOLVABLE)
} else {
call.sendError(GeolocationErrors.GOOGLE_SERVICES_ERROR)
}
}
is IONGLOCException.IONGLOCLocationRetrievalTimeoutException -> {
call.sendError(GeolocationErrors.GET_LOCATION_TIMEOUT)
}
else -> {
call.sendError(GeolocationErrors.POSITION_UNAVAILABLE)
}
}
}
/**
* Extension function to return a successful plugin result
* @param result JSOObject with the JSON content to return
* @param keepCallback boolean to determine if callback should be kept for future calls or not
*/
private fun PluginCall.sendSuccess(result: JSObject? = null, keepCallback: Boolean? = false) {
this.setKeepAlive(keepCallback)
if (result != null) {
this.resolve(result)
} else {
this.resolve()
}
}
/**
* Extension function to return a unsuccessful plugin result
* @param error error class representing the error to return, containing a code and message
*/
private fun PluginCall.sendError(error: GeolocationErrors.ErrorInfo) {
this.reject(error.message, error.code)
}
/**
* Creates the location options to pass to the native controller
* @param call the plugin call
* @return IONGLOCLocationOptions object
*/
private fun createOptions(call: PluginCall): IONGLOCLocationOptions {
val timeout = call.getNumber("timeout", 10000)
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)
return locationOptions
}
private fun PluginCall.getNumber(name: String, defaultValue: Long): Long =
getLong(name) ?: getInt(name)?.toLong() ?: defaultValue
}

View File

376
node_modules/@capacitor/geolocation/dist/docs.json generated vendored Normal file
View File

@@ -0,0 +1,376 @@
{
"api": {
"name": "GeolocationPlugin",
"slug": "geolocationplugin",
"docs": "",
"tags": [],
"methods": [
{
"name": "getCurrentPosition",
"signature": "(options?: PositionOptions | undefined) => Promise<Position>",
"parameters": [
{
"name": "options",
"docs": "",
"type": "PositionOptions | undefined"
}
],
"returns": "Promise<Position>",
"tags": [
{
"name": "since",
"text": "1.0.0"
}
],
"docs": "Get the current GPS location of the device",
"complexTypes": [
"Position",
"PositionOptions"
],
"slug": "getcurrentposition"
},
{
"name": "watchPosition",
"signature": "(options: PositionOptions, callback: WatchPositionCallback) => Promise<CallbackID>",
"parameters": [
{
"name": "options",
"docs": "",
"type": "PositionOptions"
},
{
"name": "callback",
"docs": "",
"type": "WatchPositionCallback"
}
],
"returns": "Promise<string>",
"tags": [
{
"name": "since",
"text": "1.0.0"
}
],
"docs": "Set up a watch for location changes. Note that watching for location changes\ncan consume a large amount of energy. Be smart about listening only when you need to.",
"complexTypes": [
"PositionOptions",
"WatchPositionCallback",
"CallbackID"
],
"slug": "watchposition"
},
{
"name": "clearWatch",
"signature": "(options: ClearWatchOptions) => Promise<void>",
"parameters": [
{
"name": "options",
"docs": "",
"type": "ClearWatchOptions"
}
],
"returns": "Promise<void>",
"tags": [
{
"name": "since",
"text": "1.0.0"
}
],
"docs": "Clear a given watch",
"complexTypes": [
"ClearWatchOptions"
],
"slug": "clearwatch"
},
{
"name": "checkPermissions",
"signature": "() => Promise<PermissionStatus>",
"parameters": [],
"returns": "Promise<PermissionStatus>",
"tags": [
{
"name": "since",
"text": "1.0.0"
}
],
"docs": "Check location permissions. Will throw if system location services are disabled.",
"complexTypes": [
"PermissionStatus"
],
"slug": "checkpermissions"
},
{
"name": "requestPermissions",
"signature": "(permissions?: GeolocationPluginPermissions | undefined) => Promise<PermissionStatus>",
"parameters": [
{
"name": "permissions",
"docs": "",
"type": "GeolocationPluginPermissions | undefined"
}
],
"returns": "Promise<PermissionStatus>",
"tags": [
{
"name": "since",
"text": "1.0.0"
}
],
"docs": "Request location permissions. Will throw if system location services are disabled.\n\nNot available on web.",
"complexTypes": [
"PermissionStatus",
"GeolocationPluginPermissions"
],
"slug": "requestpermissions"
}
],
"properties": []
},
"interfaces": [
{
"name": "Position",
"slug": "position",
"docs": "",
"tags": [],
"methods": [],
"properties": [
{
"name": "timestamp",
"tags": [
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "Creation timestamp for coords",
"complexTypes": [],
"type": "number"
},
{
"name": "coords",
"tags": [
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "The GPS coordinates along with the accuracy of the data",
"complexTypes": [],
"type": "{ latitude: number; longitude: number; accuracy: number; altitudeAccuracy: number | null | undefined; altitude: number | null; speed: number | null; heading: number | null; }"
}
]
},
{
"name": "PositionOptions",
"slug": "positionoptions",
"docs": "",
"tags": [],
"methods": [],
"properties": [
{
"name": "enableHighAccuracy",
"tags": [
{
"text": "false",
"name": "default"
},
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "High accuracy mode (such as GPS, if available)\n\nOn Android 12+ devices it will be ignored if users didn't grant\nACCESS_FINE_LOCATION permissions (can be checked with location alias).",
"complexTypes": [],
"type": "boolean | undefined"
},
{
"name": "timeout",
"tags": [
{
"text": "10000",
"name": "default"
},
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "The maximum wait time in milliseconds for location updates.\n\nIn Android, since version 7.1.0 of the plugin, it is also used to determine the\ninterval of location updates for `watchPosition`.",
"complexTypes": [],
"type": "number | undefined"
},
{
"name": "maximumAge",
"tags": [
{
"text": "0",
"name": "default"
},
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "The maximum age in milliseconds of a possible cached position that is acceptable to return",
"complexTypes": [],
"type": "number | undefined"
},
{
"name": "minimumUpdateInterval",
"tags": [
{
"text": "5000",
"name": "default"
},
{
"text": "6.1.0",
"name": "since"
}
],
"docs": "The minumum update interval for location updates.\n\nIf location updates are available faster than this interval then an update\nwill only occur if the minimum update interval has expired since the last location update.\n\nThis parameter is only available for Android. It has no effect on iOS or Web platforms.",
"complexTypes": [],
"type": "number | undefined"
}
]
},
{
"name": "ClearWatchOptions",
"slug": "clearwatchoptions",
"docs": "",
"tags": [],
"methods": [],
"properties": [
{
"name": "id",
"tags": [],
"docs": "",
"complexTypes": [
"CallbackID"
],
"type": "CallbackID"
}
]
},
{
"name": "PermissionStatus",
"slug": "permissionstatus",
"docs": "",
"tags": [],
"methods": [],
"properties": [
{
"name": "location",
"tags": [
{
"text": "1.0.0",
"name": "since"
}
],
"docs": "Permission state for location alias.\n\nOn Android it requests/checks both ACCESS_COARSE_LOCATION and\nACCESS_FINE_LOCATION permissions.\n\nOn iOS and web it requests/checks location permission.",
"complexTypes": [
"PermissionState"
],
"type": "PermissionState"
},
{
"name": "coarseLocation",
"tags": [
{
"text": "1.2.0",
"name": "since"
}
],
"docs": "Permission state for coarseLocation alias.\n\nOn Android it requests/checks ACCESS_COARSE_LOCATION.\n\nOn Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) or\nPrecise location (ACCESS_FINE_LOCATION), so this alias can be used if the app doesn't\nneed high accuracy.\n\nOn iOS and web it will have the same value as location alias.",
"complexTypes": [
"PermissionState"
],
"type": "PermissionState"
}
]
},
{
"name": "GeolocationPluginPermissions",
"slug": "geolocationpluginpermissions",
"docs": "",
"tags": [],
"methods": [],
"properties": [
{
"name": "permissions",
"tags": [],
"docs": "",
"complexTypes": [
"GeolocationPermissionType"
],
"type": "GeolocationPermissionType[]"
}
]
}
],
"enums": [],
"typeAliases": [
{
"name": "WatchPositionCallback",
"slug": "watchpositioncallback",
"docs": "",
"types": [
{
"text": "(position: Position | null, err?: any): void",
"complexTypes": [
"Position"
]
}
]
},
{
"name": "CallbackID",
"slug": "callbackid",
"docs": "",
"types": [
{
"text": "string",
"complexTypes": []
}
]
},
{
"name": "PermissionState",
"slug": "permissionstate",
"docs": "",
"types": [
{
"text": "'prompt'",
"complexTypes": []
},
{
"text": "'prompt-with-rationale'",
"complexTypes": []
},
{
"text": "'granted'",
"complexTypes": []
},
{
"text": "'denied'",
"complexTypes": []
}
]
},
{
"name": "GeolocationPermissionType",
"slug": "geolocationpermissiontype",
"docs": "",
"types": [
{
"text": "'location'",
"complexTypes": []
},
{
"text": "'coarseLocation'",
"complexTypes": []
}
]
}
],
"pluginConfigs": []
}

View File

@@ -0,0 +1,187 @@
import type { PermissionState } from '@capacitor/core';
export type CallbackID = string;
export interface PermissionStatus {
/**
* Permission state for location alias.
*
* On Android it requests/checks both ACCESS_COARSE_LOCATION and
* ACCESS_FINE_LOCATION permissions.
*
* On iOS and web it requests/checks location permission.
*
* @since 1.0.0
*/
location: PermissionState;
/**
* Permission state for coarseLocation alias.
*
* On Android it requests/checks ACCESS_COARSE_LOCATION.
*
* On Android 12+, users can choose between Approximate location (ACCESS_COARSE_LOCATION) or
* Precise location (ACCESS_FINE_LOCATION), so this alias can be used if the app doesn't
* need high accuracy.
*
* On iOS and web it will have the same value as location alias.
*
* @since 1.2.0
*/
coarseLocation: PermissionState;
}
export type GeolocationPermissionType = 'location' | 'coarseLocation';
export interface GeolocationPluginPermissions {
permissions: GeolocationPermissionType[];
}
export interface GeolocationPlugin {
/**
* Get the current GPS location of the device
*
* @since 1.0.0
*/
getCurrentPosition(options?: PositionOptions): Promise<Position>;
/**
* Set up a watch for location changes. Note that watching for location changes
* can consume a large amount of energy. Be smart about listening only when you need to.
*
* @since 1.0.0
*/
watchPosition(options: PositionOptions, callback: WatchPositionCallback): Promise<CallbackID>;
/**
* Clear a given watch
*
* @since 1.0.0
*/
clearWatch(options: ClearWatchOptions): Promise<void>;
/**
* Check location permissions. Will throw if system location services are disabled.
*
* @since 1.0.0
*/
checkPermissions(): Promise<PermissionStatus>;
/**
* Request location permissions. Will throw if system location services are disabled.
*
* Not available on web.
*
* @since 1.0.0
*/
requestPermissions(permissions?: GeolocationPluginPermissions): Promise<PermissionStatus>;
}
export interface ClearWatchOptions {
id: CallbackID;
}
export interface Position {
/**
* Creation timestamp for coords
*
* @since 1.0.0
*/
timestamp: number;
/**
* The GPS coordinates along with the accuracy of the data
*
* @since 1.0.0
*/
coords: {
/**
* Latitude in decimal degrees
*
* @since 1.0.0
*/
latitude: number;
/**
* longitude in decimal degrees
*
* @since 1.0.0
*/
longitude: number;
/**
* Accuracy level of the latitude and longitude coordinates in meters
*
* @since 1.0.0
*/
accuracy: number;
/**
* Accuracy level of the altitude coordinate in meters, if available.
*
* Available on all iOS versions and on Android 8.0+.
*
* @since 1.0.0
*/
altitudeAccuracy: number | null | undefined;
/**
* The altitude the user is at (if available)
*
* @since 1.0.0
*/
altitude: number | null;
/**
* The speed the user is traveling (if available)
*
* @since 1.0.0
*/
speed: number | null;
/**
* The heading the user is facing (if available)
*
* @since 1.0.0
*/
heading: number | null;
};
}
export interface PositionOptions {
/**
* 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 7.1.0 of the plugin, it is also used to determine the
* interval of location updates for `watchPosition`.
*
* @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;
}
export type WatchPositionCallback = (position: Position | null, err?: any) => void;
/**
* @deprecated Use `PositionOptions`.
* @since 1.0.0
*/
export type GeolocationOptions = PositionOptions;
/**
* @deprecated Use `WatchPositionCallback`.
* @since 1.0.0
*/
export type GeolocationWatchCallback = WatchPositionCallback;
/**
* @deprecated Use `Position`.
* @since 1.0.0
*/
export type GeolocationPosition = Position;

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=definitions.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
import type { GeolocationPlugin } from './definitions';
declare const Geolocation: GeolocationPlugin;
export * from './definitions';
export { Geolocation };

View File

@@ -0,0 +1,9 @@
import { registerPlugin } from '@capacitor/core';
import { exposeSynapse } from '@capacitor/synapse';
const Geolocation = registerPlugin('Geolocation', {
web: () => import('./web').then((m) => new m.GeolocationWeb()),
});
exposeSynapse();
export * from './definitions';
export { Geolocation };
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,MAAM,WAAW,GAAG,cAAc,CAAoB,aAAa,EAAE;IACnE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;CAC/D,CAAC,CAAC;AAEH,aAAa,EAAE,CAAC;AAEhB,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\n\nimport type { GeolocationPlugin } from './definitions';\n\nconst Geolocation = registerPlugin<GeolocationPlugin>('Geolocation', {\n web: () => import('./web').then((m) => new m.GeolocationWeb()),\n});\n\nexposeSynapse();\n\nexport * from './definitions';\nexport { Geolocation };\n"]}

13
node_modules/@capacitor/geolocation/dist/esm/web.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { WebPlugin } from '@capacitor/core';
import type { CallbackID, GeolocationPlugin, PermissionStatus, Position, PositionOptions, WatchPositionCallback } from './definitions';
export declare class GeolocationWeb extends WebPlugin implements GeolocationPlugin {
getCurrentPosition(options?: PositionOptions): Promise<Position>;
watchPosition(options: PositionOptions, callback: WatchPositionCallback): Promise<CallbackID>;
clearWatch(options: {
id: string;
}): Promise<void>;
checkPermissions(): Promise<PermissionStatus>;
requestPermissions(): Promise<PermissionStatus>;
}
declare const Geolocation: GeolocationWeb;
export { Geolocation };

38
node_modules/@capacitor/geolocation/dist/esm/web.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
import { WebPlugin } from '@capacitor/core';
export class GeolocationWeb extends WebPlugin {
async getCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((pos) => {
resolve(pos);
}, (err) => {
reject(err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0 }, options));
});
}
async watchPosition(options, callback) {
const id = navigator.geolocation.watchPosition((pos) => {
callback(pos);
}, (err) => {
callback(null, err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0, minimumUpdateInterval: 5000 }, options));
return `${id}`;
}
async clearWatch(options) {
navigator.geolocation.clearWatch(parseInt(options.id, 10));
}
async checkPermissions() {
if (typeof navigator === 'undefined' || !navigator.permissions) {
throw this.unavailable('Permissions API not available in this browser');
}
const permission = await navigator.permissions.query({
name: 'geolocation',
});
return { location: permission.state, coarseLocation: permission.state };
}
async requestPermissions() {
throw this.unimplemented('Not implemented on web.');
}
}
const Geolocation = new GeolocationWeb();
export { Geolocation };
//# sourceMappingURL=web.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAW5C,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C,KAAK,CAAC,kBAAkB,CAAC,OAAyB;QAChD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,SAAS,CAAC,WAAW,CAAC,kBAAkB,CACtC,CAAC,GAAG,EAAE,EAAE;gBACN,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,EACD,CAAC,GAAG,EAAE,EAAE;gBACN,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,kBAEC,kBAAkB,EAAE,KAAK,EACzB,OAAO,EAAE,KAAK,EACd,UAAU,EAAE,CAAC,IACV,OAAO,EAEb,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB,EAAE,QAA+B;QAC3E,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAC5C,CAAC,GAAG,EAAE,EAAE;YACN,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,EACD,CAAC,GAAG,EAAE,EAAE;YACN,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACtB,CAAC,kBAEC,kBAAkB,EAAE,KAAK,EACzB,OAAO,EAAE,KAAK,EACd,UAAU,EAAE,CAAC,EACb,qBAAqB,EAAE,IAAI,IACxB,OAAO,EAEb,CAAC;QAEF,OAAO,GAAG,EAAE,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAuB;QACtC,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YAC/D,MAAM,IAAI,CAAC,WAAW,CAAC,+CAA+C,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;YACnD,IAAI,EAAE,aAAa;SACpB,CAAC,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;IACtD,CAAC;CACF;AAED,MAAM,WAAW,GAAG,IAAI,cAAc,EAAE,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,CAAC","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n CallbackID,\n GeolocationPlugin,\n PermissionStatus,\n Position,\n PositionOptions,\n WatchPositionCallback,\n} from './definitions';\n\nexport class GeolocationWeb extends WebPlugin implements GeolocationPlugin {\n async getCurrentPosition(options?: PositionOptions): Promise<Position> {\n return new Promise((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(\n (pos) => {\n resolve(pos);\n },\n (err) => {\n reject(err);\n },\n {\n enableHighAccuracy: false,\n timeout: 10000,\n maximumAge: 0,\n ...options,\n },\n );\n });\n }\n\n async watchPosition(options: PositionOptions, callback: WatchPositionCallback): Promise<CallbackID> {\n const id = navigator.geolocation.watchPosition(\n (pos) => {\n callback(pos);\n },\n (err) => {\n callback(null, err);\n },\n {\n enableHighAccuracy: false,\n timeout: 10000,\n maximumAge: 0,\n minimumUpdateInterval: 5000,\n ...options,\n },\n );\n\n return `${id}`;\n }\n\n async clearWatch(options: { id: string }): Promise<void> {\n navigator.geolocation.clearWatch(parseInt(options.id, 10));\n }\n\n async checkPermissions(): Promise<PermissionStatus> {\n if (typeof navigator === 'undefined' || !navigator.permissions) {\n throw this.unavailable('Permissions API not available in this browser');\n }\n\n const permission = await navigator.permissions.query({\n name: 'geolocation',\n });\n return { location: permission.state, coarseLocation: permission.state };\n }\n\n async requestPermissions(): Promise<PermissionStatus> {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n\nconst Geolocation = new GeolocationWeb();\n\nexport { Geolocation };\n"]}

56
node_modules/@capacitor/geolocation/dist/plugin.cjs.js generated vendored Normal file
View File

@@ -0,0 +1,56 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var core = require('@capacitor/core');
var synapse = require('@capacitor/synapse');
const Geolocation$1 = core.registerPlugin('Geolocation', {
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.GeolocationWeb()),
});
synapse.exposeSynapse();
class GeolocationWeb extends core.WebPlugin {
async getCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((pos) => {
resolve(pos);
}, (err) => {
reject(err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0 }, options));
});
}
async watchPosition(options, callback) {
const id = navigator.geolocation.watchPosition((pos) => {
callback(pos);
}, (err) => {
callback(null, err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0, minimumUpdateInterval: 5000 }, options));
return `${id}`;
}
async clearWatch(options) {
navigator.geolocation.clearWatch(parseInt(options.id, 10));
}
async checkPermissions() {
if (typeof navigator === 'undefined' || !navigator.permissions) {
throw this.unavailable('Permissions API not available in this browser');
}
const permission = await navigator.permissions.query({
name: 'geolocation',
});
return { location: permission.state, coarseLocation: permission.state };
}
async requestPermissions() {
throw this.unimplemented('Not implemented on web.');
}
}
const Geolocation = new GeolocationWeb();
var web = /*#__PURE__*/Object.freeze({
__proto__: null,
GeolocationWeb: GeolocationWeb,
Geolocation: Geolocation
});
exports.Geolocation = Geolocation$1;
//# sourceMappingURL=plugin.cjs.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\nconst Geolocation = registerPlugin('Geolocation', {\n web: () => import('./web').then((m) => new m.GeolocationWeb()),\n});\nexposeSynapse();\nexport * from './definitions';\nexport { Geolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class GeolocationWeb extends WebPlugin {\n async getCurrentPosition(options) {\n return new Promise((resolve, reject) => {\n navigator.geolocation.getCurrentPosition((pos) => {\n resolve(pos);\n }, (err) => {\n reject(err);\n }, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0 }, options));\n });\n }\n async watchPosition(options, callback) {\n const id = navigator.geolocation.watchPosition((pos) => {\n callback(pos);\n }, (err) => {\n callback(null, err);\n }, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0, minimumUpdateInterval: 5000 }, options));\n return `${id}`;\n }\n async clearWatch(options) {\n navigator.geolocation.clearWatch(parseInt(options.id, 10));\n }\n async checkPermissions() {\n if (typeof navigator === 'undefined' || !navigator.permissions) {\n throw this.unavailable('Permissions API not available in this browser');\n }\n const permission = await navigator.permissions.query({\n name: 'geolocation',\n });\n return { location: permission.state, coarseLocation: permission.state };\n }\n async requestPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\nconst Geolocation = new GeolocationWeb();\nexport { Geolocation };\n//# sourceMappingURL=web.js.map"],"names":["Geolocation","registerPlugin","exposeSynapse","WebPlugin"],"mappings":";;;;;;;AAEK,MAACA,aAAW,GAAGC,mBAAc,CAAC,aAAa,EAAE;AAClD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;AAClE,CAAC,EAAE;AACHC,qBAAa,EAAE;;ACJR,MAAM,cAAc,SAASC,cAAS,CAAC;AAC9C,IAAI,MAAM,kBAAkB,CAAC,OAAO,EAAE;AACtC,QAAQ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AAChD,YAAY,SAAS,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,GAAG,KAAK;AAC9D,gBAAgB,OAAO,CAAC,GAAG,CAAC,CAAC;AAC7B,aAAa,EAAE,CAAC,GAAG,KAAK;AACxB,gBAAgB,MAAM,CAAC,GAAG,CAAC,CAAC;AAC5B,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;AACrG,SAAS,CAAC,CAAC;AACX,KAAK;AACL,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE;AAC3C,QAAQ,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,GAAG,KAAK;AAChE,YAAY,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC1B,SAAS,EAAE,CAAC,GAAG,KAAK;AACpB,YAAY,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAChC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,qBAAqB,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;AAC9H,QAAQ,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACvB,KAAK;AACL,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;AAC9B,QAAQ,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnE,KAAK;AACL,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;AACxE,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,+CAA+C,CAAC,CAAC;AACpF,SAAS;AACT,QAAQ,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;AAC7D,YAAY,IAAI,EAAE,aAAa;AAC/B,SAAS,CAAC,CAAC;AACX,QAAQ,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;AAChF,KAAK;AACL,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;AAC5D,KAAK;AACL,CAAC;AACD,MAAM,WAAW,GAAG,IAAI,cAAc,EAAE;;;;;;;;;;"}

58
node_modules/@capacitor/geolocation/dist/plugin.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
var capacitorGeolocationPluginCapacitor = (function (exports, core, synapse) {
'use strict';
const Geolocation$1 = core.registerPlugin('Geolocation', {
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.GeolocationWeb()),
});
synapse.exposeSynapse();
class GeolocationWeb extends core.WebPlugin {
async getCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((pos) => {
resolve(pos);
}, (err) => {
reject(err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0 }, options));
});
}
async watchPosition(options, callback) {
const id = navigator.geolocation.watchPosition((pos) => {
callback(pos);
}, (err) => {
callback(null, err);
}, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0, minimumUpdateInterval: 5000 }, options));
return `${id}`;
}
async clearWatch(options) {
navigator.geolocation.clearWatch(parseInt(options.id, 10));
}
async checkPermissions() {
if (typeof navigator === 'undefined' || !navigator.permissions) {
throw this.unavailable('Permissions API not available in this browser');
}
const permission = await navigator.permissions.query({
name: 'geolocation',
});
return { location: permission.state, coarseLocation: permission.state };
}
async requestPermissions() {
throw this.unimplemented('Not implemented on web.');
}
}
const Geolocation = new GeolocationWeb();
var web = /*#__PURE__*/Object.freeze({
__proto__: null,
GeolocationWeb: GeolocationWeb,
Geolocation: Geolocation
});
exports.Geolocation = Geolocation$1;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, capacitorExports, synapse);
//# sourceMappingURL=plugin.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nimport { exposeSynapse } from '@capacitor/synapse';\nconst Geolocation = registerPlugin('Geolocation', {\n web: () => import('./web').then((m) => new m.GeolocationWeb()),\n});\nexposeSynapse();\nexport * from './definitions';\nexport { Geolocation };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class GeolocationWeb extends WebPlugin {\n async getCurrentPosition(options) {\n return new Promise((resolve, reject) => {\n navigator.geolocation.getCurrentPosition((pos) => {\n resolve(pos);\n }, (err) => {\n reject(err);\n }, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0 }, options));\n });\n }\n async watchPosition(options, callback) {\n const id = navigator.geolocation.watchPosition((pos) => {\n callback(pos);\n }, (err) => {\n callback(null, err);\n }, Object.assign({ enableHighAccuracy: false, timeout: 10000, maximumAge: 0, minimumUpdateInterval: 5000 }, options));\n return `${id}`;\n }\n async clearWatch(options) {\n navigator.geolocation.clearWatch(parseInt(options.id, 10));\n }\n async checkPermissions() {\n if (typeof navigator === 'undefined' || !navigator.permissions) {\n throw this.unavailable('Permissions API not available in this browser');\n }\n const permission = await navigator.permissions.query({\n name: 'geolocation',\n });\n return { location: permission.state, coarseLocation: permission.state };\n }\n async requestPermissions() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\nconst Geolocation = new GeolocationWeb();\nexport { Geolocation };\n//# sourceMappingURL=web.js.map"],"names":["Geolocation","registerPlugin","exposeSynapse","WebPlugin"],"mappings":";;;AAEK,UAACA,aAAW,GAAGC,mBAAc,CAAC,aAAa,EAAE;IAClD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;IAClE,CAAC,EAAE;AACHC,yBAAa,EAAE;;ICJR,MAAM,cAAc,SAASC,cAAS,CAAC;IAC9C,IAAI,MAAM,kBAAkB,CAAC,OAAO,EAAE;IACtC,QAAQ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;IAChD,YAAY,SAAS,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,GAAG,KAAK;IAC9D,gBAAgB,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,aAAa,EAAE,CAAC,GAAG,KAAK;IACxB,gBAAgB,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IACrG,SAAS,CAAC,CAAC;IACX,KAAK;IACL,IAAI,MAAM,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE;IAC3C,QAAQ,MAAM,EAAE,GAAG,SAAS,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,GAAG,KAAK;IAChE,YAAY,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC1B,SAAS,EAAE,CAAC,GAAG,KAAK;IACpB,YAAY,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,qBAAqB,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9H,QAAQ,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACvB,KAAK;IACL,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;IAC9B,QAAQ,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACnE,KAAK;IACL,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;IACxE,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,+CAA+C,CAAC,CAAC;IACpF,SAAS;IACT,QAAQ,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;IAC7D,YAAY,IAAI,EAAE,aAAa;IAC/B,SAAS,CAAC,CAAC;IACX,QAAQ,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAChF,KAAK;IACL,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;IAC5D,KAAK;IACL,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,cAAc,EAAE;;;;;;;;;;;;;;;;;;"}

View File

@@ -0,0 +1,154 @@
import Capacitor
import IONGeolocationLib
private enum GeolocationCallbackType {
case requestPermissions
case location
case watch
var shouldKeepCallback: Bool {
self == .watch
}
var shouldClearAfterSending: Bool {
self == .location || self == .requestPermissions
}
}
private struct GeolocationCallbackGroup {
let ids: [CAPPluginCall]
let type: GeolocationCallbackType
}
final class GeolocationCallbackManager {
private(set) var requestPermissionsCallbacks: [CAPPluginCall]
private(set) var locationCallbacks: [CAPPluginCall]
private(set) var watchCallbacks: [String: CAPPluginCall]
private let capacitorBridge: CAPBridgeProtocol?
private var allCallbackGroups: [GeolocationCallbackGroup] {
[
.init(ids: requestPermissionsCallbacks, type: .requestPermissions),
.init(ids: locationCallbacks, type: .location),
.init(ids: Array(watchCallbacks.values), type: .watch)
]
}
private var requestPermissionsCallbackGroup: GeolocationCallbackGroup? {
allCallbackGroups.first { $0.type == .requestPermissions }
}
init(capacitorBridge: CAPBridgeProtocol?) {
self.capacitorBridge = capacitorBridge
self.requestPermissionsCallbacks = []
self.locationCallbacks = []
self.watchCallbacks = [:]
}
func addRequestPermissionsCallback(capacitorCall call: CAPPluginCall) {
capacitorBridge?.saveCall(call)
requestPermissionsCallbacks.append(call)
}
func addLocationCallback(capacitorCall call: CAPPluginCall) {
capacitorBridge?.saveCall(call)
locationCallbacks.append(call)
}
func addWatchCallback(_ watchId: String, capacitorCall call: CAPPluginCall) {
capacitorBridge?.saveCall(call)
watchCallbacks[watchId] = call
}
func clearRequestPermissionsCallbacks() {
requestPermissionsCallbacks.forEach {
capacitorBridge?.releaseCall($0)
}
requestPermissionsCallbacks.removeAll()
}
func clearWatchCallbackIfExists(_ watchId: String) {
if let callbackToRemove = watchCallbacks[watchId] {
capacitorBridge?.releaseCall(callbackToRemove)
watchCallbacks.removeValue(forKey: watchId)
}
}
func clearLocationCallbacks() {
locationCallbacks.forEach {
capacitorBridge?.releaseCall($0)
}
locationCallbacks.removeAll()
}
func sendSuccess(_ call: CAPPluginCall) {
call.resolve()
}
func sendSuccess(_ call: CAPPluginCall, with data: PluginCallResultData) {
call.resolve(data)
}
func sendRequestPermissionsSuccess(_ permissionsResult: String) {
if let group = requestPermissionsCallbackGroup {
let data = [
Constants.AuthorisationStatus.ResultKey.location: permissionsResult,
Constants.AuthorisationStatus.ResultKey.coarseLocation: permissionsResult
]
send(.success(data), to: group)
}
}
func sendSuccess(with position: IONGLOCPositionModel) {
createPluginResult(status: .success(position.toJSObject()))
}
func sendError(_ call: CAPPluginCall, error: GeolocationError) {
let errorModel = error.toCodeMessagePair()
call.reject(errorModel.1, errorModel.0)
}
func sendError(_ error: GeolocationError) {
createPluginResult(status: .error(error.toCodeMessagePair()))
}
}
private enum CallResultStatus {
typealias SuccessModel = JSObject
typealias ErrorModel = (code: String, message: String)
case success(_ data: SuccessModel)
case error(_ codeAndMessage: ErrorModel)
}
private extension GeolocationCallbackManager {
func createPluginResult(status: CallResultStatus) {
allCallbackGroups.forEach {
send(status, to: $0)
}
}
func send(_ callResultStatus: CallResultStatus, to group: GeolocationCallbackGroup) {
group.ids.forEach { call in
call.keepAlive = group.type.shouldKeepCallback
switch callResultStatus {
case .success(let data):
call.resolve(data)
case .error(let error):
call.reject(error.message, error.code)
}
}
if group.type.shouldClearAfterSending {
clearCallbacks(for: group.type)
}
}
func clearCallbacks(for type: GeolocationCallbackType) {
if case .location = type {
clearLocationCallbacks()
} else if case .requestPermissions = type {
clearRequestPermissionsCallbacks()
}
}
}

View File

@@ -0,0 +1,36 @@
enum Constants {
enum Arguments {
static let enableHighAccuracy = "enableHighAccuracy"
static let id = "id"
}
enum AuthorisationStatus {
enum ResultKey {
static let location = "location"
static let coarseLocation = "coarseLocation"
}
enum Status {
static let denied: String = "denied"
static let granted: String = "granted"
static let prompt: String = "prompt"
}
}
enum LocationUsageDescription {
static let always: String = "NSLocationAlwaysAndWhenInUseUsageDescription"
static let whenInUse: String = "NSLocationWhenInUseUsageDescription"
}
enum Position {
static let altitude: String = "altitude"
static let coords: String = "coords"
static let heading: String = "heading"
static let accuracy: String = "accuracy"
static let latitude: String = "latitude"
static let longitude: String = "longitude"
static let speed: String = "speed"
static let timestamp: String = "timestamp"
static let altitudeAccuracy: String = "altitudeAccuracy"
}
}

View File

@@ -0,0 +1,44 @@
enum GeolocationMethod: String {
case getCurrentPosition
case watchPosition
case clearWatch
}
enum GeolocationError: Error {
case locationServicesDisabled
case permissionDenied
case permissionRestricted
case positionUnavailable
case inputArgumentsIssue(target: GeolocationMethod)
func toCodeMessagePair() -> (String, String) {
("OS-PLUG-GLOC-\(String(format: "%04d", code))", description)
}
}
private extension GeolocationError {
var code: Int {
switch self {
case .positionUnavailable: 2
case .permissionDenied: 3
case .locationServicesDisabled: 7
case .permissionRestricted: 8
case .inputArgumentsIssue(let target):
switch target {
case .getCurrentPosition: 4
case .watchPosition: 5
case .clearWatch: 6
}
}
}
var description: String {
switch self {
case .positionUnavailable: "There was en 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."
}
}
}

View File

@@ -0,0 +1,228 @@
import Capacitor
import IONGeolocationLib
import UIKit
import Combine
@objc(GeolocationPlugin)
public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "GeolocationPlugin"
public let jsName = "Geolocation"
public let pluginMethods: [CAPPluginMethod] = [
.init(name: "getCurrentPosition", returnType: CAPPluginReturnPromise),
.init(name: "watchPosition", returnType: CAPPluginReturnCallback),
.init(name: "clearWatch", returnType: CAPPluginReturnPromise),
.init(name: "checkPermissions", returnType: CAPPluginReturnPromise),
.init(name: "requestPermissions", returnType: CAPPluginReturnPromise)
]
private var locationService: (any IONGLOCService)?
private var cancellables = Set<AnyCancellable>()
private var locationCancellable: 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),
name: UIApplication.didBecomeActiveNotification,
object: nil
)
}
@objc private func appDidBecomeActive() {
if let watchCallbacksEmpty = callbackManager?.watchCallbacks.isEmpty, !watchCallbacksEmpty {
print("App became active. Restarting location monitoring for watch callbacks.")
locationCancellable?.cancel()
locationCancellable = nil
locationInitialized = false
locationService?.stopMonitoringLocation()
locationService?.startMonitoringLocation()
bindLocationPublisher()
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func getCurrentPosition(_ call: CAPPluginCall) {
shouldSetupBindings()
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
handleLocationRequest(enableHighAccuracy, call: call)
}
@objc func watchPosition(_ call: CAPPluginCall) {
shouldSetupBindings()
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
let watchUUID = call.callbackId
handleLocationRequest(enableHighAccuracy, watchUUID: watchUUID, call: call)
}
@objc func clearWatch(_ call: CAPPluginCall) {
shouldSetupBindings()
guard let callbackId = call.getString(Constants.Arguments.id) else {
callbackManager?.sendError(.inputArgumentsIssue(target: .clearWatch))
return
}
callbackManager?.clearWatchCallbackIfExists(callbackId)
if (callbackManager?.watchCallbacks.isEmpty) ?? false {
locationService?.stopMonitoringLocation()
locationCancellable?.cancel()
locationCancellable = nil
locationInitialized = false
}
callbackManager?.sendSuccess(call)
}
@objc override public func checkPermissions(_ call: CAPPluginCall) {
guard checkIfLocationServicesAreEnabled(call) else { return }
let status = switch locationService?.authorisationStatus {
case .restricted, .denied: Constants.AuthorisationStatus.Status.denied
case .authorisedAlways, .authorisedWhenInUse: Constants.AuthorisationStatus.Status.granted
default: Constants.AuthorisationStatus.Status.prompt
}
let callResultData = [
Constants.AuthorisationStatus.ResultKey.location: status,
Constants.AuthorisationStatus.ResultKey.coarseLocation: status
]
callbackManager?.sendSuccess(call, with: callResultData)
}
@objc override public func requestPermissions(_ call: CAPPluginCall) {
guard checkIfLocationServicesAreEnabled(call) else { return }
if locationService?.authorisationStatus == .notDetermined {
shouldSetupBindings()
callbackManager?.addRequestPermissionsCallback(capacitorCall: call)
} else {
checkPermissions(call)
}
}
}
private extension GeolocationPlugin {
func shouldSetupBindings() {
bindAuthorisationStatusPublisher()
bindLocationPublisher()
}
func bindAuthorisationStatusPublisher() {
guard !statusInitialized else { return }
statusInitialized = true
locationService?.authorisationStatusPublisher
.sink(receiveValue: { [weak self] status in
guard let self else { return }
switch status {
case .denied:
self.onLocationPermissionNotGranted(error: .permissionDenied)
case .notDetermined:
self.requestLocationAuthorisation(type: .whenInUse)
case .restricted:
self.onLocationPermissionNotGranted(error: .permissionRestricted)
case .authorisedAlways, .authorisedWhenInUse:
self.onLocationPermissionGranted()
@unknown default: break
}
})
.store(in: &cancellables)
}
func bindLocationPublisher() {
guard !locationInitialized else { return }
locationInitialized = true
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)
return Empty<IONGLOCPositionModel, Never>()
.eraseToAnyPublisher()
} else {
self?.callbackManager?.sendError(.positionUnavailable)
return Empty<IONGLOCPositionModel, Never>()
.eraseToAnyPublisher()
}
}
.sink(receiveValue: { [weak self] position in
self?.callbackManager?.sendSuccess(with: position)
})
}
func requestLocationAuthorisation(type requestType: IONGLOCAuthorisationRequestType) {
DispatchQueue.global(qos: .background).async {
guard self.checkIfLocationServicesAreEnabled() else { return }
self.locationService?.requestAuthorisation(withType: requestType)
}
}
func checkIfLocationServicesAreEnabled(_ call: CAPPluginCall? = nil) -> Bool {
guard locationService?.areLocationServicesEnabled() == true else {
call.map { callbackManager?.sendError($0, error: .locationServicesDisabled) }
?? callbackManager?.sendError(.locationServicesDisabled)
return false
}
return true
}
func onLocationPermissionNotGranted(error: GeolocationError) {
let shouldNotifyRequestPermissionsResult = callbackManager?.requestPermissionsCallbacks.isEmpty == false
let shouldNotifyPermissionError = callbackManager?.locationCallbacks.isEmpty == false || callbackManager?.watchCallbacks.isEmpty == false
if shouldNotifyRequestPermissionsResult {
self.callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.denied)
}
if shouldNotifyPermissionError {
self.callbackManager?.sendError(error)
}
}
func onLocationPermissionGranted() {
let shouldNotifyPermissionGranted = callbackManager?.requestPermissionsCallbacks.isEmpty == false
// should request location if callbacks below exist and are not empty
let shouldRequestCurrentPosition = callbackManager?.locationCallbacks.isEmpty == false
let shouldRequestLocationMonitoring = callbackManager?.watchCallbacks.isEmpty == false
if shouldNotifyPermissionGranted {
callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.granted)
}
if shouldRequestCurrentPosition {
locationService?.requestSingleLocation()
}
if shouldRequestLocationMonitoring {
locationService?.startMonitoringLocation()
}
}
func handleLocationRequest(_ enableHighAccuracy: Bool, watchUUID: String? = nil, call: CAPPluginCall) {
bindLocationPublisher()
let configurationModel = IONGLOCConfigurationModel(enableHighAccuracy: enableHighAccuracy)
locationService?.updateConfiguration(configurationModel)
if let watchUUID {
callbackManager?.addWatchCallback(watchUUID, capacitorCall: call)
} else {
callbackManager?.addLocationCallback(capacitorCall: call)
}
switch locationService?.authorisationStatus {
case .authorisedAlways, .authorisedWhenInUse: onLocationPermissionGranted()
case .denied: callbackManager?.sendError(.permissionDenied)
case .restricted: callbackManager?.sendError(.permissionRestricted)
default: break
}
}
}

View File

@@ -0,0 +1,23 @@
import Capacitor
import IONGeolocationLib
extension IONGLOCPositionModel {
func toJSObject() -> JSObject {
[
Constants.Position.timestamp: timestamp,
Constants.Position.coords: coordsJSObject
]
}
private var coordsJSObject: JSObject {
[
Constants.Position.altitude: altitude,
Constants.Position.heading: course,
Constants.Position.accuracy: horizontalAccuracy,
Constants.Position.latitude: latitude,
Constants.Position.longitude: longitude,
Constants.Position.speed: speed,
Constants.Position.altitudeAccuracy: verticalAccuracy
]
}
}

View File

@@ -0,0 +1,15 @@
import XCTest
@testable import GeolocationCapacitorPlugin
class GeolocationPluginCapacitorTests: XCTestCase {
func testEcho() {
// This is an example of a functional test case for a plugin.
// Use XCTAssert and related functions to verify your tests produce the correct results.
let implementation = GeolocationPluginCapacitor()
let value = "Hello, World!"
let result = implementation.echo(value)
XCTAssertEqual(value, result)
}
}

89
node_modules/@capacitor/geolocation/package.json generated vendored Normal file
View File

@@ -0,0 +1,89 @@
{
"name": "@capacitor/geolocation",
"version": "7.1.5",
"description": "The Geolocation API provides simple methods for getting and tracking the current position of the device using GPS, along with altitude, heading, and speed information if available.",
"main": "dist/plugin.cjs.js",
"module": "dist/esm/index.js",
"types": "dist/esm/index.d.ts",
"unpkg": "dist/plugin.js",
"files": [
"android/src/main/",
"android/build.gradle",
"dist/",
"ios/Sources",
"ios/Tests",
"Package.swift",
"CapacitorGeolocation.podspec"
],
"author": "Outsystems",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/ionic-team/capacitor-geolocation.git"
},
"bugs": {
"url": "https://github.com/ionic-team/capacitor-geolocation/issues"
},
"keywords": [
"capacitor",
"plugin",
"native"
],
"scripts": {
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
"verify:ios": "xcodebuild -scheme CapacitorGeolocation -destination generic/platform=iOS",
"verify:android": "cd android && ./gradlew clean build test && cd ..",
"verify:web": "npm run build",
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
"eslint": "eslint . --ext ts",
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
"swiftlint": "node-swiftlint",
"docgen": "docgen --api GeolocationPlugin --output-readme README.md --output-json dist/docs.json && cp README.md ../../README.md",
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
"clean": "rimraf ./dist",
"watch": "tsc --watch",
"prepublishOnly": "npm run build"
},
"dependencies": {
"@capacitor/synapse": "^1.0.3"
},
"devDependencies": {
"@capacitor/android": "next",
"@capacitor/core": "next",
"@capacitor/docgen": "^0.2.2",
"@capacitor/ios": "next",
"@ionic/eslint-config": "^0.4.0",
"@ionic/prettier-config": "^4.0.0",
"@ionic/swiftlint-config": "^2.0.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^11.0.1",
"@semantic-release/npm": "^12.0.1",
"@types/node": "^20.14.8",
"eslint": "^8.57.0",
"prettier": "^3.3.3",
"prettier-plugin-java": "^2.6.4",
"rimraf": "^6.0.1",
"rollup": "^2.78.1",
"semantic-release": "^24.0.0",
"swiftlint": "^2.0.0",
"typescript": "~5.4.5"
},
"peerDependencies": {
"@capacitor/core": ">=7.0.0"
},
"prettier": "@ionic/prettier-config",
"swiftlint": "@ionic/swiftlint-config",
"eslintConfig": {
"extends": "@ionic/eslint-config/recommended"
},
"capacitor": {
"ios": {
"src": "ios"
},
"android": {
"src": "android"
}
}
}