react-native-move-sdk 2.4.2 → 2.4.3
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/android/build.gradle +2 -4
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/in/dolph/move/sdk/BluetoothConnectionsReceiver.kt +96 -0
- package/android/src/main/java/in/dolph/move/sdk/DeviceScanner.kt +186 -0
- package/android/src/main/java/in/dolph/move/sdk/Mapper.kt +27 -0
- package/android/src/main/java/in/dolph/move/sdk/MoveExtensions.kt +9 -0
- package/android/src/main/java/in/dolph/move/sdk/MoveSdkModule.kt +67 -2
- package/android/src/main/java/in/dolph/move/sdk/NativeMoveSdkWrapper.kt +101 -12
- package/ios/NativeModule/MoveSdk.h +14 -1
- package/ios/NativeModule/MoveSdk.swift +141 -12
- package/ios/NativeModule/MoveSdkDeviceScanner.swift +127 -0
- package/lib/commonjs/index.js +37 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +37 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +25 -1
- package/package.json +1 -1
- package/react-native-move-sdk.podspec +1 -1
- package/src/index.ts +62 -2
|
@@ -5,14 +5,19 @@ import android.content.Context
|
|
|
5
5
|
import android.util.Log
|
|
6
6
|
import com.facebook.react.bridge.Promise
|
|
7
7
|
import com.facebook.react.bridge.ReadableArray
|
|
8
|
-
import
|
|
8
|
+
import com.facebook.react.bridge.ReadableMap
|
|
9
|
+
import com.google.gson.Gson
|
|
10
|
+
import io.dolphin.move.DeviceDiscovery
|
|
9
11
|
import io.dolphin.move.DrivingService
|
|
12
|
+
import io.dolphin.move.MoveAssistanceCallStatus
|
|
10
13
|
import io.dolphin.move.MoveAuth
|
|
11
14
|
import io.dolphin.move.MoveAuthState
|
|
12
15
|
import io.dolphin.move.MoveConfig
|
|
13
16
|
import io.dolphin.move.MoveConfigurationError
|
|
14
17
|
import io.dolphin.move.MoveDetectionService
|
|
18
|
+
import io.dolphin.move.MoveDevice
|
|
15
19
|
import io.dolphin.move.MoveOptions
|
|
20
|
+
import io.dolphin.move.MoveScanResult
|
|
16
21
|
import io.dolphin.move.MoveSdk
|
|
17
22
|
import io.dolphin.move.MoveSdkState
|
|
18
23
|
import io.dolphin.move.MoveServiceFailure
|
|
@@ -20,11 +25,16 @@ import io.dolphin.move.MoveServiceWarning
|
|
|
20
25
|
import io.dolphin.move.MoveShutdownResult
|
|
21
26
|
import io.dolphin.move.MoveTripState
|
|
22
27
|
import io.dolphin.move.WalkingService
|
|
28
|
+
import kotlinx.coroutines.CoroutineScope
|
|
29
|
+
import kotlinx.coroutines.Dispatchers
|
|
30
|
+
import kotlinx.coroutines.launch
|
|
31
|
+
import kotlinx.coroutines.withContext
|
|
23
32
|
|
|
24
33
|
@SuppressLint("StaticFieldLeak", "MissingPermission")
|
|
25
34
|
class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener,
|
|
26
35
|
MoveSdk.InitializeListener, MoveSdk.TripStateListener, MoveSdk.AuthStateUpdateListener,
|
|
27
|
-
MoveSdk.MoveLogCallback, MoveSdk.MoveErrorListener, MoveSdk.MoveWarningListener
|
|
36
|
+
MoveSdk.MoveLogCallback, MoveSdk.MoveErrorListener, MoveSdk.MoveWarningListener,
|
|
37
|
+
MoveSdk.DeviceDiscoveryListener {
|
|
28
38
|
|
|
29
39
|
companion object {
|
|
30
40
|
|
|
@@ -40,8 +50,12 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
private val configRepository = MoveSdkConfigRepository(context)
|
|
53
|
+
private val deviceScanner = DeviceScanner(context)
|
|
43
54
|
|
|
44
55
|
private var delegate: MoveSdkModule? = null
|
|
56
|
+
private val mainScope = CoroutineScope(Dispatchers.Main)
|
|
57
|
+
private val ioContext = Dispatchers.IO
|
|
58
|
+
private val gson = Gson()
|
|
45
59
|
|
|
46
60
|
fun init(context: Context) {
|
|
47
61
|
val moveSdk = MoveSdk.init(context.applicationContext)
|
|
@@ -55,6 +69,8 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
55
69
|
moveSdk.setServiceErrorListener(this)
|
|
56
70
|
moveSdk.setServiceWarningListener(this)
|
|
57
71
|
|
|
72
|
+
moveSdk.deviceDiscoveryListener(this)
|
|
73
|
+
|
|
58
74
|
// Initialize notifications by default (might be overwritten by setup)
|
|
59
75
|
val config: MoveSdkConfig = configRepository.loadConfig()
|
|
60
76
|
try {
|
|
@@ -87,7 +103,7 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
87
103
|
timelineDetectionServices: ReadableArray,
|
|
88
104
|
drivingServices: ReadableArray,
|
|
89
105
|
walkingServices: ReadableArray,
|
|
90
|
-
options:
|
|
106
|
+
options: ReadableMap?,
|
|
91
107
|
// Platform config
|
|
92
108
|
recognitionNotificationTitle: String,
|
|
93
109
|
recognitionNotificationText: String,
|
|
@@ -149,7 +165,27 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
149
165
|
// TODO - just use recognition notification for now
|
|
150
166
|
val walkingNotification = recognitionNotification
|
|
151
167
|
|
|
152
|
-
val featureOptions = options
|
|
168
|
+
val featureOptions = options?.toHashMap()
|
|
169
|
+
val moveOptions = try {
|
|
170
|
+
val motionPermissionMandatory = featureOptions?.get("motionPermissionMandatory") as? Boolean
|
|
171
|
+
val deviceDiscovery = featureOptions?.get("deviceDiscovery") as? Map<String, Any>
|
|
172
|
+
val startDelay = deviceDiscovery?.get("startDelay") as? Double
|
|
173
|
+
val duration = deviceDiscovery?.get("duration") as? Double
|
|
174
|
+
val interval = deviceDiscovery?.get("interval") as? Double
|
|
175
|
+
val stopScanOnFirstDiscovered = deviceDiscovery?.get("stopScanOnFirstDiscovered") as? Boolean
|
|
176
|
+
MoveOptions(
|
|
177
|
+
motionPermissionRequired = motionPermissionMandatory ?: false,
|
|
178
|
+
deviceDiscovery = DeviceDiscovery(
|
|
179
|
+
startDelay = startDelay?.toLong(),
|
|
180
|
+
duration = duration?.toLong(),
|
|
181
|
+
interval = interval?.toLong(),
|
|
182
|
+
stopScanOnFirstDiscovered = stopScanOnFirstDiscovered ?: false,
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
} catch (e: Exception) {
|
|
186
|
+
Log.e(MoveSdkModule.LOG_TAG, "setup: ${e.message}", e)
|
|
187
|
+
null
|
|
188
|
+
}
|
|
153
189
|
|
|
154
190
|
try {
|
|
155
191
|
Log.d(MoveSdkModule.LOG_TAG, "MOVE SDK Version " + MoveSdk.version)
|
|
@@ -166,11 +202,6 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
166
202
|
it.walkingLocationNotification(walkingNotification.toAndroidNotification(context))
|
|
167
203
|
}
|
|
168
204
|
val moveConfig = MoveConfig(timelineDetectionServicesToUse)
|
|
169
|
-
val moveOptions = MoveOptions(
|
|
170
|
-
motionPermissionRequired = featureOptions.contains(
|
|
171
|
-
MoveOptions::class.java.declaredFields[0].name
|
|
172
|
-
),
|
|
173
|
-
)
|
|
174
205
|
MoveSdk.setup(
|
|
175
206
|
auth = moveAuth,
|
|
176
207
|
config = moveConfig,
|
|
@@ -212,7 +243,7 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
212
243
|
configRepository.clear()
|
|
213
244
|
|
|
214
245
|
MoveSdk.get()?.shutdown(force) { result ->
|
|
215
|
-
when(result) {
|
|
246
|
+
when (result) {
|
|
216
247
|
MoveShutdownResult.SUCCESS -> promise?.resolve(result.name.toSnakeCase())
|
|
217
248
|
MoveShutdownResult.NETWORK_ERROR,
|
|
218
249
|
MoveShutdownResult.UNINITIALIZED -> promise?.reject(Exception(result.name.toSnakeCase()))
|
|
@@ -387,7 +418,11 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
387
418
|
delegate?.emitDeviceEvent(eventName, eventData)
|
|
388
419
|
}
|
|
389
420
|
|
|
390
|
-
|
|
421
|
+
fun emitDeviceEvent(eventName: String, eventData: Array<Any>) {
|
|
422
|
+
delegate?.emitDeviceEvent(eventName, eventData)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
fun emitDeviceEvent(eventName: String, eventData: String) {
|
|
391
426
|
delegate?.emitDeviceEvent(eventName, eventData)
|
|
392
427
|
}
|
|
393
428
|
|
|
@@ -411,12 +446,66 @@ class NativeMoveSdkWrapper(private val context: Context) : MoveSdk.StateListener
|
|
|
411
446
|
}
|
|
412
447
|
|
|
413
448
|
fun getDeviceQualifier(): String? {
|
|
414
|
-
return
|
|
449
|
+
return MoveSdk.get()?.getDeviceQualifier()
|
|
415
450
|
}
|
|
416
451
|
|
|
417
452
|
fun isAuthValid(): Boolean {
|
|
418
453
|
return MoveSdk.get()?.getAuthState() is MoveAuthState.VALID
|
|
419
454
|
}
|
|
455
|
+
|
|
456
|
+
override fun onScanResult(results: List<MoveScanResult>) {
|
|
457
|
+
emitDeviceEvent(EVENT_MOVE_SCAN_RESULT, results.toScanResultArray())
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
fun registerDevices(rawData: ArrayList<Map<String, String>>?) {
|
|
461
|
+
val devices = rawData?.mapNotNull {
|
|
462
|
+
try {
|
|
463
|
+
gson.fromJson(it["data"], MoveDevice::class.java)
|
|
464
|
+
} catch (e: Exception) {
|
|
465
|
+
null
|
|
466
|
+
}
|
|
467
|
+
}.orEmpty()
|
|
468
|
+
MoveSdk.get()?.registerDevices(devices)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
fun unregisterDevices(rawData: ArrayList<Map<String, String>>?) {
|
|
472
|
+
val devices = rawData?.mapNotNull {
|
|
473
|
+
try {
|
|
474
|
+
gson.fromJson(it["data"], MoveDevice::class.java)
|
|
475
|
+
} catch (e: Exception) {
|
|
476
|
+
null
|
|
477
|
+
}
|
|
478
|
+
}.orEmpty()
|
|
479
|
+
MoveSdk.get()?.unregisterDevices(devices)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
fun getRegisteredDevices(promise: Promise) {
|
|
483
|
+
mainScope.launch {
|
|
484
|
+
val devices = mutableListOf<MoveDevice>()
|
|
485
|
+
withContext(ioContext) {
|
|
486
|
+
MoveSdk.get()?.getRegisteredDevices()?.let(devices::addAll)
|
|
487
|
+
}
|
|
488
|
+
promise.resolve(devices.toMoveDeviceTypedArray().toWritableArray())
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
fun startScanningDevices(filters: List<String>, manufacturerId: Int?, uuid: String?) {
|
|
493
|
+
deviceScanner.startScanning(
|
|
494
|
+
filters,
|
|
495
|
+
manufacturerId.takeIf { it != -1 },
|
|
496
|
+
uuid,
|
|
497
|
+
onNewDevices = {
|
|
498
|
+
emitDeviceEvent(EVENT_MOVE_DEVICES, it.toMoveDeviceTypedArray())
|
|
499
|
+
},
|
|
500
|
+
onNewEvent = { eventName, value ->
|
|
501
|
+
emitDeviceEvent(EVENT_MOVE_SDK_APP, "$eventName ${value ?: ""}".trim())
|
|
502
|
+
},
|
|
503
|
+
)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
fun stopScanningDevices() {
|
|
507
|
+
deviceScanner.stopScanning()
|
|
508
|
+
}
|
|
420
509
|
}
|
|
421
510
|
|
|
422
511
|
fun List<MoveServiceFailure>.failuresToArray(): Array<Any> {
|
|
@@ -20,7 +20,7 @@ RCT_EXTERN_METHOD(setup: (NSString *)contractId
|
|
|
20
20
|
timelineDetectionServices: (NSArray<NSString> *)timelineDetectionServices
|
|
21
21
|
drivingServices: (NSArray<NSString> *)drivingServices
|
|
22
22
|
walkingServices: (NSArray<NSString> *)walkingServices
|
|
23
|
-
options: (
|
|
23
|
+
options: (id)options
|
|
24
24
|
resolve: (RCTPromiseResolveBlock)resolve
|
|
25
25
|
reject: (RCTPromiseRejectBlock)reject)
|
|
26
26
|
|
|
@@ -62,6 +62,19 @@ RCT_EXTERN_METHOD(ignoreCurrentTrip)
|
|
|
62
62
|
|
|
63
63
|
RCT_EXTERN_METHOD(finishCurrentTrip)
|
|
64
64
|
|
|
65
|
+
RCT_EXTERN_METHOD(startScanningDevices: (NSArray*) filter
|
|
66
|
+
uuid: (NSString*) uuid
|
|
67
|
+
manufacturerId: (id)manufacturerId)
|
|
68
|
+
|
|
69
|
+
RCT_EXTERN_METHOD(stopScanningDevices)
|
|
70
|
+
|
|
71
|
+
RCT_EXTERN_METHOD(registerDevices: (NSArray*>)devices)
|
|
72
|
+
|
|
73
|
+
RCT_EXTERN_METHOD(unregisterDevices: (NSArray*>)devices)
|
|
74
|
+
|
|
75
|
+
RCT_EXTERN_METHOD(getRegisteredDevices: (RCTPromiseResolveBlock)resolve
|
|
76
|
+
rejecter: (RCTPromiseRejectBlock)reject)
|
|
77
|
+
|
|
65
78
|
RCT_EXTERN_METHOD(getAuthState: (RCTPromiseResolveBlock)resolve
|
|
66
79
|
rejecter: (RCTPromiseRejectBlock)reject)
|
|
67
80
|
|
|
@@ -3,7 +3,7 @@ import Foundation
|
|
|
3
3
|
import DolphinMoveSDK
|
|
4
4
|
|
|
5
5
|
internal protocol MoveSDKLauncherDelegate: AnyObject {
|
|
6
|
-
func send(event: MoveSDKLauncher.Event, data:
|
|
6
|
+
func send(event: MoveSDKLauncher.Event, data: Any)
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
typealias MoveSDKErrorListItem = [String:Any]
|
|
@@ -33,6 +33,7 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
let motionManager = CMMotionActivityManager()
|
|
36
|
+
var scanner: MoveSdkDeviceScanner?
|
|
36
37
|
|
|
37
38
|
override func startObserving() {
|
|
38
39
|
MoveSDKLauncher.shared.delegate = self
|
|
@@ -46,7 +47,7 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
46
47
|
timelineDetectionServices: Array<String>,
|
|
47
48
|
drivingServices: Array<String>,
|
|
48
49
|
walkingServices: Array<String>,
|
|
49
|
-
options:
|
|
50
|
+
options: Any,
|
|
50
51
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
51
52
|
reject: @escaping RCTPromiseRejectBlock) {
|
|
52
53
|
|
|
@@ -94,10 +95,7 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
94
95
|
// TODO: Fix wrapper and add config option from RN for walking services (actually only 1 now)
|
|
95
96
|
let sdkConfig = MoveConfig(detectionService: transformedDetectionServices)
|
|
96
97
|
let auth = MoveAuth(userToken: accessToken, refreshToken: refreshToken, userID: contractId, projectID: productId)
|
|
97
|
-
|
|
98
|
-
if options.contains("MOTION_PERMISSION_REQUIRE") {
|
|
99
|
-
moveOptions.insert(.motionPermissionMandatory)
|
|
100
|
-
}
|
|
98
|
+
let moveOptions = convert(options: options)
|
|
101
99
|
|
|
102
100
|
MoveSDKLauncher.shared.setup(auth: auth, config: sdkConfig, options: moveOptions)
|
|
103
101
|
resolve("OK")
|
|
@@ -106,6 +104,36 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
|
|
107
|
+
private func convert(options: Any) -> MoveOptions {
|
|
108
|
+
let moveOptions = MoveOptions()
|
|
109
|
+
|
|
110
|
+
if let opts = options as? [String: Any] {
|
|
111
|
+
if let value = opts["motionPermissionMandatory"] as? Bool {
|
|
112
|
+
moveOptions.motionPermissionMandatory = value
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if let deviceDiscovery = opts["deviceDiscovery"] as? [String: Any] {
|
|
116
|
+
if let value = deviceDiscovery["startDelay"] as? Double {
|
|
117
|
+
moveOptions.deviceDiscovery.startDelay = value
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if let value = deviceDiscovery["duration"] as? Double {
|
|
121
|
+
moveOptions.deviceDiscovery.duration = value
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if let value = deviceDiscovery["interval"] as? Double {
|
|
125
|
+
moveOptions.deviceDiscovery.interval = value
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if let value = deviceDiscovery["stopScanOnFirstDiscovered"] as? Bool {
|
|
129
|
+
moveOptions.deviceDiscovery.stopScanOnFirstDiscovered = value
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return moveOptions
|
|
135
|
+
}
|
|
136
|
+
|
|
109
137
|
@objc
|
|
110
138
|
func getState(
|
|
111
139
|
_ resolve: RCTPromiseResolveBlock,
|
|
@@ -124,12 +152,26 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
124
152
|
resolve(value)
|
|
125
153
|
}
|
|
126
154
|
|
|
155
|
+
@objc
|
|
156
|
+
func getRegisteredDevices(
|
|
157
|
+
_ resolve: RCTPromiseResolveBlock,
|
|
158
|
+
rejecter reject: RCTPromiseRejectBlock
|
|
159
|
+
) {
|
|
160
|
+
let value = MoveSDKLauncher.shared.convert(devices: MoveSDK.shared.getRegisteredDevices())
|
|
161
|
+
resolve(value)
|
|
162
|
+
}
|
|
163
|
+
|
|
127
164
|
@objc
|
|
128
165
|
func isAuthValid(
|
|
129
166
|
_ resolve: RCTPromiseResolveBlock,
|
|
130
167
|
rejecter reject: RCTPromiseRejectBlock
|
|
131
168
|
) {
|
|
132
|
-
|
|
169
|
+
switch MoveSDK.shared.getAuthState() {
|
|
170
|
+
case .invalid, .expired:
|
|
171
|
+
resolve(false)
|
|
172
|
+
default:
|
|
173
|
+
resolve(true)
|
|
174
|
+
}
|
|
133
175
|
}
|
|
134
176
|
|
|
135
177
|
@objc
|
|
@@ -283,6 +325,32 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
283
325
|
MoveSDKLauncher.shared.sdk.finishCurrentTrip()
|
|
284
326
|
}
|
|
285
327
|
|
|
328
|
+
@objc
|
|
329
|
+
func startScanningDevices(_ filter: [String], uuid: String?, manufacturerId: Any?) {
|
|
330
|
+
if scanner == nil {
|
|
331
|
+
scanner = MoveSdkDeviceScanner()
|
|
332
|
+
}
|
|
333
|
+
scanner?.delegate = self
|
|
334
|
+
scanner?.startScanning(filter: filter, uuid: uuid)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@objc
|
|
338
|
+
func registerDevices(_ devices: [Any]) {
|
|
339
|
+
let devices = MoveSDKLauncher.shared.convert(devices: devices)
|
|
340
|
+
MoveSDKLauncher.shared.sdk.register(devices: devices)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@objc
|
|
344
|
+
func unregisterDevices(_ devices: [Any]) {
|
|
345
|
+
let devices = MoveSDKLauncher.shared.convert(devices: devices)
|
|
346
|
+
MoveSDKLauncher.shared.sdk.unregister(devices: devices)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
@objc
|
|
350
|
+
func stopScanningDevices() {
|
|
351
|
+
scanner?.stopScanning()
|
|
352
|
+
}
|
|
353
|
+
|
|
286
354
|
@objc
|
|
287
355
|
func resolveError() {
|
|
288
356
|
MoveSDKLauncher.shared.sdk.resolveSDKStateError()
|
|
@@ -322,8 +390,14 @@ class RCTMoveSdk: RCTEventEmitter {
|
|
|
322
390
|
}
|
|
323
391
|
}
|
|
324
392
|
|
|
393
|
+
extension RCTMoveSdk: MoveSdkDeviceScannerDelegate {
|
|
394
|
+
func didDiscover(devices: [MoveSdkDeviceScanner.DeviceEntry]) {
|
|
395
|
+
send(event: .devices, data: MoveSDKLauncher.shared.convert(devices: devices))
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
325
399
|
extension RCTMoveSdk: MoveSDKLauncherDelegate {
|
|
326
|
-
func send(event: MoveSDKLauncher.Event, data:
|
|
400
|
+
func send(event: MoveSDKLauncher.Event, data: Any) {
|
|
327
401
|
sendEvent(withName: event.rawValue, body: data)
|
|
328
402
|
}
|
|
329
403
|
}
|
|
@@ -336,6 +410,8 @@ internal class MoveSDKLauncher {
|
|
|
336
410
|
case authState = "MOVE_SDK_AUTH_STATE"
|
|
337
411
|
case warning = "MOVE_SDK_WARNINGS"
|
|
338
412
|
case failure = "MOVE_SDK_ERRORS"
|
|
413
|
+
case devices = "MOVE_SDK_DEVICES"
|
|
414
|
+
case scanResult = "MOVE_SDK_SCAN_RESULT"
|
|
339
415
|
}
|
|
340
416
|
|
|
341
417
|
private enum DefaultsKey: String {
|
|
@@ -375,6 +451,11 @@ internal class MoveSDKLauncher {
|
|
|
375
451
|
let data: [String: Any] = ["warnings": self.convert(warnings: warnings)]
|
|
376
452
|
self.delegate?.send(event: .warning, data: data)
|
|
377
453
|
}
|
|
454
|
+
|
|
455
|
+
sdk.setDeviceDiscoveryListener { scanResults in
|
|
456
|
+
let data = self.convert(scanResults: scanResults)
|
|
457
|
+
self.delegate?.send(event: .scanResult, data: data)
|
|
458
|
+
}
|
|
378
459
|
}
|
|
379
460
|
|
|
380
461
|
func getServiceWarnings() -> [MoveSDKErrorListItem] {
|
|
@@ -385,6 +466,58 @@ internal class MoveSDKLauncher {
|
|
|
385
466
|
return convert(failures: sdk.getServiceFailures())
|
|
386
467
|
}
|
|
387
468
|
|
|
469
|
+
func convert(devices: [Any]) -> [MoveDevice] {
|
|
470
|
+
return devices.compactMap { values in
|
|
471
|
+
guard let values = values as? [String: String] else { return nil }
|
|
472
|
+
// let name: String = values["name"] ?? ""
|
|
473
|
+
let encoded: String = values["data"] ?? ""
|
|
474
|
+
|
|
475
|
+
let decoder = JSONDecoder()
|
|
476
|
+
guard let data = encoded.data(using: .utf8) else { return nil }
|
|
477
|
+
do {
|
|
478
|
+
let device = try decoder.decode(MoveDevice.self, from: data)
|
|
479
|
+
/* keep device name from info */
|
|
480
|
+
return device
|
|
481
|
+
} catch {
|
|
482
|
+
return nil
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
func convert(devices: [MoveSdkDeviceScanner.DeviceEntry]) -> [[String:String]] {
|
|
488
|
+
var deviceList: [[String: String]] = []
|
|
489
|
+
for device in devices {
|
|
490
|
+
let encoder = JSONEncoder()
|
|
491
|
+
do {
|
|
492
|
+
let data = try encoder.encode(device.device)
|
|
493
|
+
let str = String(data: data, encoding: .utf8) ?? ""
|
|
494
|
+
let info: [String: String] = ["name":device.name, "data": str]
|
|
495
|
+
deviceList.append(info)
|
|
496
|
+
} catch {
|
|
497
|
+
print(error.localizedDescription)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return deviceList
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
func convert(scanResults: [MoveScanResult]) -> [[String:Any]] {
|
|
505
|
+
var deviceList: [[String: Any]] = []
|
|
506
|
+
for result in scanResults {
|
|
507
|
+
let encoder = JSONEncoder()
|
|
508
|
+
do {
|
|
509
|
+
let data = try encoder.encode(result.device)
|
|
510
|
+
let str = String(data: data, encoding: .utf8) ?? ""
|
|
511
|
+
let info: [String: Any] = ["name":result.device.name, "device": str, "isDiscovered": result.isDiscovered]
|
|
512
|
+
deviceList.append(info)
|
|
513
|
+
} catch {
|
|
514
|
+
print(error.localizedDescription)
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return deviceList
|
|
519
|
+
}
|
|
520
|
+
|
|
388
521
|
func convert(service: DolphinMoveSDK.MoveConfig.DetectionService) -> String {
|
|
389
522
|
return service.debugDescription
|
|
390
523
|
// switch service {
|
|
@@ -428,8 +561,6 @@ internal class MoveSDKLauncher {
|
|
|
428
561
|
reasons = content
|
|
429
562
|
case .unauthorized:
|
|
430
563
|
reasons = ["Unauthorized"]
|
|
431
|
-
@unknown default:
|
|
432
|
-
break
|
|
433
564
|
}
|
|
434
565
|
converted.append(["service": convert(service: failure.service), "reasons": reasons])
|
|
435
566
|
}
|
|
@@ -446,8 +577,6 @@ internal class MoveSDKLauncher {
|
|
|
446
577
|
case let .missingPermission(permissions):
|
|
447
578
|
let content: [String] = permissions.map { self.permissionString($0) }
|
|
448
579
|
reasons = content
|
|
449
|
-
@unknown default:
|
|
450
|
-
break
|
|
451
580
|
}
|
|
452
581
|
converted.append(["service": convert(service: warning.service), "reasons": reasons])
|
|
453
582
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import CoreLocation
|
|
3
|
+
import Foundation
|
|
4
|
+
import DolphinMoveSDK
|
|
5
|
+
|
|
6
|
+
internal protocol MoveSdkDeviceScannerDelegate: AnyObject {
|
|
7
|
+
func didDiscover(devices: [MoveSdkDeviceScanner.DeviceEntry])
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
internal class MoveSdkDeviceScanner: NSObject {
|
|
11
|
+
struct DeviceEntry {
|
|
12
|
+
let device: MoveDevice
|
|
13
|
+
let name: String
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private let allowedPorts: [AVAudioSession.Port] = [.bluetoothA2DP, .bluetoothHFP, .bluetoothLE, .carAudio]
|
|
17
|
+
|
|
18
|
+
private let session = AVAudioSession.sharedInstance()
|
|
19
|
+
private let locationManager = CLLocationManager()
|
|
20
|
+
private var devices: [DeviceEntry] = []
|
|
21
|
+
private var timer: Timer?
|
|
22
|
+
private var beaconRegion: CLBeaconRegion?
|
|
23
|
+
internal var delegate: MoveSdkDeviceScannerDelegate?
|
|
24
|
+
|
|
25
|
+
override init() {
|
|
26
|
+
super.init()
|
|
27
|
+
locationManager.delegate = self
|
|
28
|
+
do {
|
|
29
|
+
try session.setCategory(.playAndRecord, options: [.allowAirPlay, .allowBluetoothA2DP, .allowBluetooth])
|
|
30
|
+
} catch {
|
|
31
|
+
print("\(error)")
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func scanAudioPorts() {
|
|
36
|
+
let devices: [DeviceEntry] = (session.availableInputs ?? []).compactMap {
|
|
37
|
+
if !allowedPorts.contains($0.portType) { return nil }
|
|
38
|
+
let device = MoveDevice(name: $0.uid, id: $0.uid)
|
|
39
|
+
return DeviceEntry(device: device, name: "\($0.portName)")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
add(devices: devices)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func scanBeacons(uuid: UUID) {
|
|
46
|
+
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, identifier: "beacons [\(uuid)]")
|
|
47
|
+
locationManager.startRangingBeacons(in: beaconRegion)
|
|
48
|
+
locationManager.requestState(for: beaconRegion)
|
|
49
|
+
self.beaconRegion = beaconRegion
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func add(devices: [DeviceEntry]) {
|
|
53
|
+
let devices = devices.filter { device in
|
|
54
|
+
!self.devices.contains { $0.device == device.device }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if !devices.isEmpty {
|
|
58
|
+
self.devices += devices
|
|
59
|
+
delegate?.didDiscover(devices: devices)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func startScanning(filter: [String], uuid uuidString: String? = nil) {
|
|
64
|
+
devices = []
|
|
65
|
+
|
|
66
|
+
if filter.contains("paired") {
|
|
67
|
+
self.scanAudioPorts()
|
|
68
|
+
|
|
69
|
+
let timer = Timer(timeInterval: 1.0, repeats: true) { _ in
|
|
70
|
+
self.scanAudioPorts()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
self.timer = timer
|
|
74
|
+
|
|
75
|
+
RunLoop.main.add(timer, forMode: .default)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if filter.contains("beacon"), let uuidString = uuidString, let uuid = UUID(uuidString: uuidString) {
|
|
79
|
+
scanBeacons(uuid: uuid)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func stopScanning() {
|
|
84
|
+
if let beaconRegion = self.beaconRegion {
|
|
85
|
+
locationManager.stopRangingBeacons(in: beaconRegion)
|
|
86
|
+
}
|
|
87
|
+
timer?.invalidate()
|
|
88
|
+
timer = nil
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
extension MoveSdkDeviceScanner: CLLocationManagerDelegate {
|
|
93
|
+
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
|
|
94
|
+
|
|
95
|
+
let devices = beacons.map {
|
|
96
|
+
let name = "Beacon \($0.major):\($0.minor)"
|
|
97
|
+
let device = MoveDevice(name: name, proximityUUID: $0.proximityUUID, major: UInt16(truncating: $0.major), minor: UInt16(truncating: $0.minor))
|
|
98
|
+
return DeviceEntry(device: device, name: name)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
add(devices: devices)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func locationManager(_ manager: CLLocationManager, rangingBeaconsDidFailFor region: CLBeaconRegion, withError error: Error) {
|
|
105
|
+
print("rangingBeaconsDidFailFor: \(region)")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
|
109
|
+
print("fail: \(error)")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
|
|
113
|
+
print("monitoringDidFailFor: \(String(describing: region)) \(error)")
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
|
|
117
|
+
print("didEnterRegion: \(region)")
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
|
|
121
|
+
print("didExitRegion: \(region)")
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
|
|
125
|
+
print("didDetermineState: \(region) : \(state)")
|
|
126
|
+
}
|
|
127
|
+
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -70,7 +70,7 @@ class MoveSdk {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
return await NativeMoveSdk.setup(userId, accessToken, refreshToken, projectId, // Config
|
|
73
|
-
timelineDetectionServices, drivingServices, walkingServices, options
|
|
73
|
+
timelineDetectionServices, drivingServices, walkingServices, options, // Platform config
|
|
74
74
|
...platformParams);
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -262,6 +262,42 @@ class MoveSdk {
|
|
|
262
262
|
} // **** PERMISSIONS MODULE END *****
|
|
263
263
|
|
|
264
264
|
|
|
265
|
+
static startScanningDevices(sdkDevicesDetected) {
|
|
266
|
+
let filter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ["paired"];
|
|
267
|
+
let uuid = arguments.length > 2 ? arguments[2] : undefined;
|
|
268
|
+
let manufacturerId = arguments.length > 3 ? arguments[3] : undefined;
|
|
269
|
+
const subscription = eventEmitter.addListener('MOVE_SDK_DEVICES', devices => {
|
|
270
|
+
sdkDevicesDetected(devices);
|
|
271
|
+
});
|
|
272
|
+
const subscriptionRemove = subscription.remove;
|
|
273
|
+
|
|
274
|
+
subscription.remove = () => {
|
|
275
|
+
NativeMoveSdk.stopScanningDevices();
|
|
276
|
+
subscriptionRemove();
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
NativeMoveSdk.startScanningDevices(filter, uuid, manufacturerId !== null && manufacturerId !== void 0 ? manufacturerId : -1);
|
|
280
|
+
return subscription;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
static async getRegisteredDevices() {
|
|
284
|
+
return await NativeMoveSdk.getRegisteredDevices();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static registerDevices(devices) {
|
|
288
|
+
NativeMoveSdk.registerDevices(devices);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static unregisterDevices(devices) {
|
|
292
|
+
NativeMoveSdk.registerDevices(devices);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
static addDeviceDiscoveryListener(onScanResult) {
|
|
296
|
+
return eventEmitter.addListener('MOVE_SDK_SCAN_RESULT', results => {
|
|
297
|
+
onScanResult(results);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
265
301
|
}
|
|
266
302
|
|
|
267
303
|
exports.default = MoveSdk;
|