ilabs-flir 2.0.5 → 2.0.7
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/README.md +2 -0
- package/android/Flir/src/main/java/flir/android/FlirManager.kt +40 -0
- package/android/Flir/src/main/java/flir/android/FlirModule.kt +40 -0
- package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +135 -0
- package/ios/Flir/src/FlirEventEmitter.m +1 -1
- package/ios/Flir/src/FlirModule.h +3 -0
- package/ios/Flir/src/FlirModule.m +57 -4
- package/package.json +2 -4
- package/scripts/fetch-binaries.js +58 -14
package/README.md
CHANGED
|
@@ -118,6 +118,8 @@ cd ios
|
|
|
118
118
|
pod install
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
Note: If you installed `ilabs-flir` via npm, `Podfile` autolinking will declare the `Flir` pod for your app automatically. To avoid duplicates, the published npm package will not contain `Flir.podspec` or in-repo podspecs; they are excluded with `.npmignore`. See `docs/MIGRATION_TO_NPM.md` for migration details if you previously used an in-repo `Flir.podspec`.
|
|
122
|
+
|
|
121
123
|
##### Building Without FLIR SDK (No Paid License)
|
|
122
124
|
|
|
123
125
|
If you don't have a paid FLIR developer license, you can build the app without the FLIR SDK. The module will provide fallback stub implementations:
|
|
@@ -63,6 +63,23 @@ object FlirManager {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
fun getLatestBitmap(): Bitmap? = latestBitmap
|
|
66
|
+
|
|
67
|
+
// Preference: ask SDK to deliver oriented/rotated frames (if SDK supports it)
|
|
68
|
+
fun setPreferSdkRotation(prefer: Boolean) {
|
|
69
|
+
sdkManager?.setPreferSdkRotation(prefer)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fun isPreferSdkRotation(): Boolean {
|
|
73
|
+
return sdkManager?.isPreferSdkRotation() ?: false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun getBatteryLevel(): Int {
|
|
77
|
+
return sdkManager?.getBatteryLevel() ?: -1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fun isBatteryCharging(): Boolean {
|
|
81
|
+
return sdkManager?.isBatteryCharging() ?: false
|
|
82
|
+
}
|
|
66
83
|
|
|
67
84
|
/**
|
|
68
85
|
* Initialize the FLIR SDK
|
|
@@ -335,6 +352,11 @@ object FlirManager {
|
|
|
335
352
|
Log.e(TAG, "Error: $message")
|
|
336
353
|
emitError(message)
|
|
337
354
|
}
|
|
355
|
+
|
|
356
|
+
override fun onBatteryUpdated(level: Int, isCharging: Boolean) {
|
|
357
|
+
Log.d(TAG, "onBatteryUpdated: level=$level charging=$isCharging")
|
|
358
|
+
emitBatteryState(level, isCharging)
|
|
359
|
+
}
|
|
338
360
|
}
|
|
339
361
|
|
|
340
362
|
// React Native event emitters
|
|
@@ -411,6 +433,24 @@ object FlirManager {
|
|
|
411
433
|
Log.e(TAG, "Failed to emit devices found", e)
|
|
412
434
|
}
|
|
413
435
|
}
|
|
436
|
+
|
|
437
|
+
private fun emitBatteryState(level: Int, isCharging: Boolean) {
|
|
438
|
+
val ctx = reactContext
|
|
439
|
+
if (ctx == null) {
|
|
440
|
+
Log.w(TAG, "Cannot emit FlirBatteryUpdated - reactContext is null!")
|
|
441
|
+
return
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
val params = Arguments.createMap().apply {
|
|
445
|
+
putInt("level", level)
|
|
446
|
+
putBoolean("isCharging", isCharging)
|
|
447
|
+
}
|
|
448
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
449
|
+
.emit("FlirBatteryUpdated", params)
|
|
450
|
+
} catch (e: Exception) {
|
|
451
|
+
Log.e(TAG, "Failed to emit battery state", e)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
414
454
|
|
|
415
455
|
private fun emitError(message: String) {
|
|
416
456
|
val ctx = reactContext ?: return
|
|
@@ -147,6 +147,46 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
147
147
|
promise.reject("ERR_FLIR_DEVICES", e)
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
+
|
|
151
|
+
@ReactMethod
|
|
152
|
+
fun setPreferSdkRotation(prefer: Boolean, promise: Promise) {
|
|
153
|
+
try {
|
|
154
|
+
FlirManager.setPreferSdkRotation(prefer)
|
|
155
|
+
promise.resolve(true)
|
|
156
|
+
} catch (e: Exception) {
|
|
157
|
+
promise.reject("ERR_FLIR_SET_ROTATION_PREF", e)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@ReactMethod
|
|
162
|
+
fun isPreferSdkRotation(promise: Promise) {
|
|
163
|
+
try {
|
|
164
|
+
val v = FlirManager.isPreferSdkRotation()
|
|
165
|
+
promise.resolve(v)
|
|
166
|
+
} catch (e: Exception) {
|
|
167
|
+
promise.reject("ERR_FLIR_GET_ROTATION_PREF", e)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@ReactMethod
|
|
172
|
+
fun getBatteryLevel(promise: Promise) {
|
|
173
|
+
try {
|
|
174
|
+
val level = FlirManager.getBatteryLevel()
|
|
175
|
+
promise.resolve(level)
|
|
176
|
+
} catch (e: Exception) {
|
|
177
|
+
promise.reject("ERR_FLIR_GET_BATTERY", e)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@ReactMethod
|
|
182
|
+
fun isBatteryCharging(promise: Promise) {
|
|
183
|
+
try {
|
|
184
|
+
val v = FlirManager.isBatteryCharging()
|
|
185
|
+
promise.resolve(v)
|
|
186
|
+
} catch (e: Exception) {
|
|
187
|
+
promise.reject("ERR_FLIR_CHARGING", e)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
150
190
|
|
|
151
191
|
@ReactMethod
|
|
152
192
|
fun startEmulator(emulatorType: String, promise: Promise) {
|
|
@@ -47,6 +47,10 @@ public class FlirSdkManager {
|
|
|
47
47
|
private final Executor executor = Executors.newFixedThreadPool(2);
|
|
48
48
|
// Single-threaded executor for frame processing to ensure ordered processing
|
|
49
49
|
private final Executor frameExecutor = Executors.newSingleThreadExecutor();
|
|
50
|
+
// Battery poller scheduler - polls battery level & charging state periodically if supported
|
|
51
|
+
private final java.util.concurrent.ScheduledExecutorService batteryPoller = java.util.concurrent.Executors.newSingleThreadScheduledExecutor();
|
|
52
|
+
private volatile int lastPolledBatteryLevel = -1;
|
|
53
|
+
private volatile boolean lastPolledCharging = false;
|
|
50
54
|
// Frame processing guard - skip frames if still processing previous one
|
|
51
55
|
private volatile boolean isProcessingFrame = false;
|
|
52
56
|
private long lastFrameProcessedMs = 0;
|
|
@@ -59,6 +63,8 @@ public class FlirSdkManager {
|
|
|
59
63
|
private ThermalStreamer streamer;
|
|
60
64
|
private Stream activeStream;
|
|
61
65
|
private final List<Identity> discoveredDevices = Collections.synchronizedList(new ArrayList<>());
|
|
66
|
+
// When true, prefer getting SDK-provided rotated frames instead of rotating ourselves
|
|
67
|
+
private volatile boolean preferSdkRotation = false;
|
|
62
68
|
|
|
63
69
|
// Listener
|
|
64
70
|
private Listener listener;
|
|
@@ -73,6 +79,7 @@ public class FlirSdkManager {
|
|
|
73
79
|
void onDisconnected();
|
|
74
80
|
void onFrame(Bitmap bitmap);
|
|
75
81
|
void onError(String message);
|
|
82
|
+
void onBatteryUpdated(int level, boolean isCharging);
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
// Private constructor for singleton
|
|
@@ -96,6 +103,34 @@ public class FlirSdkManager {
|
|
|
96
103
|
public void setListener(Listener listener) {
|
|
97
104
|
this.listener = listener;
|
|
98
105
|
}
|
|
106
|
+
|
|
107
|
+
public void setPreferSdkRotation(boolean prefer) {
|
|
108
|
+
this.preferSdkRotation = prefer;
|
|
109
|
+
// Try to ask SDK streamer to provide rotated images if possible
|
|
110
|
+
if (streamer != null) {
|
|
111
|
+
try {
|
|
112
|
+
// Try common method names via reflection to avoid hard dependency on exact API signature
|
|
113
|
+
Object obj = streamer;
|
|
114
|
+
java.lang.reflect.Method m = null;
|
|
115
|
+
try { m = obj.getClass().getMethod("setImageRotation", int.class); } catch (Throwable ignored) {}
|
|
116
|
+
if (m == null) {
|
|
117
|
+
try { m = obj.getClass().getMethod("setRotation", int.class); } catch (Throwable ignored) {}
|
|
118
|
+
}
|
|
119
|
+
if (m != null) {
|
|
120
|
+
// If caller asked SDK to rotate, choose 0 = 'auto' or prefer flag; here we request SDK to respect device orientation
|
|
121
|
+
int degrees = prefer ? 0 : 0; // SDK-specific - for now, 0 requests orientation-respected frames if method interprets so
|
|
122
|
+
m.invoke(obj, degrees);
|
|
123
|
+
Log.d(TAG, "setPreferSdkRotation: requested SDK rotation via reflection");
|
|
124
|
+
} else {
|
|
125
|
+
Log.w(TAG, "setPreferSdkRotation: SDK does not expose rotation API (reflection check)");
|
|
126
|
+
}
|
|
127
|
+
} catch (Throwable t) {
|
|
128
|
+
Log.w(TAG, "setPreferSdkRotation failed (reflection)", t);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public boolean isPreferSdkRotation() { return preferSdkRotation; }
|
|
99
134
|
|
|
100
135
|
/**
|
|
101
136
|
* Initialize the FLIR Thermal SDK
|
|
@@ -214,6 +249,8 @@ public class FlirSdkManager {
|
|
|
214
249
|
if (listener != null) {
|
|
215
250
|
listener.onConnected(identity);
|
|
216
251
|
}
|
|
252
|
+
// Start battery poller for continuous updates
|
|
253
|
+
startBatteryPoller();
|
|
217
254
|
} catch (Exception e) {
|
|
218
255
|
Log.e(TAG, "Connection failed", e);
|
|
219
256
|
camera = null;
|
|
@@ -236,6 +273,8 @@ public class FlirSdkManager {
|
|
|
236
273
|
}
|
|
237
274
|
camera = null;
|
|
238
275
|
}
|
|
276
|
+
// stop battery poller
|
|
277
|
+
stopBatteryPoller();
|
|
239
278
|
|
|
240
279
|
if (listener != null) {
|
|
241
280
|
listener.onDisconnected();
|
|
@@ -476,6 +515,67 @@ public class FlirSdkManager {
|
|
|
476
515
|
}
|
|
477
516
|
return names;
|
|
478
517
|
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Best-effort: Fetch battery level from connected camera if SDK exposes battery APIs
|
|
521
|
+
* Returns -1 if unavailable
|
|
522
|
+
*/
|
|
523
|
+
public int getBatteryLevel() {
|
|
524
|
+
if (camera == null) return -1;
|
|
525
|
+
try {
|
|
526
|
+
// Common SDK methods to try
|
|
527
|
+
try {
|
|
528
|
+
java.lang.reflect.Method m = camera.getClass().getMethod("getBatteryLevel");
|
|
529
|
+
Object r = m.invoke(camera);
|
|
530
|
+
if (r instanceof Number) return ((Number) r).intValue();
|
|
531
|
+
} catch (Throwable ignored) {}
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
java.lang.reflect.Method m = camera.getClass().getMethod("getBattery");
|
|
535
|
+
Object batt = m.invoke(camera);
|
|
536
|
+
if (batt != null) {
|
|
537
|
+
try {
|
|
538
|
+
java.lang.reflect.Method levelMethod = batt.getClass().getMethod("getLevel");
|
|
539
|
+
Object lv = levelMethod.invoke(batt);
|
|
540
|
+
if (lv instanceof Number) return ((Number) lv).intValue();
|
|
541
|
+
} catch (Throwable ignored) {}
|
|
542
|
+
}
|
|
543
|
+
} catch (Throwable ignored) {}
|
|
544
|
+
} catch (Throwable t) {
|
|
545
|
+
Log.w(TAG, "Error querying battery level", t);
|
|
546
|
+
}
|
|
547
|
+
return -1;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Best-effort: Check if the camera is charging
|
|
552
|
+
* Returns false if unknown
|
|
553
|
+
*/
|
|
554
|
+
public boolean isBatteryCharging() {
|
|
555
|
+
if (camera == null) return false;
|
|
556
|
+
try {
|
|
557
|
+
try {
|
|
558
|
+
java.lang.reflect.Method m = camera.getClass().getMethod("isCharging");
|
|
559
|
+
Object r = m.invoke(camera);
|
|
560
|
+
if (r instanceof Boolean) return (Boolean) r;
|
|
561
|
+
} catch (Throwable ignored) {}
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
java.lang.reflect.Method m = camera.getClass().getMethod("getBattery");
|
|
565
|
+
Object batt = m.invoke(camera);
|
|
566
|
+
if (batt != null) {
|
|
567
|
+
try {
|
|
568
|
+
java.lang.reflect.Method isCh = batt.getClass().getMethod("isCharging");
|
|
569
|
+
Object cv = isCh.invoke(batt);
|
|
570
|
+
if (cv instanceof Boolean) return (Boolean) cv;
|
|
571
|
+
} catch (Throwable ignored) {}
|
|
572
|
+
}
|
|
573
|
+
} catch (Throwable ignored) {}
|
|
574
|
+
} catch (Throwable t) {
|
|
575
|
+
Log.w(TAG, "Error querying battery charging state", t);
|
|
576
|
+
}
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
479
579
|
|
|
480
580
|
// Find palette by name
|
|
481
581
|
private Palette findPalette(String name) {
|
|
@@ -580,4 +680,39 @@ public class FlirSdkManager {
|
|
|
580
680
|
instance = null;
|
|
581
681
|
Log.d(TAG, "Destroyed");
|
|
582
682
|
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Start a background poller to periodically check battery state and notify listener
|
|
686
|
+
*/
|
|
687
|
+
private void startBatteryPoller() {
|
|
688
|
+
try {
|
|
689
|
+
batteryPoller.scheduleAtFixedRate(() -> {
|
|
690
|
+
if (camera == null) return;
|
|
691
|
+
try {
|
|
692
|
+
int level = getBatteryLevel();
|
|
693
|
+
boolean charging = isBatteryCharging();
|
|
694
|
+
if (level != lastPolledBatteryLevel || charging != lastPolledCharging) {
|
|
695
|
+
lastPolledBatteryLevel = level;
|
|
696
|
+
lastPolledCharging = charging;
|
|
697
|
+
if (listener != null) {
|
|
698
|
+
try { listener.onBatteryUpdated(level, charging);} catch (Throwable t) {}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
} catch (Throwable t) {
|
|
702
|
+
Log.w(TAG, "Battery poller error", t);
|
|
703
|
+
}
|
|
704
|
+
}, 0, 5, java.util.concurrent.TimeUnit.SECONDS);
|
|
705
|
+
} catch (Throwable t) {
|
|
706
|
+
Log.w(TAG, "Failed to start battery poller", t);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Stop the battery poller.
|
|
712
|
+
*/
|
|
713
|
+
private void stopBatteryPoller() {
|
|
714
|
+
try {
|
|
715
|
+
batteryPoller.shutdownNow();
|
|
716
|
+
} catch (Throwable ignored) {}
|
|
717
|
+
}
|
|
583
718
|
}
|
|
@@ -32,7 +32,7 @@ RCT_EXPORT_MODULE();
|
|
|
32
32
|
return @[
|
|
33
33
|
@"FlirDeviceConnected", @"FlirDeviceDisconnected", @"FlirDevicesFound",
|
|
34
34
|
@"FlirFrameReceived", @"FlirFrame", @"FlirError", @"FlirStateChanged",
|
|
35
|
-
@"FlirTemperatureUpdate"
|
|
35
|
+
@"FlirTemperatureUpdate", @"FlirBatteryUpdated"
|
|
36
36
|
];
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -12,6 +12,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
12
12
|
|
|
13
13
|
@interface FlirModule : RCTEventEmitter <RCTBridgeModule>
|
|
14
14
|
|
|
15
|
+
// Utility for other native code to emit battery updates (level 0-100 or -1 if unknown)
|
|
16
|
+
+ (void)emitBatteryUpdateWithLevel:(NSInteger)level charging:(BOOL)charging;
|
|
17
|
+
|
|
15
18
|
@end
|
|
16
19
|
|
|
17
20
|
NS_ASSUME_NONNULL_END
|
|
@@ -77,6 +77,7 @@ RCT_EXPORT_MODULE(FlirModule);
|
|
|
77
77
|
@"FlirFrameReceived",
|
|
78
78
|
@"FlirError",
|
|
79
79
|
@"FlirStateChanged"
|
|
80
|
+
, @"FlirBatteryUpdated"
|
|
80
81
|
];
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -88,6 +89,15 @@ RCT_EXPORT_METHOD(removeListeners:(NSInteger)count) {
|
|
|
88
89
|
// Required for RCTEventEmitter
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
// Provide a class helper so other native modules can post a battery update
|
|
93
|
+
+ (void)emitBatteryUpdateWithLevel:(NSInteger)level charging:(BOOL)charging {
|
|
94
|
+
NSDictionary *payload = @{
|
|
95
|
+
@"level": @(level),
|
|
96
|
+
@"isCharging": @(charging)
|
|
97
|
+
};
|
|
98
|
+
[[FlirEventEmitter shared] sendDeviceEvent:@"FlirBatteryUpdated" body:payload];
|
|
99
|
+
}
|
|
100
|
+
|
|
91
101
|
#pragma mark - Discovery Methods
|
|
92
102
|
|
|
93
103
|
RCT_EXPORT_METHOD(startDiscovery:(RCTPromiseResolveBlock)resolve
|
|
@@ -334,10 +344,8 @@ RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x
|
|
|
334
344
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
335
345
|
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
336
346
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
temp = self.lastTemperature;
|
|
340
|
-
}
|
|
347
|
+
// Call into native FLIRManager to query temperature at point
|
|
348
|
+
double temp = [[FLIRManager shared] getTemperatureAtPoint:[x intValue] y:[y intValue]];
|
|
341
349
|
if (isnan(temp)) {
|
|
342
350
|
resolve([NSNull null]);
|
|
343
351
|
} else {
|
|
@@ -501,6 +509,51 @@ RCT_EXPORT_METHOD(getLatestFramePath:(RCTPromiseResolveBlock)resolve
|
|
|
501
509
|
});
|
|
502
510
|
}
|
|
503
511
|
|
|
512
|
+
RCT_EXPORT_METHOD(getBatteryLevel:(RCTPromiseResolveBlock)resolve
|
|
513
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
514
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
515
|
+
#if FLIR_SDK_AVAILABLE
|
|
516
|
+
int level = [[FLIRManager shared] getBatteryLevel];
|
|
517
|
+
resolve(@(level));
|
|
518
|
+
#else
|
|
519
|
+
resolve(@(-1));
|
|
520
|
+
#endif
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
RCT_EXPORT_METHOD(isBatteryCharging:(RCTPromiseResolveBlock)resolve
|
|
525
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
526
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
527
|
+
#if FLIR_SDK_AVAILABLE
|
|
528
|
+
BOOL ch = [[FLIRManager shared] isBatteryCharging];
|
|
529
|
+
resolve(@(ch));
|
|
530
|
+
#else
|
|
531
|
+
resolve(@(NO));
|
|
532
|
+
#endif
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
RCT_EXPORT_METHOD(setPreferSdkRotation:(BOOL)prefer
|
|
537
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
538
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
539
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
540
|
+
@try {
|
|
541
|
+
[[FLIRManager shared] setPreferSdkRotation:prefer];
|
|
542
|
+
resolve(@(YES));
|
|
543
|
+
} @catch (NSException *ex) {
|
|
544
|
+
reject(@"ERR_FLIR_SET_ROTATION_PREF", ex.reason, nil);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
RCT_EXPORT_METHOD(isPreferSdkRotation:(RCTPromiseResolveBlock)resolve
|
|
550
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
551
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
552
|
+
BOOL v = [[FLIRManager shared] isPreferSdkRotation];
|
|
553
|
+
resolve(@(v));
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
504
557
|
#pragma mark - Helper Methods
|
|
505
558
|
|
|
506
559
|
- (void)emitDeviceConnected {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ilabs-flir",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"description": "FLIR Thermal SDK for React Native - iOS & Android (bundled at compile time via postinstall)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -13,11 +13,9 @@
|
|
|
13
13
|
"src/",
|
|
14
14
|
"android/Flir/src/",
|
|
15
15
|
"android/Flir/build.gradle.kts",
|
|
16
|
-
"android/Flir/libs/",
|
|
17
16
|
"ios/Flir/src/",
|
|
18
17
|
"ios/Flir/SDKLoader/",
|
|
19
|
-
|
|
20
|
-
"ios/Flir/Frameworks/",
|
|
18
|
+
|
|
21
19
|
"app.plugin.js",
|
|
22
20
|
"Flir.podspec",
|
|
23
21
|
"sdk-manifest.json",
|
|
@@ -96,7 +96,7 @@ function extractZip(zipPath, dest) {
|
|
|
96
96
|
|
|
97
97
|
if (cmdExists('unzip')) {
|
|
98
98
|
try {
|
|
99
|
-
execSync(`unzip -o
|
|
99
|
+
execSync(`unzip -o "${zipPath}" -d "${TMP_DIR}"`, { stdio: 'inherit' });
|
|
100
100
|
return;
|
|
101
101
|
} catch (err) {
|
|
102
102
|
throw new Error(`Failed to extract zip using 'unzip'. Consider installing 'unzip' or adding 'adm-zip' package. Original error: ${err.message}`);
|
|
@@ -106,7 +106,11 @@ function extractZip(zipPath, dest) {
|
|
|
106
106
|
// 'tar' can sometimes extract zip files (via bsdtar). Try it as a last resort.
|
|
107
107
|
if (cmdExists('tar')) {
|
|
108
108
|
try {
|
|
109
|
-
|
|
109
|
+
if (process.platform === 'win32') {
|
|
110
|
+
execSync(`tar -xf "${zipPath}" -C "${TMP_DIR}"`, { stdio: 'inherit' });
|
|
111
|
+
} else {
|
|
112
|
+
execSync(`tar -xf '${zipPath}' -C '${TMP_DIR}'`, { stdio: 'inherit' });
|
|
113
|
+
}
|
|
110
114
|
return;
|
|
111
115
|
} catch (err) {
|
|
112
116
|
throw new Error(`Failed to extract zip using 'tar'. Consider installing 'unzip' or add 'adm-zip' package. Original error: ${err.message}`);
|
|
@@ -172,27 +176,67 @@ async function run() {
|
|
|
172
176
|
return;
|
|
173
177
|
}
|
|
174
178
|
|
|
175
|
-
//
|
|
176
|
-
if (!fs.existsSync(DEST_ANDROID)) {
|
|
177
|
-
throw new Error(`Android libs folder ${DEST_ANDROID} does not exist. Please create it (e.g. npm pack or ensure published package includes it).`);
|
|
178
|
-
}
|
|
179
|
-
if (!fs.existsSync(DEST_IOS)) {
|
|
180
|
-
throw new Error(`iOS Frameworks folder ${DEST_IOS} does not exist. Please create it before install.`);
|
|
181
|
-
}
|
|
179
|
+
// (previous 'ensure target folders exist' logic removed; handling now occurs after args parsing)
|
|
182
180
|
|
|
183
181
|
ensureTmp();
|
|
184
182
|
|
|
185
183
|
const argv = process.argv.slice(2);
|
|
186
|
-
const args =
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
184
|
+
const args = {};
|
|
185
|
+
for (let i = 0; i < argv.length; i++) {
|
|
186
|
+
const cur = argv[i];
|
|
187
|
+
if (cur.startsWith('--')) {
|
|
188
|
+
if (cur.includes('=')) {
|
|
189
|
+
const parts = cur.split('=');
|
|
190
|
+
const key = parts.shift().replace(/^--/, '');
|
|
191
|
+
const value = parts.join('=');
|
|
192
|
+
args[key] = value;
|
|
193
|
+
} else {
|
|
194
|
+
// if following arg exists and doesn't start with '-', use it as the value
|
|
195
|
+
const next = argv[i+1];
|
|
196
|
+
if (next && !next.startsWith('-')) {
|
|
197
|
+
args[cur.replace(/^--/, '')] = next;
|
|
198
|
+
i++;
|
|
199
|
+
} else {
|
|
200
|
+
args[cur.replace(/^--/, '')] = true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else if (cur.startsWith('-')) {
|
|
204
|
+
const key = cur.replace(/^-+/, '');
|
|
205
|
+
const next = argv[i+1];
|
|
206
|
+
if (next && !next.startsWith('-')) {
|
|
207
|
+
args[key] = next;
|
|
208
|
+
i++;
|
|
209
|
+
} else {
|
|
210
|
+
args[key] = true;
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
args[cur] = true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
191
216
|
|
|
192
217
|
// Skip if present per-platform
|
|
193
218
|
const skipIfPresent = args['skip-if-present'] || args['skipIfPresent'] || false;
|
|
194
219
|
const platformArg = args['platform'] || args['p'] || 'all';
|
|
195
220
|
|
|
221
|
+
// Determine whether to create missing dest directories automatically; default is true unless explicitly disabled
|
|
222
|
+
const noCreate = process.env.FLIR_SDK_NO_CREATE_DEST === '1' || process.env.FLIR_SDK_NO_CREATE_DEST === 'true' || args['no-create-dest'] || args['noCreateDest'];
|
|
223
|
+
if ((platformArg === 'all' || platformArg === 'android') && !fs.existsSync(DEST_ANDROID)) {
|
|
224
|
+
if (noCreate) {
|
|
225
|
+
throw new Error(`Android libs folder ${DEST_ANDROID} does not exist. Please create it (e.g. npm pack or ensure published package includes it).`);
|
|
226
|
+
} else {
|
|
227
|
+
console.log(`Android libs folder ${DEST_ANDROID} not found — creating it.`);
|
|
228
|
+
fs.mkdirSync(DEST_ANDROID, { recursive: true });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if ((platformArg === 'all' || platformArg === 'ios') && !fs.existsSync(DEST_IOS)) {
|
|
232
|
+
if (noCreate) {
|
|
233
|
+
throw new Error(`iOS Frameworks folder ${DEST_IOS} does not exist. Please create it before install.`);
|
|
234
|
+
} else {
|
|
235
|
+
console.log(`iOS Frameworks folder ${DEST_IOS} not found — creating it.`);
|
|
236
|
+
fs.mkdirSync(DEST_IOS, { recursive: true });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
196
240
|
// Short circuit checks: if skipIfPresent set and files exist, skip per platform
|
|
197
241
|
if (skipIfPresent && platformArg !== 'ios' && hasAndroidAar(DEST_ANDROID)) {
|
|
198
242
|
console.log('Android AAR(s) detected in libs folder; skipping Android fetch.');
|