@expofp/react-native-efp-crowdconnected 0.0.2-alpha.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/ExpofpCrowdconnected.podspec +26 -0
- package/LICENSE +20 -0
- package/README.md +169 -0
- package/android/build.gradle +86 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/expofpcrowdconnected/ExpoFpAzimuthProvider.kt +94 -0
- package/android/src/main/java/com/expofpcrowdconnected/ExpoFpCrowdConnectedLocationProviderSettings.kt +136 -0
- package/android/src/main/java/com/expofpcrowdconnected/ExpoFpPosition.kt +96 -0
- package/android/src/main/java/com/expofpcrowdconnected/ExpoFpProviderInfo.kt +27 -0
- package/android/src/main/java/com/expofpcrowdconnected/ExpofpCrowdconnectedPackage.kt +33 -0
- package/android/src/main/java/com/expofpcrowdconnected/RCTCrowdConnectedLocationProviderModule.kt +504 -0
- package/ios/ExpoFpLocationProvider/ExpoFpCrowdConnectedLocationProviderSettings.swift +116 -0
- package/ios/ExpoFpLocationProvider/ExpoFpCrowdConnectedNavigationType.swift +14 -0
- package/ios/ExpoFpLocationProvider/ExpoFpError.swift +28 -0
- package/ios/ExpoFpLocationProvider/ExpoFpFloorType.swift +39 -0
- package/ios/ExpoFpLocationProvider/ExpoFpLocationSettings.swift +18 -0
- package/ios/ExpoFpLocationProvider/ExpoFpPosition.swift +42 -0
- package/ios/ExpoFpLocationProvider/ExpoFpProviderInfo.swift +12 -0
- package/ios/Extensions/Encodable+Extensions.swift +28 -0
- package/ios/Extensions/LocationTrackingMode+Extensions.swift +16 -0
- package/ios/Extensions/NSDictionary+Extensions.swift +21 -0
- package/ios/RCTCrowdConnectedLocationProvider.m +24 -0
- package/ios/RCTCrowdConnectedLocationProvider.swift +252 -0
- package/lib/module/crowdconnected-location-provider-native-module.js +38 -0
- package/lib/module/crowdconnected-location-provider-native-module.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/crowdconnected-location-provider-native-module.d.ts +4 -0
- package/lib/typescript/src/crowdconnected-location-provider-native-module.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +40 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +154 -0
- package/src/crowdconnected-location-provider-native-module.tsx +57 -0
- package/src/index.tsx +2 -0
- package/src/types.ts +49 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ExpoFpFloorType.swift
|
|
3
|
+
// ExpoFP
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 11.04.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
/// Floor index or name
|
|
10
|
+
public enum ExpoFpFloorType: Codable, Hashable {
|
|
11
|
+
/// Floor index
|
|
12
|
+
case index(Int)
|
|
13
|
+
/// Floor name
|
|
14
|
+
case name(String)
|
|
15
|
+
|
|
16
|
+
public func encode(to encoder: Encoder) throws {
|
|
17
|
+
var container = encoder.singleValueContainer()
|
|
18
|
+
|
|
19
|
+
switch self {
|
|
20
|
+
case .index(let index):
|
|
21
|
+
try container.encode(index)
|
|
22
|
+
|
|
23
|
+
case .name(let name):
|
|
24
|
+
try container.encode(name)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public init(from decoder: Decoder) throws {
|
|
29
|
+
let container = try decoder.singleValueContainer()
|
|
30
|
+
|
|
31
|
+
if let index = try? container.decode(Int.self) {
|
|
32
|
+
self = .index(index)
|
|
33
|
+
} else if let name = try? container.decode(String.self) {
|
|
34
|
+
self = .name(name)
|
|
35
|
+
} else {
|
|
36
|
+
throw ExpoFpError.decodingError(message: "`ExpoFpFloorType` mismatch.")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ExpoFpLocationSettings.swift
|
|
3
|
+
// ExpoFpCrowdConnected
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 23.10.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
struct ExpoFpLocationSettings: Codable {
|
|
10
|
+
let appKey: String
|
|
11
|
+
let token: String
|
|
12
|
+
let secret: String
|
|
13
|
+
let navigationType: ExpoFpCrowdConnectedNavigationType
|
|
14
|
+
let isBackgroundUpdateEnabled: Bool
|
|
15
|
+
let isBluetoothEnabled: Bool
|
|
16
|
+
let isHeadingEnabled: Bool
|
|
17
|
+
let aliases: [String: String]?
|
|
18
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ExpoFpPosition.swift
|
|
3
|
+
// ExpoFP
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 24.04.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
/// Position info
|
|
10
|
+
public struct ExpoFpPosition: Codable, Hashable {
|
|
11
|
+
/// X coordinate
|
|
12
|
+
public let x: Double?
|
|
13
|
+
/// Y coordinate
|
|
14
|
+
public let y: Double?
|
|
15
|
+
/// Floor index or name
|
|
16
|
+
public let z: ExpoFpFloorType?
|
|
17
|
+
/// Dot direction angle
|
|
18
|
+
public let angle: Double?
|
|
19
|
+
/// Latitude
|
|
20
|
+
public let lat: Double?
|
|
21
|
+
/// Longitude
|
|
22
|
+
public let lng: Double?
|
|
23
|
+
/// - Parameters:
|
|
24
|
+
/// - x: X coordinate
|
|
25
|
+
/// - y: Y coordinate
|
|
26
|
+
/// - z: Floor index or name
|
|
27
|
+
/// - angle: Dot direction angle
|
|
28
|
+
/// - lat: Latitude
|
|
29
|
+
/// - lng: Longitude
|
|
30
|
+
public init(x: Double? = nil, y: Double? = nil, z: ExpoFpFloorType? = nil, angle: Double? = nil, lat: Double? = nil, lng: Double? = nil) {
|
|
31
|
+
self.x = x
|
|
32
|
+
self.y = y
|
|
33
|
+
self.z = z
|
|
34
|
+
self.angle = angle
|
|
35
|
+
self.lat = lat
|
|
36
|
+
self.lng = lng
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func updateHeading(newHeading: Double?) -> ExpoFpPosition {
|
|
40
|
+
ExpoFpPosition(x: x, y: y, z: z, angle: newHeading, lat: lat, lng: lng)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ExpoFpProviderInfo.swift
|
|
3
|
+
// ExpofpCrowdconnected
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 24.10.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
struct ExpoFpProviderInfo: Codable {
|
|
10
|
+
var isLocationUpdating = false
|
|
11
|
+
var deviceId: String? = nil
|
|
12
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Encodable+Extensions.swift
|
|
3
|
+
// ExpoFP
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 03.04.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
extension Encodable {
|
|
12
|
+
|
|
13
|
+
var jsonString: String {
|
|
14
|
+
guard let data = try? JSONEncoder().encode(self) else { return "null" }
|
|
15
|
+
return String(data: data, encoding: .utf8) ?? "null"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func toDict() throws -> NSDictionary {
|
|
19
|
+
let data = try JSONEncoder().encode(self)
|
|
20
|
+
let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
|
|
21
|
+
|
|
22
|
+
guard let dict = jsonObject as? NSDictionary else {
|
|
23
|
+
throw ExpoFpError.internalError(message: "Object cannot be converted to dictionary.")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return dict
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LocationTrackingMode+Extensions.swift
|
|
3
|
+
// ExpoFpCrowdConnected
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 24.09.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import CrowdConnectedCore
|
|
10
|
+
|
|
11
|
+
extension LocationTrackingMode {
|
|
12
|
+
|
|
13
|
+
var isAllowedInBackground: Bool {
|
|
14
|
+
self == .foregroundAndBackground
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NSDictionary+Extensions.swift
|
|
3
|
+
// ExpofpSdkRn
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 21.10.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
extension NSDictionary {
|
|
12
|
+
|
|
13
|
+
func decode<T: Decodable>(_ type: T.Type) throws -> T {
|
|
14
|
+
guard JSONSerialization.isValidJSONObject(self) else {
|
|
15
|
+
throw ExpoFpError.decodingError(message: "\(self) is not a valid object")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let data = try JSONSerialization.data(withJSONObject: self, options: [])
|
|
19
|
+
return try JSONDecoder().decode(T.self, from: data)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RCTCrowdConnectedLocationProvider.m
|
|
3
|
+
// ExpoFpCrowdConnected
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 23.10.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#import <React/RCTEventEmitter.h>
|
|
10
|
+
#import "ExpofpCrowdconnected-Swift.h"
|
|
11
|
+
|
|
12
|
+
@interface RCT_EXTERN_MODULE(RCTCrowdConnectedLocationProvider, RCTEventEmitter)
|
|
13
|
+
|
|
14
|
+
// MARK: - Public Methods
|
|
15
|
+
|
|
16
|
+
RCT_EXTERN_METHOD(setup:(nonnull NSDictionary *)settings
|
|
17
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
18
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
19
|
+
|
|
20
|
+
RCT_EXTERN_METHOD(startUpdatingLocation:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
21
|
+
RCT_EXTERN_METHOD(stopUpdatingLocation:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
22
|
+
RCT_EXTERN_METHOD(isLocationUpdating:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
23
|
+
|
|
24
|
+
@end
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RCTCrowdConnectedLocationProvider.swift
|
|
3
|
+
// ExpoFpCrowdConnected
|
|
4
|
+
//
|
|
5
|
+
// Created by Nikita Kolesnikov on 23.10.2025.
|
|
6
|
+
// Copyright © 2025 ExpoFP. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import CoreLocation
|
|
10
|
+
import CrowdConnectedCore
|
|
11
|
+
import CrowdConnectedCoreBluetooth
|
|
12
|
+
import CrowdConnectedGeo
|
|
13
|
+
import CrowdConnectedIPS
|
|
14
|
+
import CrowdConnectedShared
|
|
15
|
+
import React
|
|
16
|
+
import UIKit
|
|
17
|
+
|
|
18
|
+
// See example https://github.com/nathvarun/react-native-native-module-swift-tutorial/blob/master/ios/Counter.swift
|
|
19
|
+
@objc(RCTCrowdConnectedLocationProvider)
|
|
20
|
+
class RCTCrowdConnectedLocationProvider: RCTEventEmitter, CLLocationManagerDelegate, CrowdConnectedDelegate {
|
|
21
|
+
|
|
22
|
+
// MARK: - Properties
|
|
23
|
+
|
|
24
|
+
private let locationEventName = "onLocationChange"
|
|
25
|
+
private let locationErrorName = "onLocationError"
|
|
26
|
+
|
|
27
|
+
private let ccLocationManager = CrowdConnected.shared
|
|
28
|
+
private let clLocationManager = CLLocationManager()
|
|
29
|
+
private var timeoutTask: Task<Void, Error>?
|
|
30
|
+
|
|
31
|
+
private var settings: ExpoFpCrowdConnectedLocationProviderSettings?
|
|
32
|
+
private var providerInfo = ExpoFpProviderInfo()
|
|
33
|
+
private var position = ExpoFpPosition() {
|
|
34
|
+
didSet {
|
|
35
|
+
guard providerInfo.isLocationUpdating, let position = try? position.toDict() else { return }
|
|
36
|
+
sendEvent(withName: locationEventName, body: position)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// MARK: - Methods
|
|
41
|
+
|
|
42
|
+
override func supportedEvents() -> [String] {
|
|
43
|
+
[locationEventName, locationErrorName]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@objc func setup(
|
|
47
|
+
_ settings: NSDictionary,
|
|
48
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
49
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
50
|
+
) {
|
|
51
|
+
do {
|
|
52
|
+
let settings = try ExpoFpCrowdConnectedLocationProviderSettings(settings: try settings.decode(ExpoFpLocationSettings.self))
|
|
53
|
+
self.settings = settings
|
|
54
|
+
|
|
55
|
+
let isLocationUpdating = providerInfo.isLocationUpdating
|
|
56
|
+
if isLocationUpdating { stopUpdatingLocation({_ in }, rejecter: {_,_,_ in }) }
|
|
57
|
+
|
|
58
|
+
ccLocationManager.delegate = self
|
|
59
|
+
clLocationManager.delegate = self
|
|
60
|
+
|
|
61
|
+
switch settings.navigationType {
|
|
62
|
+
case .all:
|
|
63
|
+
CrowdConnectedGeo.activate()
|
|
64
|
+
CrowdConnectedIPS.activate()
|
|
65
|
+
case .geo:
|
|
66
|
+
CrowdConnectedGeo.activate()
|
|
67
|
+
case .ips:
|
|
68
|
+
CrowdConnectedIPS.activate()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if settings.isBluetoothEnabled {
|
|
72
|
+
CrowdConnectedCoreBluetooth.activate()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
isLocationUpdating
|
|
76
|
+
? startUpdatingLocation(resolve, rejecter: reject)
|
|
77
|
+
: (try? providerInfo.toDict()).map(resolve)
|
|
78
|
+
|
|
79
|
+
} catch {
|
|
80
|
+
rejectWith(error, reject)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@objc func startUpdatingLocation(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
85
|
+
guard let settings else {
|
|
86
|
+
let error = ExpoFpError.locationProviderError(message: "Settings are missing. Use `setup` method first.")
|
|
87
|
+
rejectWith(error, reject)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
guard !providerInfo.isLocationUpdating else {
|
|
92
|
+
(try? providerInfo.toDict()).map(resolve)
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if let errorMessage = getAuthorizationStatusErrorMessage() {
|
|
97
|
+
let error = ExpoFpError.locationProviderError(message: errorMessage)
|
|
98
|
+
rejectWith(error, reject)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
providerInfo.isLocationUpdating = true
|
|
103
|
+
requestPermission(settings)
|
|
104
|
+
startCrowdConnected(settings, resolve, reject)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@objc func stopUpdatingLocation(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
108
|
+
stopTimeoutTask()
|
|
109
|
+
ccLocationManager.stop()
|
|
110
|
+
clLocationManager.stopUpdatingHeading()
|
|
111
|
+
providerInfo.isLocationUpdating = false
|
|
112
|
+
(try? providerInfo.toDict()).map(resolve)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@objc func isLocationUpdating(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
|
|
116
|
+
(try? providerInfo.toDict()).map(resolve)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@objc func didUpdateLocation(_ locations: [Location]) {
|
|
120
|
+
guard let location = locations.last,
|
|
121
|
+
let navType = ExpoFpCrowdConnectedNavigationType(rawValue: location.type)
|
|
122
|
+
else { return }
|
|
123
|
+
|
|
124
|
+
position = switch navType {
|
|
125
|
+
case .ips:
|
|
126
|
+
ExpoFpPosition(
|
|
127
|
+
x: location.pixelCoordinates?.xPixels,
|
|
128
|
+
y: location.pixelCoordinates?.yPixels,
|
|
129
|
+
z: .index(location.floor),
|
|
130
|
+
angle: position.angle
|
|
131
|
+
)
|
|
132
|
+
default:
|
|
133
|
+
ExpoFpPosition(
|
|
134
|
+
z: .index(location.floor),
|
|
135
|
+
angle: position.angle,
|
|
136
|
+
lat: location.latitude,
|
|
137
|
+
lng: location.longitude
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
|
|
143
|
+
guard position != ExpoFpPosition() else { return }
|
|
144
|
+
position = position.updateHeading(newHeading: newHeading.trueHeading)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
|
|
148
|
+
settings.map(requestPermission)
|
|
149
|
+
getAuthorizationStatusErrorMessage().map(sendError)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// MARK: - Private Methods
|
|
153
|
+
|
|
154
|
+
private func requestPermission(_ settings: ExpoFpCrowdConnectedLocationProviderSettings) {
|
|
155
|
+
if clLocationManager.authorizationStatus == .notDetermined ||
|
|
156
|
+
(clLocationManager.authorizationStatus == .authorizedWhenInUse && settings.trackingMode.isAllowedInBackground) {
|
|
157
|
+
|
|
158
|
+
settings.trackingMode.isAllowedInBackground
|
|
159
|
+
? clLocationManager.requestAlwaysAuthorization()
|
|
160
|
+
: clLocationManager.requestWhenInUseAuthorization()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private func startCrowdConnected(
|
|
165
|
+
_ settings: ExpoFpCrowdConnectedLocationProviderSettings,
|
|
166
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
167
|
+
_ reject: @escaping RCTPromiseRejectBlock
|
|
168
|
+
) {
|
|
169
|
+
startTimeoutTask(resolve, reject)
|
|
170
|
+
|
|
171
|
+
ccLocationManager.start(
|
|
172
|
+
credentials: settings.credentials,
|
|
173
|
+
trackingMode: settings.trackingMode
|
|
174
|
+
) { [weak self] deviceID, result in
|
|
175
|
+
|
|
176
|
+
self?.stopTimeoutTask()
|
|
177
|
+
|
|
178
|
+
if deviceID != nil {
|
|
179
|
+
self?.providerInfo.deviceId = deviceID
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
switch result {
|
|
183
|
+
case .alreadyRunning, .success:
|
|
184
|
+
if settings.isHeadingEnabled {
|
|
185
|
+
self?.clLocationManager.startUpdatingHeading()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if settings.trackingMode.isAllowedInBackground {
|
|
189
|
+
self?.ccLocationManager.activateSDKBackgroundRefresh()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
settings.aliases.forEach(CrowdConnected.shared.setAlias)
|
|
193
|
+
(try? self?.providerInfo.toDict()).map(resolve)
|
|
194
|
+
|
|
195
|
+
case .missingAppKey, // will crash the app
|
|
196
|
+
.missingToken, // will crash the app
|
|
197
|
+
.missingSecret, // will crash the app
|
|
198
|
+
.deviceRegistrationFailed,
|
|
199
|
+
.noModulesAreActive, // will crash the app
|
|
200
|
+
.missingBluetoothPermissionItem, // will crash the app
|
|
201
|
+
.missingWhileInUseLocationPermissionItem, // will crash the app
|
|
202
|
+
.missingAlwaysLocationPermissionItem, // will crash the app
|
|
203
|
+
.missingLocationBackgroundModeItem, // will crash the app
|
|
204
|
+
.missingBluetoothBackgroundModeItem: // will crash the app
|
|
205
|
+
self?.stopUpdatingLocation({_ in }, rejecter: {_,_,_ in })
|
|
206
|
+
|
|
207
|
+
let error = ExpoFpError.locationProviderError(message: result.description)
|
|
208
|
+
self?.rejectWith(error, reject)
|
|
209
|
+
|
|
210
|
+
@unknown default:
|
|
211
|
+
self?.stopUpdatingLocation({_ in }, rejecter: {_,_,_ in })
|
|
212
|
+
let error = ExpoFpError.locationProviderError(message: "@unknown start result!")
|
|
213
|
+
self?.rejectWith(error, reject)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private func startTimeoutTask(_ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) {
|
|
219
|
+
timeoutTask?.cancel()
|
|
220
|
+
|
|
221
|
+
timeoutTask = Task { [weak self] in
|
|
222
|
+
try await Task.sleep(nanoseconds: 65 * 1_000_000_000) // 65 seconds
|
|
223
|
+
guard !Task.isCancelled else { return }
|
|
224
|
+
|
|
225
|
+
self?.sendError(with: "Start Timeout! Restarting...")
|
|
226
|
+
self?.stopUpdatingLocation({_ in }, rejecter: {_,_,_ in })
|
|
227
|
+
self?.startUpdatingLocation(resolve, rejecter: reject)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private func stopTimeoutTask() {
|
|
232
|
+
timeoutTask?.cancel()
|
|
233
|
+
timeoutTask = nil
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private func getAuthorizationStatusErrorMessage() -> String? {
|
|
237
|
+
switch clLocationManager.authorizationStatus {
|
|
238
|
+
case .denied: "App location service status: Denied."
|
|
239
|
+
case .restricted: "App location service status: Restricted."
|
|
240
|
+
default: nil
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private func sendError(with message: String) {
|
|
245
|
+
let deviceId = providerInfo.deviceId.map { " Device ID: \($0)." } ?? ""
|
|
246
|
+
sendEvent(withName: locationErrorName, body: message + deviceId)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private func rejectWith(_ error: Error, _ reject: RCTPromiseRejectBlock) {
|
|
250
|
+
reject("500", "\(error)", error)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeEventEmitter, NativeModules } from "react-native";
|
|
4
|
+
const {
|
|
5
|
+
RCTCrowdConnectedLocationProvider
|
|
6
|
+
} = NativeModules;
|
|
7
|
+
const nativeEventEmitter = new NativeEventEmitter(RCTCrowdConnectedLocationProvider);
|
|
8
|
+
|
|
9
|
+
// Export preload method from ExpofpModule
|
|
10
|
+
export const RCTCrowdConnectedLocationProviderNativeModule = RCTCrowdConnectedLocationProvider;
|
|
11
|
+
|
|
12
|
+
// https://reactnative.dev/docs/next/the-new-architecture/native-modules-custom-events
|
|
13
|
+
// https://www.callstack.com/blog/sending-events-to-javascript-from-your-native-module-in-react-native
|
|
14
|
+
export const CrowdConnectedLocationProvider = {
|
|
15
|
+
setup: RCTCrowdConnectedLocationProviderNativeModule.setup,
|
|
16
|
+
startUpdatingLocation: RCTCrowdConnectedLocationProviderNativeModule.startUpdatingLocation,
|
|
17
|
+
stopUpdatingLocation: RCTCrowdConnectedLocationProviderNativeModule.stopUpdatingLocation,
|
|
18
|
+
isLocationUpdating: RCTCrowdConnectedLocationProviderNativeModule.isLocationUpdating,
|
|
19
|
+
onLocationChange: callback => {
|
|
20
|
+
const onLocationChange = location => {
|
|
21
|
+
callback(location);
|
|
22
|
+
};
|
|
23
|
+
const locationListener = nativeEventEmitter.addListener("onLocationChange", onLocationChange);
|
|
24
|
+
return () => {
|
|
25
|
+
locationListener.remove();
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
onError: callback => {
|
|
29
|
+
const onLocationError = error => {
|
|
30
|
+
callback(new Error(error));
|
|
31
|
+
};
|
|
32
|
+
const errorListener = nativeEventEmitter.addListener("onLocationError", onLocationError);
|
|
33
|
+
return () => {
|
|
34
|
+
errorListener.remove();
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=crowdconnected-location-provider-native-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","RCTCrowdConnectedLocationProvider","nativeEventEmitter","RCTCrowdConnectedLocationProviderNativeModule","CrowdConnectedLocationProvider","setup","startUpdatingLocation","stopUpdatingLocation","isLocationUpdating","onLocationChange","callback","location","locationListener","addListener","remove","onError","onLocationError","error","Error","errorListener"],"sourceRoot":"../../src","sources":["crowdconnected-location-provider-native-module.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;AAChE,MAAM;EAAEC;AAAkC,CAAC,GAAGD,aAAa;AAQ3D,MAAME,kBAAkB,GAAG,IAAIH,kBAAkB,CAC/CE,iCACF,CAAC;;AAED;AACA,OAAO,MAAME,6CAA6C,GACxDF,iCAAgF;;AAElF;AACA;AACA,OAAO,MAAMG,8BAA+D,GAAG;EAC7EC,KAAK,EAAEF,6CAA6C,CAACE,KAAK;EAC1DC,qBAAqB,EACnBH,6CAA6C,CAACG,qBAAqB;EACrEC,oBAAoB,EAClBJ,6CAA6C,CAACI,oBAAoB;EACpEC,kBAAkB,EAChBL,6CAA6C,CAACK,kBAAkB;EAClEC,gBAAgB,EAAGC,QAAQ,IAAK;IAC9B,MAAMD,gBAAgB,GAAIE,QAAwB,IAAK;MACrDD,QAAQ,CAACC,QAAQ,CAAC;IACpB,CAAC;IAED,MAAMC,gBAAgB,GAAGV,kBAAkB,CAACW,WAAW,CACrD,kBAAkB,EAClBJ,gBACF,CAAC;IAED,OAAO,MAAM;MACXG,gBAAgB,CAACE,MAAM,CAAC,CAAC;IAC3B,CAAC;EACH,CAAC;EAEDC,OAAO,EAAGL,QAAQ,IAAK;IACrB,MAAMM,eAAe,GAAIC,KAAa,IAAK;MACzCP,QAAQ,CAAC,IAAIQ,KAAK,CAACD,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,MAAME,aAAa,GAAGjB,kBAAkB,CAACW,WAAW,CAClD,iBAAiB,EACjBG,eACF,CAAC;IAED,OAAO,MAAM;MACXG,aAAa,CAACL,MAAM,CAAC,CAAC;IACxB,CAAC;EACH;AACF,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,cAAc,YAAS;AACvB,cAAc,qDAAkD","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ICrowdConnectedLocationProviderNativeModule, ICrowdConnectedLocationProvider } from "./types";
|
|
2
|
+
export declare const RCTCrowdConnectedLocationProviderNativeModule: ICrowdConnectedLocationProviderNativeModule;
|
|
3
|
+
export declare const CrowdConnectedLocationProvider: ICrowdConnectedLocationProvider;
|
|
4
|
+
//# sourceMappingURL=crowdconnected-location-provider-native-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crowdconnected-location-provider-native-module.d.ts","sourceRoot":"","sources":["../../../src/crowdconnected-location-provider-native-module.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,2CAA2C,EAC3C,+BAA+B,EAEhC,MAAM,SAAS,CAAC;AAOjB,eAAO,MAAM,6CAA6C,EACnB,2CAA2C,CAAC;AAInF,eAAO,MAAM,8BAA8B,EAAE,+BAqC5C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,kDAAkD,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ICrowdConnectedLocationProviderNativeModule {
|
|
2
|
+
setup(settings: ExpoFpLocationSettings): Promise<ExpoFpProviderInfo>;
|
|
3
|
+
startUpdatingLocation(): Promise<ExpoFpProviderInfo>;
|
|
4
|
+
stopUpdatingLocation(): Promise<ExpoFpProviderInfo>;
|
|
5
|
+
isLocationUpdating(): Promise<ExpoFpProviderInfo>;
|
|
6
|
+
}
|
|
7
|
+
export interface ICrowdConnectedLocationProvider {
|
|
8
|
+
setup(settings: ExpoFpLocationSettings): Promise<ExpoFpProviderInfo>;
|
|
9
|
+
startUpdatingLocation(): Promise<ExpoFpProviderInfo>;
|
|
10
|
+
stopUpdatingLocation(): Promise<ExpoFpProviderInfo>;
|
|
11
|
+
isLocationUpdating(): Promise<ExpoFpProviderInfo>;
|
|
12
|
+
onLocationChange(callback: LocationUpdateCallback): Unsubscribe;
|
|
13
|
+
onError(callback: ErrorCallback): Unsubscribe;
|
|
14
|
+
}
|
|
15
|
+
export type Unsubscribe = () => void;
|
|
16
|
+
export type LocationUpdateCallback = (location: ExpoFpPosition) => void;
|
|
17
|
+
export type ErrorCallback = (e: Error) => void;
|
|
18
|
+
export interface ExpoFpLocationSettings {
|
|
19
|
+
appKey: string;
|
|
20
|
+
token: string;
|
|
21
|
+
secret: string;
|
|
22
|
+
navigationType: "all" | "GEO" | "IPS";
|
|
23
|
+
isBackgroundUpdateEnabled: boolean;
|
|
24
|
+
isBluetoothEnabled: boolean;
|
|
25
|
+
isHeadingEnabled: boolean;
|
|
26
|
+
aliases?: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
export type ExpoFpPosition = {
|
|
29
|
+
x?: number;
|
|
30
|
+
y?: number;
|
|
31
|
+
z?: string | number;
|
|
32
|
+
angle?: number;
|
|
33
|
+
lat?: number;
|
|
34
|
+
lng?: number;
|
|
35
|
+
};
|
|
36
|
+
export type ExpoFpProviderInfo = {
|
|
37
|
+
deviceId?: string | null;
|
|
38
|
+
isLocationUpdating: boolean;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,2CAA2C;IAC1D,KAAK,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrD,oBAAoB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpD,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,+BAA+B;IAC9C,KAAK,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrE,qBAAqB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrD,oBAAoB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpD,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClD,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,WAAW,CAAC;IAChE,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG,WAAW,CAAC;CAC/C;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC,MAAM,MAAM,sBAAsB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;AAE/C,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IACtC,yBAAyB,EAAE,OAAO,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAGD,MAAM,MAAM,cAAc,GAAG;IAC3B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC"}
|