@nitra/geolocation 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorGeolocation.podspec +18 -0
- package/Package.swift +34 -0
- package/README.md +238 -0
- package/android/build.gradle +72 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationErrors.kt +71 -0
- package/android/src/main/kotlin/com/capacitorjs/plugins/geolocation/GeolocationPlugin.kt +338 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/ios/Sources/GeolocationPlugin/GeolocationCallbackManager.swift +154 -0
- package/ios/Sources/GeolocationPlugin/GeolocationConstants.swift +36 -0
- package/ios/Sources/GeolocationPlugin/GeolocationError.swift +44 -0
- package/ios/Sources/GeolocationPlugin/GeolocationPlugin.swift +184 -0
- package/ios/Sources/GeolocationPlugin/IONGLOCPositionModel+JSONTransformer.swift +23 -0
- package/ios/Tests/GeolocationTests/GeolocationTests.swift +15 -0
- package/package.json +89 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapacitorGeolocation'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '14.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.dependency 'IONGeolocationLib', spec='~> 1.0'
|
|
17
|
+
s.swift_version = '5.1'
|
|
18
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "GeolocationCapacitor",
|
|
6
|
+
platforms: [.iOS(.v13)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "GeolocationCapacitor",
|
|
10
|
+
targets: ["GeolocationPlugin"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", branch: "main")
|
|
14
|
+
],
|
|
15
|
+
targets: [
|
|
16
|
+
.binaryTarget(
|
|
17
|
+
name: "IONGeolocationLib",
|
|
18
|
+
url: "https://github.com/ionic-team/ion-ios-geolocation/releases/download/1.0.0/IONGeolocationLib.zip",
|
|
19
|
+
checksum: "b117d3681a947f5d367e79abdb3bfc9abf7ab070ea5279d7da634ddd2d54ffdb" // sha-256
|
|
20
|
+
),
|
|
21
|
+
.target(
|
|
22
|
+
name: "GeolocationPlugin",
|
|
23
|
+
dependencies: [
|
|
24
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
25
|
+
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
26
|
+
"IONGeolocationLib"
|
|
27
|
+
],
|
|
28
|
+
path: "ios/Sources/GeolocationPlugin"),
|
|
29
|
+
.testTarget(
|
|
30
|
+
name: "GeolocationPluginTests",
|
|
31
|
+
dependencies: ["GeolocationPlugin"],
|
|
32
|
+
path: "ios/Tests/GeolocationTests")
|
|
33
|
+
]
|
|
34
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# @nitra/geolocation
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @nitra/geolocation
|
|
9
|
+
npx cap sync
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## iOS
|
|
13
|
+
|
|
14
|
+
Apple requires privacy descriptions to be specified in `Info.plist` for location information:
|
|
15
|
+
|
|
16
|
+
- `NSLocationAlwaysAndWhenInUseUsageDescription` (`Privacy - Location Always and When In Use Usage Description`)
|
|
17
|
+
- `NSLocationWhenInUseUsageDescription` (`Privacy - Location When In Use Usage Description`)
|
|
18
|
+
|
|
19
|
+
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
|
|
20
|
+
|
|
21
|
+
## Android
|
|
22
|
+
|
|
23
|
+
This plugin requires the following permissions be added to your `AndroidManifest.xml`:
|
|
24
|
+
|
|
25
|
+
```xml
|
|
26
|
+
<!-- Geolocation Plugin -->
|
|
27
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
28
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
29
|
+
<uses-feature android:name="android.hardware.location.gps" />
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
<docgen-index>
|
|
40
|
+
|
|
41
|
+
* [`getCurrentPosition(...)`](#getcurrentposition)
|
|
42
|
+
* [`watchPosition(...)`](#watchposition)
|
|
43
|
+
* [`clearWatch(...)`](#clearwatch)
|
|
44
|
+
* [`checkPermissions()`](#checkpermissions)
|
|
45
|
+
* [`requestPermissions(...)`](#requestpermissions)
|
|
46
|
+
* [Interfaces](#interfaces)
|
|
47
|
+
* [Type Aliases](#type-aliases)
|
|
48
|
+
|
|
49
|
+
</docgen-index>
|
|
50
|
+
|
|
51
|
+
For list of error codes, see [Errors](#errors)
|
|
52
|
+
|
|
53
|
+
<docgen-api>
|
|
54
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
55
|
+
|
|
56
|
+
### getCurrentPosition(...)
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
getCurrentPosition(options?: PositionOptions | undefined) => Promise<Position>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Get the current GPS location of the device
|
|
63
|
+
|
|
64
|
+
| Param | Type |
|
|
65
|
+
| ------------- | ----------------------------------------------------------- |
|
|
66
|
+
| **`options`** | <code><a href="#positionoptions">PositionOptions</a></code> |
|
|
67
|
+
|
|
68
|
+
**Returns:** <code>Promise<<a href="#position">Position</a>></code>
|
|
69
|
+
|
|
70
|
+
**Since:** 1.0.0
|
|
71
|
+
|
|
72
|
+
--------------------
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### watchPosition(...)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
watchPosition(options: PositionOptions, callback: WatchPositionCallback) => Promise<CallbackID>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Set up a watch for location changes. Note that watching for location changes
|
|
82
|
+
can consume a large amount of energy. Be smart about listening only when you need to.
|
|
83
|
+
|
|
84
|
+
| Param | Type |
|
|
85
|
+
| -------------- | ----------------------------------------------------------------------- |
|
|
86
|
+
| **`options`** | <code><a href="#positionoptions">PositionOptions</a></code> |
|
|
87
|
+
| **`callback`** | <code><a href="#watchpositioncallback">WatchPositionCallback</a></code> |
|
|
88
|
+
|
|
89
|
+
**Returns:** <code>Promise<string></code>
|
|
90
|
+
|
|
91
|
+
**Since:** 1.0.0
|
|
92
|
+
|
|
93
|
+
--------------------
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
### clearWatch(...)
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
clearWatch(options: ClearWatchOptions) => Promise<void>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Clear a given watch
|
|
103
|
+
|
|
104
|
+
| Param | Type |
|
|
105
|
+
| ------------- | --------------------------------------------------------------- |
|
|
106
|
+
| **`options`** | <code><a href="#clearwatchoptions">ClearWatchOptions</a></code> |
|
|
107
|
+
|
|
108
|
+
**Since:** 1.0.0
|
|
109
|
+
|
|
110
|
+
--------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
### checkPermissions()
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
checkPermissions() => Promise<PermissionStatus>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Check location permissions. Will throw if system location services are disabled.
|
|
120
|
+
|
|
121
|
+
**Returns:** <code>Promise<<a href="#permissionstatus">PermissionStatus</a>></code>
|
|
122
|
+
|
|
123
|
+
**Since:** 1.0.0
|
|
124
|
+
|
|
125
|
+
--------------------
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
### requestPermissions(...)
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
requestPermissions(permissions?: GeolocationPluginPermissions | undefined) => Promise<PermissionStatus>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Request location permissions. Will throw if system location services are disabled.
|
|
135
|
+
|
|
136
|
+
Not available on web.
|
|
137
|
+
|
|
138
|
+
| Param | Type |
|
|
139
|
+
| ----------------- | ------------------------------------------------------------------------------------- |
|
|
140
|
+
| **`permissions`** | <code><a href="#geolocationpluginpermissions">GeolocationPluginPermissions</a></code> |
|
|
141
|
+
|
|
142
|
+
**Returns:** <code>Promise<<a href="#permissionstatus">PermissionStatus</a>></code>
|
|
143
|
+
|
|
144
|
+
**Since:** 1.0.0
|
|
145
|
+
|
|
146
|
+
--------------------
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### Interfaces
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
#### Position
|
|
153
|
+
|
|
154
|
+
| Prop | Type | Description | Since |
|
|
155
|
+
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----- |
|
|
156
|
+
| **`timestamp`** | <code>number</code> | Creation timestamp for coords | 1.0.0 |
|
|
157
|
+
| **`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 |
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
#### PositionOptions
|
|
161
|
+
|
|
162
|
+
| Prop | Type | Description | Default | Since |
|
|
163
|
+
| --------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
|
|
164
|
+
| **`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 |
|
|
165
|
+
| **`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 |
|
|
166
|
+
| **`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 |
|
|
167
|
+
| **`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 |
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
#### ClearWatchOptions
|
|
171
|
+
|
|
172
|
+
| Prop | Type |
|
|
173
|
+
| -------- | ------------------------------------------------- |
|
|
174
|
+
| **`id`** | <code><a href="#callbackid">CallbackID</a></code> |
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
#### PermissionStatus
|
|
178
|
+
|
|
179
|
+
| Prop | Type | Description | Since |
|
|
180
|
+
| -------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
|
|
181
|
+
| **`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 |
|
|
182
|
+
| **`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 |
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
#### GeolocationPluginPermissions
|
|
186
|
+
|
|
187
|
+
| Prop | Type |
|
|
188
|
+
| ----------------- | ---------------------------------------- |
|
|
189
|
+
| **`permissions`** | <code>GeolocationPermissionType[]</code> |
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
### Type Aliases
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
#### WatchPositionCallback
|
|
196
|
+
|
|
197
|
+
<code>(position: <a href="#position">Position</a> | null, err?: any): void</code>
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
#### CallbackID
|
|
201
|
+
|
|
202
|
+
<code>string</code>
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
#### PermissionState
|
|
206
|
+
|
|
207
|
+
<code>'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'</code>
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
#### GeolocationPermissionType
|
|
211
|
+
|
|
212
|
+
<code>'location' | 'coarseLocation'</code>
|
|
213
|
+
|
|
214
|
+
</docgen-api>
|
|
215
|
+
|
|
216
|
+
### Errors
|
|
217
|
+
|
|
218
|
+
The plugin returns specific errors with specific codes on native Android and iOS. Web does not follow this standard for errors.
|
|
219
|
+
|
|
220
|
+
The following table list all the plugin errors:
|
|
221
|
+
|
|
222
|
+
| Error code | Platform(s) | Message |
|
|
223
|
+
| -------------------- | ------------ | ---------------------------------------- |
|
|
224
|
+
| OS-PLUG-GLOC-0002 | Android, iOS | There was en error trying to obtain the location. |
|
|
225
|
+
| OS-PLUG-GLOC-0003 | Android, iOS | Location permission request was denied. |
|
|
226
|
+
| OS-PLUG-GLOC-0004 | iOS | The 'getCurrentPosition' input parameters aren't valid. |
|
|
227
|
+
| OS-PLUG-GLOC-0005 | iOS | The 'watchPosition' input parameters aren't valid. |
|
|
228
|
+
| OS-PLUG-GLOC-0006 | iOS | The 'clearWatch' input parameters aren't valid. |
|
|
229
|
+
| OS-PLUG-GLOC-0007 | Android, iOS | Location services are not enabled. |
|
|
230
|
+
| OS-PLUG-GLOC-0008 | iOS | Application's use of location services was restricted. |
|
|
231
|
+
| OS-PLUG-GLOC-0009 | Android | Request to enable location was denied. |
|
|
232
|
+
| OS-PLUG-GLOC-0010 | Android | Could not obtain location in time. Try with a higher timeout. |
|
|
233
|
+
| OS-PLUG-GLOC-0011 | Android | Timeout needs to be a positive value. |
|
|
234
|
+
| OS-PLUG-GLOC-0012 | Android | WatchId not found. |
|
|
235
|
+
| OS-PLUG-GLOC-0013 | Android | WatchId needs to be provided. |
|
|
236
|
+
| OS-PLUG-GLOC-0014 | Android | Google Play Services error user resolvable. |
|
|
237
|
+
| OS-PLUG-GLOC-0015 | Android | Google Play Services error. |
|
|
238
|
+
| OS-PLUG-GLOC-0016 | Android | Location settings error. |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
|
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
|
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
|
|
6
|
+
playServicesLocationVersion = project.hasProperty('playServicesLocationVersion') ? rootProject.ext.playServicesLocationVersion : '21.3.0'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
buildscript {
|
|
10
|
+
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.24'
|
|
11
|
+
repositories {
|
|
12
|
+
google()
|
|
13
|
+
mavenCentral()
|
|
14
|
+
}
|
|
15
|
+
dependencies {
|
|
16
|
+
classpath 'com.android.tools.build:gradle:8.7.1'
|
|
17
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply plugin: 'com.android.library'
|
|
22
|
+
apply plugin: 'kotlin-android'
|
|
23
|
+
|
|
24
|
+
android {
|
|
25
|
+
namespace "com.capacitorjs.plugins.geolocation"
|
|
26
|
+
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
|
27
|
+
defaultConfig {
|
|
28
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
|
29
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
|
30
|
+
versionCode 1
|
|
31
|
+
versionName "1.0"
|
|
32
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
33
|
+
}
|
|
34
|
+
buildTypes {
|
|
35
|
+
release {
|
|
36
|
+
minifyEnabled false
|
|
37
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
lintOptions {
|
|
41
|
+
abortOnError false
|
|
42
|
+
}
|
|
43
|
+
compileOptions {
|
|
44
|
+
sourceCompatibility JavaVersion.VERSION_21
|
|
45
|
+
targetCompatibility JavaVersion.VERSION_21
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
kotlin {
|
|
50
|
+
jvmToolchain(21)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
repositories {
|
|
54
|
+
google()
|
|
55
|
+
mavenCentral()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
dependencies {
|
|
60
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
61
|
+
implementation("io.ionic.libs:iongeolocation-android:1.0.0")
|
|
62
|
+
implementation project(':capacitor-android')
|
|
63
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
64
|
+
|
|
65
|
+
implementation 'com.google.code.gson:gson:2.10.1'
|
|
66
|
+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4")
|
|
67
|
+
implementation "com.google.android.gms:play-services-location:$playServicesLocationVersion"
|
|
68
|
+
|
|
69
|
+
testImplementation "junit:junit:$junitVersion"
|
|
70
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
71
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
72
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
package com.capacitorjs.plugins.geolocation
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Object with plugin errors
|
|
5
|
+
*/
|
|
6
|
+
object GeolocationErrors {
|
|
7
|
+
|
|
8
|
+
private fun formatErrorCode(number: Int): String {
|
|
9
|
+
return "OS-PLUG-GLOC-" + number.toString().padStart(4, '0')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
data class ErrorInfo(
|
|
13
|
+
val code: String,
|
|
14
|
+
val message: String
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
val POSITION_UNAVAILABLE = ErrorInfo(
|
|
18
|
+
code = formatErrorCode(2),
|
|
19
|
+
message = "There was en error trying to obtain the location."
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
val LOCATION_PERMISSIONS_DENIED = ErrorInfo(
|
|
23
|
+
code = formatErrorCode(3),
|
|
24
|
+
message = "Location permission request was denied."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
val LOCATION_DISABLED = ErrorInfo(
|
|
28
|
+
code = formatErrorCode(7),
|
|
29
|
+
message = "Location services are not enabled."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
val LOCATION_ENABLE_REQUEST_DENIED = ErrorInfo(
|
|
33
|
+
code = formatErrorCode(9),
|
|
34
|
+
message = "Request to enable location was denied."
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
val GET_LOCATION_TIMEOUT = ErrorInfo(
|
|
38
|
+
code = formatErrorCode(10),
|
|
39
|
+
message = "Could not obtain location in time. Try with a higher timeout."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
val INVALID_TIMEOUT = ErrorInfo(
|
|
43
|
+
code = formatErrorCode(11),
|
|
44
|
+
message = "Timeout needs to be a positive value."
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
val WATCH_ID_NOT_FOUND = ErrorInfo(
|
|
48
|
+
code = formatErrorCode(12),
|
|
49
|
+
message = "WatchId not found."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
val WATCH_ID_NOT_PROVIDED = ErrorInfo(
|
|
53
|
+
code = formatErrorCode(13),
|
|
54
|
+
message = "WatchId needs to be provided."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
val GOOGLE_SERVICES_RESOLVABLE = ErrorInfo(
|
|
58
|
+
code = formatErrorCode(14),
|
|
59
|
+
message = "Google Play Services error user resolvable."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
val GOOGLE_SERVICES_ERROR = ErrorInfo(
|
|
63
|
+
code = formatErrorCode(15),
|
|
64
|
+
message = "Google Play Services error."
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
val LOCATION_SETTINGS_ERROR = ErrorInfo(
|
|
68
|
+
code = formatErrorCode(16),
|
|
69
|
+
message = "Location settings error."
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
package com.capacitorjs.plugins.geolocation
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import androidx.activity.result.contract.ActivityResultContracts
|
|
6
|
+
import com.getcapacitor.JSObject
|
|
7
|
+
import com.getcapacitor.PermissionState
|
|
8
|
+
import com.getcapacitor.Plugin
|
|
9
|
+
import com.getcapacitor.PluginCall
|
|
10
|
+
import com.getcapacitor.PluginMethod
|
|
11
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
12
|
+
import com.getcapacitor.annotation.Permission
|
|
13
|
+
import com.getcapacitor.annotation.PermissionCallback
|
|
14
|
+
import com.google.android.gms.location.LocationServices
|
|
15
|
+
import io.ionic.libs.iongeolocationlib.controller.IONGLOCController
|
|
16
|
+
import io.ionic.libs.iongeolocationlib.model.IONGLOCException
|
|
17
|
+
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationOptions
|
|
18
|
+
import io.ionic.libs.iongeolocationlib.model.IONGLOCLocationResult
|
|
19
|
+
import kotlinx.coroutines.CoroutineScope
|
|
20
|
+
import kotlinx.coroutines.Dispatchers
|
|
21
|
+
import kotlinx.coroutines.cancel
|
|
22
|
+
import kotlinx.coroutines.launch
|
|
23
|
+
|
|
24
|
+
@CapacitorPlugin(
|
|
25
|
+
name = "Geolocation",
|
|
26
|
+
permissions = [Permission(
|
|
27
|
+
strings = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION],
|
|
28
|
+
alias = GeolocationPlugin.LOCATION_ALIAS
|
|
29
|
+
), Permission(
|
|
30
|
+
strings = [Manifest.permission.ACCESS_COARSE_LOCATION],
|
|
31
|
+
alias = GeolocationPlugin.COARSE_LOCATION_ALIAS
|
|
32
|
+
)]
|
|
33
|
+
)
|
|
34
|
+
class GeolocationPlugin : Plugin() {
|
|
35
|
+
|
|
36
|
+
private lateinit var controller: IONGLOCController
|
|
37
|
+
private lateinit var coroutineScope: CoroutineScope
|
|
38
|
+
private val watchingCalls: MutableMap<String, PluginCall> = mutableMapOf()
|
|
39
|
+
|
|
40
|
+
companion object {
|
|
41
|
+
const val LOCATION_ALIAS: String = "location"
|
|
42
|
+
const val COARSE_LOCATION_ALIAS: String = "coarseLocation"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun load() {
|
|
46
|
+
super.load()
|
|
47
|
+
|
|
48
|
+
coroutineScope = CoroutineScope(Dispatchers.Main)
|
|
49
|
+
val activityLauncher = activity.registerForActivityResult(
|
|
50
|
+
ActivityResultContracts.StartIntentSenderForResult()
|
|
51
|
+
) { result ->
|
|
52
|
+
CoroutineScope(Dispatchers.Main).launch {
|
|
53
|
+
controller.onResolvableExceptionResult(result.resultCode)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.controller = IONGLOCController(
|
|
58
|
+
LocationServices.getFusedLocationProviderClient(context),
|
|
59
|
+
activityLauncher
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun handleOnDestroy() {
|
|
65
|
+
super.handleOnDestroy()
|
|
66
|
+
coroutineScope.cancel()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@PluginMethod
|
|
70
|
+
override fun checkPermissions(call: PluginCall) {
|
|
71
|
+
checkLocationState(call) { super.checkPermissions(call) }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@PluginMethod
|
|
75
|
+
override fun requestPermissions(call: PluginCall) {
|
|
76
|
+
checkLocationState(call) { super.requestPermissions(call) }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Helper function to determine if location services are enabled or not
|
|
81
|
+
* @param call the PluginCall to use in case we want to send an error
|
|
82
|
+
* @param onLocationEnabled lambda function to use in case location services are enabled
|
|
83
|
+
*/
|
|
84
|
+
private fun checkLocationState(call: PluginCall, onLocationEnabled: () -> Unit) {
|
|
85
|
+
if (controller.areLocationServicesEnabled(context)) {
|
|
86
|
+
onLocationEnabled()
|
|
87
|
+
} else {
|
|
88
|
+
call.sendError(GeolocationErrors.LOCATION_DISABLED)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Checks location permission state, requesting them if necessary.
|
|
94
|
+
* If not, calls getPosition to get the device's position
|
|
95
|
+
* @param call the plugin call
|
|
96
|
+
*/
|
|
97
|
+
@PluginMethod
|
|
98
|
+
fun getCurrentPosition(call: PluginCall) {
|
|
99
|
+
handlePermissionRequest(call, "completeCurrentPosition") { getPosition(call) }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Checks location permission state, requesting them if necessary.
|
|
104
|
+
* If not, calls startWatch to start getting location updates
|
|
105
|
+
* @param call the plugin call
|
|
106
|
+
*/
|
|
107
|
+
@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
|
|
108
|
+
fun watchPosition(call: PluginCall) {
|
|
109
|
+
handlePermissionRequest(call, "completeWatchPosition") { startWatch(call) }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Helper function to determine if a permission is granted or not and request it if necessary
|
|
114
|
+
* @param call the PluginCall to use in case we want to send an error
|
|
115
|
+
* @param callbackName a string identifying the callback to call once the permission prompt is answered
|
|
116
|
+
* @param onPermissionGranted lambda function to use in case the permission is enabled
|
|
117
|
+
*/
|
|
118
|
+
private fun handlePermissionRequest(
|
|
119
|
+
call: PluginCall,
|
|
120
|
+
callbackName: String,
|
|
121
|
+
onPermissionGranted: () -> Unit
|
|
122
|
+
) {
|
|
123
|
+
val alias = getAlias(call)
|
|
124
|
+
if (getPermissionState(alias) != PermissionState.GRANTED) {
|
|
125
|
+
requestPermissionForAlias(alias, call, callbackName)
|
|
126
|
+
} else {
|
|
127
|
+
onPermissionGranted()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Completes the getCurrentPosition plugin call after a permission request
|
|
133
|
+
* @see .getCurrentPosition
|
|
134
|
+
* @param call the plugin call
|
|
135
|
+
*/
|
|
136
|
+
@PermissionCallback
|
|
137
|
+
private fun completeCurrentPosition(call: PluginCall) {
|
|
138
|
+
handlePermissionResult(call) { getPosition(call) }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Completes the watchPosition plugin call after a permission request
|
|
143
|
+
* @see .startWatch
|
|
144
|
+
* @param call the plugin call
|
|
145
|
+
*/
|
|
146
|
+
@PermissionCallback
|
|
147
|
+
private fun completeWatchPosition(call: PluginCall) {
|
|
148
|
+
handlePermissionResult(call) { startWatch(call) }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Helper function to handle the result of a location permission request
|
|
153
|
+
* @param call the PluginCall to use in case we want to send an error
|
|
154
|
+
* @param onPermissionGranted lambda function to use in case the permission was granted
|
|
155
|
+
*/
|
|
156
|
+
private fun handlePermissionResult(call: PluginCall, onPermissionGranted: () -> Unit) {
|
|
157
|
+
if (getPermissionState(COARSE_LOCATION_ALIAS) == PermissionState.GRANTED) {
|
|
158
|
+
onPermissionGranted()
|
|
159
|
+
} else {
|
|
160
|
+
call.sendError(GeolocationErrors.LOCATION_PERMISSIONS_DENIED)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Clears the watch, removing location updates.
|
|
166
|
+
* @param call the plugin call
|
|
167
|
+
*/
|
|
168
|
+
@PluginMethod
|
|
169
|
+
fun clearWatch(call: PluginCall) {
|
|
170
|
+
val id = call.getString("id")
|
|
171
|
+
if (id.isNullOrBlank()) {
|
|
172
|
+
call.sendError(GeolocationErrors.WATCH_ID_NOT_PROVIDED)
|
|
173
|
+
} else {
|
|
174
|
+
watchingCalls.remove(id)?.release(bridge)
|
|
175
|
+
val watchCleared = controller.clearWatch(id)
|
|
176
|
+
if (watchCleared) {
|
|
177
|
+
call.sendSuccess()
|
|
178
|
+
} else {
|
|
179
|
+
call.sendError(GeolocationErrors.WATCH_ID_NOT_FOUND)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Gets the appropriate permission alias
|
|
186
|
+
* @param call the plugin call
|
|
187
|
+
* @return String with correct alias
|
|
188
|
+
*/
|
|
189
|
+
private fun getAlias(call: PluginCall): String {
|
|
190
|
+
var alias = LOCATION_ALIAS
|
|
191
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
192
|
+
val enableHighAccuracy = call.getBoolean("enableHighAccuracy") ?: false
|
|
193
|
+
if (!enableHighAccuracy) {
|
|
194
|
+
alias = COARSE_LOCATION_ALIAS
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return alias
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Gets the current position
|
|
202
|
+
* @param call the plugin call
|
|
203
|
+
*/
|
|
204
|
+
private fun getPosition(call: PluginCall) {
|
|
205
|
+
coroutineScope.launch {
|
|
206
|
+
val locationOptions = createOptions(call)
|
|
207
|
+
|
|
208
|
+
// call getCurrentPosition method from controller
|
|
209
|
+
val locationResult = controller.getCurrentPosition(activity, locationOptions)
|
|
210
|
+
|
|
211
|
+
locationResult
|
|
212
|
+
.onSuccess { location ->
|
|
213
|
+
call.sendSuccess(getJSObjectForLocation(location))
|
|
214
|
+
}
|
|
215
|
+
.onFailure { exception ->
|
|
216
|
+
onLocationError(exception, call)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Starts watching the device's location by requesting location updates
|
|
223
|
+
* @param call the plugin call
|
|
224
|
+
*/
|
|
225
|
+
private fun startWatch(call: PluginCall) {
|
|
226
|
+
coroutineScope.launch {
|
|
227
|
+
val watchId = call.callbackId
|
|
228
|
+
|
|
229
|
+
val locationOptions = createOptions(call)
|
|
230
|
+
|
|
231
|
+
// call addWatch method from controller
|
|
232
|
+
controller.addWatch(activity, locationOptions, watchId).collect { result ->
|
|
233
|
+
result.onSuccess { locationList ->
|
|
234
|
+
locationList.forEach { locationResult ->
|
|
235
|
+
call.sendSuccess(
|
|
236
|
+
result = getJSObjectForLocation(locationResult),
|
|
237
|
+
keepCallback = true)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
result.onFailure { exception ->
|
|
241
|
+
onLocationError(exception, call)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
watchingCalls[call.callbackId] = call
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Helper function to convert IONGLOCLocationResult object into the format accepted by the Capacitor bridge
|
|
250
|
+
* @param locationResult IONGLOCLocationResult object with the location to convert
|
|
251
|
+
* @return JSObject with converted JSON object
|
|
252
|
+
*/
|
|
253
|
+
private fun getJSObjectForLocation(locationResult: IONGLOCLocationResult): JSObject {
|
|
254
|
+
val coords = JSObject().apply {
|
|
255
|
+
put("latitude", locationResult.latitude)
|
|
256
|
+
put("longitude", locationResult.longitude)
|
|
257
|
+
put("accuracy", locationResult.accuracy)
|
|
258
|
+
put("altitude", locationResult.altitude)
|
|
259
|
+
locationResult.altitudeAccuracy?.let { put("altitudeAccuracy", it) }
|
|
260
|
+
put("speed", locationResult.speed)
|
|
261
|
+
put("heading", locationResult.heading)
|
|
262
|
+
}
|
|
263
|
+
return JSObject().apply {
|
|
264
|
+
put("timestamp", locationResult.timestamp)
|
|
265
|
+
put("coords", coords)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Helper function to handle error cases
|
|
271
|
+
* @param exception Throwable to handle as an error
|
|
272
|
+
* @param call the plugin call
|
|
273
|
+
*/
|
|
274
|
+
private fun onLocationError(exception: Throwable?, call: PluginCall) {
|
|
275
|
+
when (exception) {
|
|
276
|
+
is IONGLOCException.IONGLOCRequestDeniedException -> {
|
|
277
|
+
call.sendError(GeolocationErrors.LOCATION_ENABLE_REQUEST_DENIED)
|
|
278
|
+
}
|
|
279
|
+
is IONGLOCException.IONGLOCSettingsException -> {
|
|
280
|
+
call.sendError(GeolocationErrors.LOCATION_SETTINGS_ERROR)
|
|
281
|
+
}
|
|
282
|
+
is IONGLOCException.IONGLOCInvalidTimeoutException -> {
|
|
283
|
+
call.sendError(GeolocationErrors.INVALID_TIMEOUT)
|
|
284
|
+
}
|
|
285
|
+
is IONGLOCException.IONGLOCGoogleServicesException -> {
|
|
286
|
+
if (exception.resolvable) {
|
|
287
|
+
call.sendError(GeolocationErrors.GOOGLE_SERVICES_RESOLVABLE)
|
|
288
|
+
} else {
|
|
289
|
+
call.sendError(GeolocationErrors.GOOGLE_SERVICES_ERROR)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
is IONGLOCException.IONGLOCLocationRetrievalTimeoutException -> {
|
|
293
|
+
call.sendError(GeolocationErrors.GET_LOCATION_TIMEOUT)
|
|
294
|
+
}
|
|
295
|
+
else -> {
|
|
296
|
+
call.sendError(GeolocationErrors.POSITION_UNAVAILABLE)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Extension function to return a successful plugin result
|
|
303
|
+
* @param result JSOObject with the JSON content to return
|
|
304
|
+
* @param keepCallback boolean to determine if callback should be kept for future calls or not
|
|
305
|
+
*/
|
|
306
|
+
private fun PluginCall.sendSuccess(result: JSObject? = null, keepCallback: Boolean? = false) {
|
|
307
|
+
this.setKeepAlive(keepCallback)
|
|
308
|
+
if (result != null) {
|
|
309
|
+
this.resolve(result)
|
|
310
|
+
} else {
|
|
311
|
+
this.resolve()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Extension function to return a unsuccessful plugin result
|
|
317
|
+
* @param error error class representing the error to return, containing a code and message
|
|
318
|
+
*/
|
|
319
|
+
private fun PluginCall.sendError(error: GeolocationErrors.ErrorInfo) {
|
|
320
|
+
this.reject(error.message, error.code)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Creates the location options to pass to the native controller
|
|
325
|
+
* @param call the plugin call
|
|
326
|
+
* @return IONGLOCLocationOptions object
|
|
327
|
+
*/
|
|
328
|
+
private fun createOptions(call: PluginCall): IONGLOCLocationOptions {
|
|
329
|
+
val timeout = call.getLong("timeout", 10000) ?: 10000
|
|
330
|
+
val maximumAge = call.getLong("maximumAge", 0) ?: 0
|
|
331
|
+
val enableHighAccuracy = call.getBoolean("enableHighAccuracy", false) ?: false
|
|
332
|
+
val minimumUpdateInterval = call.getLong("minimumUpdateInterval", 5000) ?: 5000
|
|
333
|
+
|
|
334
|
+
val locationOptions = IONGLOCLocationOptions(timeout, maximumAge, enableHighAccuracy, minimumUpdateInterval)
|
|
335
|
+
|
|
336
|
+
return locationOptions
|
|
337
|
+
}
|
|
338
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import Capacitor
|
|
2
|
+
import IONGeolocationLib
|
|
3
|
+
|
|
4
|
+
private enum GeolocationCallbackType {
|
|
5
|
+
case requestPermissions
|
|
6
|
+
case location
|
|
7
|
+
case watch
|
|
8
|
+
|
|
9
|
+
var shouldKeepCallback: Bool {
|
|
10
|
+
self == .watch
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var shouldClearAfterSending: Bool {
|
|
14
|
+
self == .location || self == .requestPermissions
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private struct GeolocationCallbackGroup {
|
|
19
|
+
let ids: [CAPPluginCall]
|
|
20
|
+
let type: GeolocationCallbackType
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
final class GeolocationCallbackManager {
|
|
24
|
+
private(set) var requestPermissionsCallbacks: [CAPPluginCall]
|
|
25
|
+
private(set) var locationCallbacks: [CAPPluginCall]
|
|
26
|
+
private(set) var watchCallbacks: [String: CAPPluginCall]
|
|
27
|
+
private let capacitorBridge: CAPBridgeProtocol?
|
|
28
|
+
|
|
29
|
+
private var allCallbackGroups: [GeolocationCallbackGroup] {
|
|
30
|
+
[
|
|
31
|
+
.init(ids: requestPermissionsCallbacks, type: .requestPermissions),
|
|
32
|
+
.init(ids: locationCallbacks, type: .location),
|
|
33
|
+
.init(ids: Array(watchCallbacks.values), type: .watch)
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
private var requestPermissionsCallbackGroup: GeolocationCallbackGroup? {
|
|
37
|
+
allCallbackGroups.first { $0.type == .requestPermissions }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
init(capacitorBridge: CAPBridgeProtocol?) {
|
|
41
|
+
self.capacitorBridge = capacitorBridge
|
|
42
|
+
self.requestPermissionsCallbacks = []
|
|
43
|
+
self.locationCallbacks = []
|
|
44
|
+
self.watchCallbacks = [:]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func addRequestPermissionsCallback(capacitorCall call: CAPPluginCall) {
|
|
48
|
+
capacitorBridge?.saveCall(call)
|
|
49
|
+
requestPermissionsCallbacks.append(call)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func addLocationCallback(capacitorCall call: CAPPluginCall) {
|
|
53
|
+
capacitorBridge?.saveCall(call)
|
|
54
|
+
locationCallbacks.append(call)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func addWatchCallback(_ watchId: String, capacitorCall call: CAPPluginCall) {
|
|
58
|
+
capacitorBridge?.saveCall(call)
|
|
59
|
+
watchCallbacks[watchId] = call
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
func clearRequestPermissionsCallbacks() {
|
|
63
|
+
requestPermissionsCallbacks.forEach {
|
|
64
|
+
capacitorBridge?.releaseCall($0)
|
|
65
|
+
}
|
|
66
|
+
requestPermissionsCallbacks.removeAll()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func clearWatchCallbackIfExists(_ watchId: String) {
|
|
70
|
+
if let callbackToRemove = watchCallbacks[watchId] {
|
|
71
|
+
capacitorBridge?.releaseCall(callbackToRemove)
|
|
72
|
+
watchCallbacks.removeValue(forKey: watchId)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func clearLocationCallbacks() {
|
|
77
|
+
locationCallbacks.forEach {
|
|
78
|
+
capacitorBridge?.releaseCall($0)
|
|
79
|
+
}
|
|
80
|
+
locationCallbacks.removeAll()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func sendSuccess(_ call: CAPPluginCall) {
|
|
84
|
+
call.resolve()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func sendSuccess(_ call: CAPPluginCall, with data: PluginCallResultData) {
|
|
88
|
+
call.resolve(data)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func sendRequestPermissionsSuccess(_ permissionsResult: String) {
|
|
92
|
+
if let group = requestPermissionsCallbackGroup {
|
|
93
|
+
let data = [
|
|
94
|
+
Constants.AuthorisationStatus.ResultKey.location: permissionsResult,
|
|
95
|
+
Constants.AuthorisationStatus.ResultKey.coarseLocation: permissionsResult
|
|
96
|
+
]
|
|
97
|
+
send(.success(data), to: group)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func sendSuccess(with position: IONGLOCPositionModel) {
|
|
102
|
+
createPluginResult(status: .success(position.toJSObject()))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func sendError(_ call: CAPPluginCall, error: GeolocationError) {
|
|
106
|
+
let errorModel = error.toCodeMessagePair()
|
|
107
|
+
call.reject(errorModel.1, errorModel.0)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func sendError(_ error: GeolocationError) {
|
|
111
|
+
createPluginResult(status: .error(error.toCodeMessagePair()))
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private enum CallResultStatus {
|
|
116
|
+
typealias SuccessModel = JSObject
|
|
117
|
+
typealias ErrorModel = (code: String, message: String)
|
|
118
|
+
|
|
119
|
+
case success(_ data: SuccessModel)
|
|
120
|
+
case error(_ codeAndMessage: ErrorModel)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private extension GeolocationCallbackManager {
|
|
124
|
+
|
|
125
|
+
func createPluginResult(status: CallResultStatus) {
|
|
126
|
+
allCallbackGroups.forEach {
|
|
127
|
+
send(status, to: $0)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
func send(_ callResultStatus: CallResultStatus, to group: GeolocationCallbackGroup) {
|
|
132
|
+
group.ids.forEach { call in
|
|
133
|
+
call.keepAlive = group.type.shouldKeepCallback
|
|
134
|
+
switch callResultStatus {
|
|
135
|
+
case .success(let data):
|
|
136
|
+
call.resolve(data)
|
|
137
|
+
case .error(let error):
|
|
138
|
+
call.reject(error.message, error.code)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if group.type.shouldClearAfterSending {
|
|
143
|
+
clearCallbacks(for: group.type)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func clearCallbacks(for type: GeolocationCallbackType) {
|
|
148
|
+
if case .location = type {
|
|
149
|
+
clearLocationCallbacks()
|
|
150
|
+
} else if case .requestPermissions = type {
|
|
151
|
+
clearRequestPermissionsCallbacks()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
enum Constants {
|
|
2
|
+
enum Arguments {
|
|
3
|
+
static let enableHighAccuracy = "enableHighAccuracy"
|
|
4
|
+
static let id = "id"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
enum AuthorisationStatus {
|
|
8
|
+
enum ResultKey {
|
|
9
|
+
static let location = "location"
|
|
10
|
+
static let coarseLocation = "coarseLocation"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
enum Status {
|
|
14
|
+
static let denied: String = "denied"
|
|
15
|
+
static let granted: String = "granted"
|
|
16
|
+
static let prompt: String = "prompt"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
enum LocationUsageDescription {
|
|
21
|
+
static let always: String = "NSLocationAlwaysAndWhenInUseUsageDescription"
|
|
22
|
+
static let whenInUse: String = "NSLocationWhenInUseUsageDescription"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum Position {
|
|
26
|
+
static let altitude: String = "altitude"
|
|
27
|
+
static let coords: String = "coords"
|
|
28
|
+
static let heading: String = "heading"
|
|
29
|
+
static let accuracy: String = "accuracy"
|
|
30
|
+
static let latitude: String = "latitude"
|
|
31
|
+
static let longitude: String = "longitude"
|
|
32
|
+
static let speed: String = "speed"
|
|
33
|
+
static let timestamp: String = "timestamp"
|
|
34
|
+
static let altitudeAccuracy: String = "altitudeAccuracy"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
enum GeolocationMethod: String {
|
|
2
|
+
case getCurrentPosition
|
|
3
|
+
case watchPosition
|
|
4
|
+
case clearWatch
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
enum GeolocationError: Error {
|
|
8
|
+
case locationServicesDisabled
|
|
9
|
+
case permissionDenied
|
|
10
|
+
case permissionRestricted
|
|
11
|
+
case positionUnavailable
|
|
12
|
+
case inputArgumentsIssue(target: GeolocationMethod)
|
|
13
|
+
|
|
14
|
+
func toCodeMessagePair() -> (String, String) {
|
|
15
|
+
("OS-PLUG-GLOC-\(String(format: "%04d", code))", description)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private extension GeolocationError {
|
|
20
|
+
var code: Int {
|
|
21
|
+
switch self {
|
|
22
|
+
case .positionUnavailable: 2
|
|
23
|
+
case .permissionDenied: 3
|
|
24
|
+
case .locationServicesDisabled: 7
|
|
25
|
+
case .permissionRestricted: 8
|
|
26
|
+
case .inputArgumentsIssue(let target):
|
|
27
|
+
switch target {
|
|
28
|
+
case .getCurrentPosition: 4
|
|
29
|
+
case .watchPosition: 5
|
|
30
|
+
case .clearWatch: 6
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var description: String {
|
|
36
|
+
switch self {
|
|
37
|
+
case .positionUnavailable: "There was en error trying to obtain the location."
|
|
38
|
+
case .permissionDenied: "Location permission request was denied."
|
|
39
|
+
case .locationServicesDisabled: "Location services are not enabled."
|
|
40
|
+
case .permissionRestricted: "Application's use of location services was restricted."
|
|
41
|
+
case .inputArgumentsIssue(let target): "The '\(target.rawValue)' input parameters aren't valid."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import Capacitor
|
|
2
|
+
import IONGeolocationLib
|
|
3
|
+
|
|
4
|
+
import Combine
|
|
5
|
+
|
|
6
|
+
@objc(GeolocationPlugin)
|
|
7
|
+
public class GeolocationPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
8
|
+
public let identifier = "GeolocationPlugin"
|
|
9
|
+
public let jsName = "Geolocation"
|
|
10
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
11
|
+
.init(name: "getCurrentPosition", returnType: CAPPluginReturnPromise),
|
|
12
|
+
.init(name: "watchPosition", returnType: CAPPluginReturnCallback),
|
|
13
|
+
.init(name: "clearWatch", returnType: CAPPluginReturnPromise),
|
|
14
|
+
.init(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
|
15
|
+
.init(name: "requestPermissions", returnType: CAPPluginReturnPromise)
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
private var locationService: (any IONGLOCService)?
|
|
19
|
+
private var cancellables = Set<AnyCancellable>()
|
|
20
|
+
private var callbackManager: GeolocationCallbackManager?
|
|
21
|
+
private var isInitialised: Bool = false
|
|
22
|
+
|
|
23
|
+
override public func load() {
|
|
24
|
+
self.locationService = IONGLOCManagerWrapper()
|
|
25
|
+
self.callbackManager = .init(capacitorBridge: bridge)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@objc func getCurrentPosition(_ call: CAPPluginCall) {
|
|
29
|
+
shouldSetupBindings()
|
|
30
|
+
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
|
|
31
|
+
handleLocationRequest(enableHighAccuracy, call: call)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@objc func watchPosition(_ call: CAPPluginCall) {
|
|
35
|
+
shouldSetupBindings()
|
|
36
|
+
let enableHighAccuracy = call.getBool(Constants.Arguments.enableHighAccuracy, false)
|
|
37
|
+
let watchUUID = call.callbackId
|
|
38
|
+
handleLocationRequest(enableHighAccuracy, watchUUID: watchUUID, call: call)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@objc func clearWatch(_ call: CAPPluginCall) {
|
|
42
|
+
shouldSetupBindings()
|
|
43
|
+
guard let callbackId = call.getString(Constants.Arguments.id) else {
|
|
44
|
+
callbackManager?.sendError(.inputArgumentsIssue(target: .clearWatch))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
callbackManager?.clearWatchCallbackIfExists(callbackId)
|
|
48
|
+
|
|
49
|
+
if (callbackManager?.watchCallbacks.isEmpty) ?? false {
|
|
50
|
+
locationService?.stopMonitoringLocation()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
callbackManager?.sendSuccess(call)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@objc override public func checkPermissions(_ call: CAPPluginCall) {
|
|
57
|
+
guard checkIfLocationServicesAreEnabled(call) else { return }
|
|
58
|
+
|
|
59
|
+
let status = switch locationService?.authorisationStatus {
|
|
60
|
+
case .restricted, .denied: Constants.AuthorisationStatus.Status.denied
|
|
61
|
+
case .authorisedAlways, .authorisedWhenInUse: Constants.AuthorisationStatus.Status.granted
|
|
62
|
+
default: Constants.AuthorisationStatus.Status.prompt
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let callResultData = [
|
|
66
|
+
Constants.AuthorisationStatus.ResultKey.location: status,
|
|
67
|
+
Constants.AuthorisationStatus.ResultKey.coarseLocation: status
|
|
68
|
+
]
|
|
69
|
+
callbackManager?.sendSuccess(call, with: callResultData)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@objc override public func requestPermissions(_ call: CAPPluginCall) {
|
|
73
|
+
guard checkIfLocationServicesAreEnabled(call) else { return }
|
|
74
|
+
|
|
75
|
+
if locationService?.authorisationStatus == .notDetermined {
|
|
76
|
+
shouldSetupBindings()
|
|
77
|
+
callbackManager?.addRequestPermissionsCallback(capacitorCall: call)
|
|
78
|
+
} else {
|
|
79
|
+
checkPermissions(call)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private extension GeolocationPlugin {
|
|
85
|
+
func shouldSetupBindings() {
|
|
86
|
+
guard !isInitialised else { return }
|
|
87
|
+
isInitialised = true
|
|
88
|
+
setupBindings()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func setupBindings() {
|
|
92
|
+
locationService?.authorisationStatusPublisher
|
|
93
|
+
.sink(receiveValue: { [weak self] status in
|
|
94
|
+
guard let self else { return }
|
|
95
|
+
|
|
96
|
+
switch status {
|
|
97
|
+
case .denied:
|
|
98
|
+
self.onLocationPermissionNotGranted(error: .permissionDenied)
|
|
99
|
+
case .notDetermined:
|
|
100
|
+
self.requestLocationAuthorisation(type: .whenInUse)
|
|
101
|
+
case .restricted:
|
|
102
|
+
self.onLocationPermissionNotGranted(error: .permissionRestricted)
|
|
103
|
+
case .authorisedAlways, .authorisedWhenInUse:
|
|
104
|
+
self.onLocationPermissionGranted()
|
|
105
|
+
@unknown default: break
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.store(in: &cancellables)
|
|
109
|
+
|
|
110
|
+
locationService?.currentLocationPublisher
|
|
111
|
+
.sink(receiveCompletion: { [weak self] completion in
|
|
112
|
+
if case .failure(let error) = completion {
|
|
113
|
+
print("An error was found while retrieving the location: \(error)")
|
|
114
|
+
self?.callbackManager?.sendError(.positionUnavailable)
|
|
115
|
+
}
|
|
116
|
+
}, receiveValue: { [weak self] position in
|
|
117
|
+
self?.callbackManager?.sendSuccess(with: position)
|
|
118
|
+
})
|
|
119
|
+
.store(in: &cancellables)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func requestLocationAuthorisation(type requestType: IONGLOCAuthorisationRequestType) {
|
|
123
|
+
DispatchQueue.global(qos: .background).async {
|
|
124
|
+
guard self.checkIfLocationServicesAreEnabled() else { return }
|
|
125
|
+
self.locationService?.requestAuthorisation(withType: requestType)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func checkIfLocationServicesAreEnabled(_ call: CAPPluginCall? = nil) -> Bool {
|
|
130
|
+
guard locationService?.areLocationServicesEnabled() == true else {
|
|
131
|
+
call.map { callbackManager?.sendError($0, error: .locationServicesDisabled) }
|
|
132
|
+
?? callbackManager?.sendError(.locationServicesDisabled)
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
return true
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func onLocationPermissionNotGranted(error: GeolocationError) {
|
|
139
|
+
let shouldNotifyRequestPermissionsResult = callbackManager?.requestPermissionsCallbacks.isEmpty == false
|
|
140
|
+
let shouldNotifyPermissionError = callbackManager?.locationCallbacks.isEmpty == false || callbackManager?.watchCallbacks.isEmpty == false
|
|
141
|
+
|
|
142
|
+
if shouldNotifyRequestPermissionsResult {
|
|
143
|
+
self.callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.denied)
|
|
144
|
+
}
|
|
145
|
+
if shouldNotifyPermissionError {
|
|
146
|
+
self.callbackManager?.sendError(error)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
func onLocationPermissionGranted() {
|
|
151
|
+
let shouldNotifyPermissionGranted = callbackManager?.requestPermissionsCallbacks.isEmpty == false
|
|
152
|
+
// should request location if callbacks below exist and are not empty
|
|
153
|
+
let shouldRequestCurrentPosition = callbackManager?.locationCallbacks.isEmpty == false
|
|
154
|
+
let shouldRequestLocationMonitoring = callbackManager?.watchCallbacks.isEmpty == false
|
|
155
|
+
|
|
156
|
+
if shouldNotifyPermissionGranted {
|
|
157
|
+
callbackManager?.sendRequestPermissionsSuccess(Constants.AuthorisationStatus.Status.granted)
|
|
158
|
+
}
|
|
159
|
+
if shouldRequestCurrentPosition {
|
|
160
|
+
locationService?.requestSingleLocation()
|
|
161
|
+
}
|
|
162
|
+
if shouldRequestLocationMonitoring {
|
|
163
|
+
locationService?.startMonitoringLocation()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func handleLocationRequest(_ enableHighAccuracy: Bool, watchUUID: String? = nil, call: CAPPluginCall) {
|
|
168
|
+
let configurationModel = IONGLOCConfigurationModel(enableHighAccuracy: enableHighAccuracy)
|
|
169
|
+
locationService?.updateConfiguration(configurationModel)
|
|
170
|
+
|
|
171
|
+
if let watchUUID {
|
|
172
|
+
callbackManager?.addWatchCallback(watchUUID, capacitorCall: call)
|
|
173
|
+
} else {
|
|
174
|
+
callbackManager?.addLocationCallback(capacitorCall: call)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
switch locationService?.authorisationStatus {
|
|
178
|
+
case .authorisedAlways, .authorisedWhenInUse: onLocationPermissionGranted()
|
|
179
|
+
case .denied: callbackManager?.sendError(.permissionDenied)
|
|
180
|
+
case .restricted: callbackManager?.sendError(.permissionRestricted)
|
|
181
|
+
default: break
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Capacitor
|
|
2
|
+
import IONGeolocationLib
|
|
3
|
+
|
|
4
|
+
extension IONGLOCPositionModel {
|
|
5
|
+
func toJSObject() -> JSObject {
|
|
6
|
+
[
|
|
7
|
+
Constants.Position.timestamp: timestamp,
|
|
8
|
+
Constants.Position.coords: coordsJSObject
|
|
9
|
+
]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private var coordsJSObject: JSObject {
|
|
13
|
+
[
|
|
14
|
+
Constants.Position.altitude: altitude,
|
|
15
|
+
Constants.Position.heading: course,
|
|
16
|
+
Constants.Position.accuracy: horizontalAccuracy,
|
|
17
|
+
Constants.Position.latitude: latitude,
|
|
18
|
+
Constants.Position.longitude: longitude,
|
|
19
|
+
Constants.Position.speed: speed,
|
|
20
|
+
Constants.Position.altitudeAccuracy: verticalAccuracy
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import GeolocationCapacitorPlugin
|
|
3
|
+
|
|
4
|
+
class GeolocationPluginCapacitorTests: XCTestCase {
|
|
5
|
+
func testEcho() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
|
|
9
|
+
let implementation = GeolocationPluginCapacitor()
|
|
10
|
+
let value = "Hello, World!"
|
|
11
|
+
let result = implementation.echo(value)
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(value, result)
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nitra/geolocation",
|
|
3
|
+
"version": "7.1.1",
|
|
4
|
+
"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.",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
16
|
+
"CapacitorGeolocation.podspec"
|
|
17
|
+
],
|
|
18
|
+
"author": "Outsystems",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/ionic-team/capacitor-geolocation.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/ionic-team/capacitor-geolocation/issues"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"capacitor",
|
|
29
|
+
"plugin",
|
|
30
|
+
"native"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
34
|
+
"verify:ios": "xcodebuild -scheme GeolocationCapacitor -destination generic/platform=iOS",
|
|
35
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
36
|
+
"verify:web": "npm run build",
|
|
37
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
38
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
39
|
+
"eslint": "eslint . --ext ts",
|
|
40
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
41
|
+
"swiftlint": "node-swiftlint",
|
|
42
|
+
"docgen": "docgen --api GeolocationPlugin --output-readme README.md --output-json dist/docs.json && cp README.md ../../README.md",
|
|
43
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
44
|
+
"clean": "rimraf ./dist",
|
|
45
|
+
"watch": "tsc --watch",
|
|
46
|
+
"prepublishOnly": "npm run build"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@capacitor/synapse": "^1.0.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@capacitor/android": "next",
|
|
53
|
+
"@capacitor/core": "next",
|
|
54
|
+
"@capacitor/docgen": "^0.2.2",
|
|
55
|
+
"@capacitor/ios": "next",
|
|
56
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
57
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
58
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
59
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
60
|
+
"@semantic-release/git": "^10.0.1",
|
|
61
|
+
"@semantic-release/github": "^11.0.1",
|
|
62
|
+
"@semantic-release/npm": "^12.0.1",
|
|
63
|
+
"@types/node": "^20.14.8",
|
|
64
|
+
"eslint": "^8.57.0",
|
|
65
|
+
"prettier": "^3.3.3",
|
|
66
|
+
"prettier-plugin-java": "^2.6.4",
|
|
67
|
+
"rimraf": "^6.0.1",
|
|
68
|
+
"rollup": "^2.78.1",
|
|
69
|
+
"semantic-release": "^24.0.0",
|
|
70
|
+
"swiftlint": "^2.0.0",
|
|
71
|
+
"typescript": "~5.4.5"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@capacitor/core": ">=7.0.0"
|
|
75
|
+
},
|
|
76
|
+
"prettier": "@ionic/prettier-config",
|
|
77
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
78
|
+
"eslintConfig": {
|
|
79
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
80
|
+
},
|
|
81
|
+
"capacitor": {
|
|
82
|
+
"ios": {
|
|
83
|
+
"src": "ios"
|
|
84
|
+
},
|
|
85
|
+
"android": {
|
|
86
|
+
"src": "android"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|