ilabs-flir 2.1.35 → 2.1.37
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/Flir.podspec +11 -4
- package/android/Flir/build.gradle.kts +1 -1
- package/ios/Flir/src/Flir-Bridging-Header.h +25 -4
- package/ios/Flir/src/FlirEventEmitter.h +7 -0
- package/ios/Flir/src/FlirManager.swift +47 -0
- package/ios/Flir/src/FlirModule.h +7 -0
- package/ios/Flir/src/FlirModule.m +27 -1
- package/ios/Flir/src/FlirPublic.h +50 -0
- package/ios/Flir/src/FlirViewManager.h +5 -0
- package/package.json +1 -1
package/Flir.podspec
CHANGED
|
@@ -36,14 +36,21 @@ Pod::Spec.new do |s|
|
|
|
36
36
|
|
|
37
37
|
# Ensure React headers are available to this Pod across various RN/CocoaPods layouts
|
|
38
38
|
# (helps when headers are in different public/private/ReactCore locations or when using use_frameworks)
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
begin
|
|
40
|
+
existing = s.pod_target_xcconfig rescue {}
|
|
41
|
+
end
|
|
42
|
+
existing_hdrs = existing.is_a?(Hash) ? (existing['HEADER_SEARCH_PATHS'] || '$(inherited)') : '$(inherited)'
|
|
41
43
|
hdrs = [existing_hdrs,
|
|
42
44
|
'"${PODS_ROOT}/Headers/Public/React"',
|
|
43
45
|
'"${PODS_ROOT}/Headers/Public/React-Core"',
|
|
44
46
|
'"${PODS_ROOT}/Headers/Public/ReactCommon"',
|
|
45
|
-
'"${PODS_ROOT}/Headers/Public/React-CoreModules"']
|
|
46
|
-
|
|
47
|
+
'"${PODS_ROOT}/Headers/Public/React-CoreModules"'].join(' ')
|
|
48
|
+
begin
|
|
49
|
+
s.pod_target_xcconfig = (existing || {}).merge('HEADER_SEARCH_PATHS' => hdrs)
|
|
50
|
+
rescue NoMethodError
|
|
51
|
+
# Fallback for older CocoaPods that don't support pod_target_xcconfig
|
|
52
|
+
s.user_target_xcconfig = (s.user_target_xcconfig || {}).merge('HEADER_SEARCH_PATHS' => hdrs)
|
|
53
|
+
end
|
|
47
54
|
|
|
48
55
|
|
|
49
56
|
# ==========================================================================
|
|
@@ -38,7 +38,7 @@ android {
|
|
|
38
38
|
|
|
39
39
|
dependencies {
|
|
40
40
|
// React Native
|
|
41
|
-
implementation("com.facebook.react:react-native:+")
|
|
41
|
+
implementation("com.facebook.react:react-native:+")66a6f83912ba50ae5553aff1f5b0
|
|
42
42
|
|
|
43
43
|
// Kotlin coroutines
|
|
44
44
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
|
|
@@ -11,16 +11,40 @@
|
|
|
11
11
|
|
|
12
12
|
// Note: React headers are provided by the app's build system
|
|
13
13
|
// These imports are for documentation purposes when building within Xcode
|
|
14
|
-
|
|
14
|
+
// Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
|
|
15
15
|
#if __has_include(<React/RCTBridgeModule.h>)
|
|
16
16
|
#import <React/RCTBridgeModule.h>
|
|
17
|
+
#if __has_include(<React/RCTEventEmitter.h>)
|
|
17
18
|
#import <React/RCTEventEmitter.h>
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<React/RCTLog.h>)
|
|
21
|
+
#import <React/RCTLog.h>
|
|
22
|
+
#endif
|
|
23
|
+
#if __has_include(<React/RCTViewManager.h>)
|
|
24
|
+
#import <React/RCTViewManager.h>
|
|
25
|
+
#endif
|
|
18
26
|
#elif __has_include(<ReactCore/RCTBridgeModule.h>)
|
|
19
27
|
#import <ReactCore/RCTBridgeModule.h>
|
|
28
|
+
#if __has_include(<ReactCore/RCTEventEmitter.h>)
|
|
29
|
+
#import <ReactCore/RCTEventEmitter.h>
|
|
30
|
+
#elif __has_include(<React/RCTEventEmitter.h>)
|
|
20
31
|
#import <React/RCTEventEmitter.h>
|
|
32
|
+
#endif
|
|
33
|
+
#if __has_include(<ReactCore/RCTLog.h>)
|
|
34
|
+
#import <ReactCore/RCTLog.h>
|
|
35
|
+
#elif __has_include(<React/RCTLog.h>)
|
|
36
|
+
#import <React/RCTLog.h>
|
|
37
|
+
#endif
|
|
38
|
+
#if __has_include(<ReactCore/RCTViewManager.h>)
|
|
39
|
+
#import <ReactCore/RCTViewManager.h>
|
|
40
|
+
#elif __has_include(<React/RCTViewManager.h>)
|
|
41
|
+
#import <React/RCTViewManager.h>
|
|
42
|
+
#endif
|
|
21
43
|
#elif __has_include("RCTBridgeModule.h")
|
|
22
44
|
#import "RCTBridgeModule.h"
|
|
23
45
|
#import "RCTEventEmitter.h"
|
|
46
|
+
#import "RCTLog.h"
|
|
47
|
+
#import "RCTViewManager.h"
|
|
24
48
|
#else
|
|
25
49
|
#import <Foundation/Foundation.h>
|
|
26
50
|
@interface RCTEventEmitter : NSObject
|
|
@@ -28,9 +52,6 @@
|
|
|
28
52
|
@protocol RCTBridgeModule <NSObject>
|
|
29
53
|
@end
|
|
30
54
|
#endif
|
|
31
|
-
#import <React/RCTLog.h>
|
|
32
|
-
#import <React/RCTViewManager.h>
|
|
33
|
-
#endif
|
|
34
55
|
|
|
35
56
|
// FLIR module headers (local)
|
|
36
57
|
#import "FlirEventEmitter.h"
|
|
@@ -5,12 +5,19 @@
|
|
|
5
5
|
// Event emitter for sending FLIR events to React Native
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
+
// Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
|
|
8
9
|
#if __has_include(<React/RCTBridgeModule.h>)
|
|
9
10
|
#import <React/RCTBridgeModule.h>
|
|
11
|
+
#if __has_include(<React/RCTEventEmitter.h>)
|
|
10
12
|
#import <React/RCTEventEmitter.h>
|
|
13
|
+
#endif
|
|
11
14
|
#elif __has_include(<ReactCore/RCTBridgeModule.h>)
|
|
12
15
|
#import <ReactCore/RCTBridgeModule.h>
|
|
16
|
+
#if __has_include(<ReactCore/RCTEventEmitter.h>)
|
|
17
|
+
#import <ReactCore/RCTEventEmitter.h>
|
|
18
|
+
#elif __has_include(<React/RCTEventEmitter.h>)
|
|
13
19
|
#import <React/RCTEventEmitter.h>
|
|
20
|
+
#endif
|
|
14
21
|
#elif __has_include("RCTBridgeModule.h")
|
|
15
22
|
#import "RCTBridgeModule.h"
|
|
16
23
|
#import "RCTEventEmitter.h"
|
|
@@ -43,6 +43,7 @@ import ThermalSDK
|
|
|
43
43
|
func onDeviceConnected(_ device: FlirDeviceInfo)
|
|
44
44
|
func onDeviceDisconnected()
|
|
45
45
|
func onFrameReceived(_ image: UIImage, width: Int, height: Int)
|
|
46
|
+
@objc optional func onFrameReceivedRaw(_ data: Data, width: Int, height: Int, bytesPerRow: Int, timestamp: Double)
|
|
46
47
|
func onError(_ message: String)
|
|
47
48
|
func onStateChanged(_ state: String, isConnected: Bool, isStreaming: Bool, isEmulator: Bool)
|
|
48
49
|
}
|
|
@@ -188,6 +189,35 @@ import ThermalSDK
|
|
|
188
189
|
return nil
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
// Returns a NSDictionary with BGRA base64 data for the latest frame.
|
|
193
|
+
// Keys: width (Int), height (Int), bytesPerRow (Int), dataBase64 (String)
|
|
194
|
+
@objc public func latestFrameBitmapBase64() -> NSDictionary? {
|
|
195
|
+
guard let img = latestImage else { return nil }
|
|
196
|
+
guard let bmp = convertUIImageToBGRA(img) else { return nil }
|
|
197
|
+
let b64 = bmp.data.base64EncodedString()
|
|
198
|
+
return ["width": bmp.width, "height": bmp.height, "bytesPerRow": bmp.bytesPerRow, "dataBase64": b64]
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Convert a UIImage to BGRA (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst).
|
|
202
|
+
private func convertUIImageToBGRA(_ image: UIImage) -> (data: Data, width: Int, height: Int, bytesPerRow: Int)? {
|
|
203
|
+
guard let cg = image.cgImage else { return nil }
|
|
204
|
+
let width = cg.width
|
|
205
|
+
let height = cg.height
|
|
206
|
+
let bytesPerRow = width * 4
|
|
207
|
+
let size = height * bytesPerRow
|
|
208
|
+
var data = Data(count: size)
|
|
209
|
+
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
|
210
|
+
let bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue
|
|
211
|
+
let success = data.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) -> Bool in
|
|
212
|
+
guard let base = ptr.baseAddress else { return false }
|
|
213
|
+
guard let ctx = CGContext(data: base, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { return false }
|
|
214
|
+
let rect = CGRect(x: 0, y: 0, width: width, height: height)
|
|
215
|
+
ctx.draw(cg, in: rect)
|
|
216
|
+
return true
|
|
217
|
+
}
|
|
218
|
+
return success ? (data, width, height, bytesPerRow) : nil
|
|
219
|
+
}
|
|
220
|
+
|
|
191
221
|
// Client lifecycle helpers: callers (UI/filters) can retain/release to ensure
|
|
192
222
|
// discovery runs while any client is active.
|
|
193
223
|
@objc public func retainClient(_ clientId: String) {
|
|
@@ -851,6 +881,23 @@ extension FlirManager: FLIRStreamDelegate {
|
|
|
851
881
|
height: Int(image.size.height)
|
|
852
882
|
)
|
|
853
883
|
}
|
|
884
|
+
|
|
885
|
+
// Also provide a raw BGRA bitmap callback (optional) to delegates and a
|
|
886
|
+
// queryable base64 bitmap dict for RN consumers. Conversion is done
|
|
887
|
+
// off the main thread to avoid blocking UI.
|
|
888
|
+
DispatchQueue.global(qos: .utility).async { [weak self, weak image] in
|
|
889
|
+
guard let self = self, let image = image else { return }
|
|
890
|
+
if let bmp = self.convertUIImageToBGRA(image) {
|
|
891
|
+
let ts = Date().timeIntervalSince1970 * 1000.0
|
|
892
|
+
DispatchQueue.main.async {
|
|
893
|
+
// Notify the delegate if set (may be FlirModule or another consumer)
|
|
894
|
+
self.delegate?.onFrameReceivedRaw?(bmp.data, width: bmp.width, height: bmp.height, bytesPerRow: bmp.bytesPerRow, timestamp: ts)
|
|
895
|
+
|
|
896
|
+
// Post a system notification so multiple native observers can react
|
|
897
|
+
NotificationCenter.default.post(name: Notification.Name("FlirFrameBitmapAvailableNative"), object: nil, userInfo: ["width": bmp.width, "height": bmp.height, "bytesPerRow": bmp.bytesPerRow, "timestamp": ts])
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
854
901
|
}
|
|
855
902
|
} catch {
|
|
856
903
|
NSLog("[FlirManager] Streamer update error: \(error)")
|
|
@@ -5,12 +5,19 @@
|
|
|
5
5
|
// React Native bridge module for FLIR thermal camera SDK
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
+
// Prefer React/ headers, but fall back to ReactCore or local headers for different RN layouts
|
|
8
9
|
#if __has_include(<React/RCTBridgeModule.h>)
|
|
9
10
|
#import <React/RCTBridgeModule.h>
|
|
11
|
+
#if __has_include(<React/RCTEventEmitter.h>)
|
|
10
12
|
#import <React/RCTEventEmitter.h>
|
|
13
|
+
#endif
|
|
11
14
|
#elif __has_include(<ReactCore/RCTBridgeModule.h>)
|
|
12
15
|
#import <ReactCore/RCTBridgeModule.h>
|
|
16
|
+
#if __has_include(<ReactCore/RCTEventEmitter.h>)
|
|
17
|
+
#import <ReactCore/RCTEventEmitter.h>
|
|
18
|
+
#elif __has_include(<React/RCTEventEmitter.h>)
|
|
13
19
|
#import <React/RCTEventEmitter.h>
|
|
20
|
+
#endif
|
|
14
21
|
#elif __has_include("RCTBridgeModule.h")
|
|
15
22
|
#import "RCTBridgeModule.h"
|
|
16
23
|
#import "RCTEventEmitter.h"
|
|
@@ -121,7 +121,7 @@ RCT_EXPORT_MODULE(FlirModule);
|
|
|
121
121
|
- (NSArray<NSString *> *)supportedEvents {
|
|
122
122
|
return @[
|
|
123
123
|
@"FlirDeviceConnected", @"FlirDeviceDisconnected", @"FlirDevicesFound",
|
|
124
|
-
@"FlirFrameReceived", @"FlirError", @"FlirStateChanged",
|
|
124
|
+
@"FlirFrameReceived", @"FlirFrameBitmapAvailable", @"FlirError", @"FlirStateChanged",
|
|
125
125
|
@"FlirBatteryUpdated"
|
|
126
126
|
];
|
|
127
127
|
}
|
|
@@ -308,6 +308,22 @@ RCT_EXPORT_METHOD(isEmulator : (RCTPromiseResolveBlock)
|
|
|
308
308
|
});
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
RCT_EXPORT_METHOD(getLatestFrameBitmap : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
312
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
313
|
+
id manager = flir_manager_shared();
|
|
314
|
+
if (!manager || ![manager respondsToSelector:sel_registerName("latestFrameBitmapBase64")]) {
|
|
315
|
+
resolve([NSNull null]);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
NSDictionary *dict = ((NSDictionary * (*)(id, SEL)) objc_msgSend)(manager, sel_registerName("latestFrameBitmapBase64"));
|
|
319
|
+
if (!dict) {
|
|
320
|
+
resolve([NSNull null]);
|
|
321
|
+
} else {
|
|
322
|
+
resolve(dict);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
311
327
|
RCT_EXPORT_METHOD(isDeviceConnected : (RCTPromiseResolveBlock)
|
|
312
328
|
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
313
329
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
@@ -431,6 +447,16 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
431
447
|
}];
|
|
432
448
|
}
|
|
433
449
|
|
|
450
|
+
- (void)onFrameReceivedRaw:(NSData *)data width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow timestamp:(double)timestamp {
|
|
451
|
+
// Emit a lightweight event to notify JS that a raw bitmap is available; raw bytes are available via getLatestFrameBitmap()
|
|
452
|
+
[[FlirEventEmitter shared] sendDeviceEvent:@"FlirFrameBitmapAvailable" body:@{
|
|
453
|
+
@"width": @(width),
|
|
454
|
+
@"height": @(height),
|
|
455
|
+
@"bytesPerRow": @(bytesPerRow),
|
|
456
|
+
@"timestamp": @(timestamp)
|
|
457
|
+
}];
|
|
458
|
+
}
|
|
459
|
+
|
|
434
460
|
- (void)onError:(NSString *)message {
|
|
435
461
|
if (self.connectReject) {
|
|
436
462
|
self.connectReject(@"ERR_FLIR", message, nil);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// FlirPublic.h
|
|
2
|
+
// Public C/ObjC API for the Flir library
|
|
3
|
+
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
#import <UIKit/UIKit.h>
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
@interface FlirDeviceInfo : NSObject
|
|
10
|
+
@property (nonatomic, readonly) NSString *deviceId;
|
|
11
|
+
@property (nonatomic, readonly) NSString *name;
|
|
12
|
+
@property (nonatomic, readonly) NSString *communicationType;
|
|
13
|
+
@property (nonatomic, readonly) BOOL isEmulator;
|
|
14
|
+
- (NSDictionary *)toDictionary;
|
|
15
|
+
@end
|
|
16
|
+
|
|
17
|
+
@protocol FlirPublicDelegate <NSObject>
|
|
18
|
+
- (void)onDevicesFound:(NSArray<FlirDeviceInfo *> *)devices;
|
|
19
|
+
- (void)onDeviceConnected:(FlirDeviceInfo *)device;
|
|
20
|
+
- (void)onDeviceDisconnected;
|
|
21
|
+
- (void)onFrameReceived:(UIImage *)image width:(NSInteger)width height:(NSInteger)height;
|
|
22
|
+
@optional
|
|
23
|
+
- (void)onFrameReceivedRaw:(NSData *)data width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow timestamp:(double)timestamp;
|
|
24
|
+
- (void)onError:(NSString *)message;
|
|
25
|
+
- (void)onStateChanged:(NSString *)state isConnected:(BOOL)isConnected isStreaming:(BOOL)isStreaming isEmulator:(BOOL)isEmulator;
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
@interface FlirManager : NSObject
|
|
29
|
+
+ (instancetype)shared NS_SWIFT_NAME(shared);
|
|
30
|
+
|
|
31
|
+
@property (nonatomic, weak, nullable) id<FlirPublicDelegate> delegate;
|
|
32
|
+
|
|
33
|
+
// Lifecycle
|
|
34
|
+
- (void)startDiscovery;
|
|
35
|
+
- (void)stopDiscovery;
|
|
36
|
+
- (void)connectToDevice:(NSString *)deviceId;
|
|
37
|
+
- (void)disconnect;
|
|
38
|
+
- (void)stop;
|
|
39
|
+
|
|
40
|
+
// Frame accessors
|
|
41
|
+
- (nullable NSDictionary *)latestFrameBitmapBase64; // { width, height, bytesPerRow, dataBase64 }
|
|
42
|
+
- (nullable NSString *)latestFrameBase64;
|
|
43
|
+
|
|
44
|
+
// Utilities
|
|
45
|
+
- (NSInteger)getBatteryLevel;
|
|
46
|
+
- (BOOL)isBatteryCharging;
|
|
47
|
+
|
|
48
|
+
@end
|
|
49
|
+
|
|
50
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -5,8 +5,13 @@
|
|
|
5
5
|
// React Native view manager for FLIR preview
|
|
6
6
|
//
|
|
7
7
|
|
|
8
|
+
// Prefer React/ headers, but support multiple RN header layouts
|
|
8
9
|
#if __has_include(<React/RCTViewManager.h>)
|
|
9
10
|
#import <React/RCTViewManager.h>
|
|
11
|
+
#elif __has_include(<ReactCore/RCTViewManager.h>)
|
|
12
|
+
#import <ReactCore/RCTViewManager.h>
|
|
13
|
+
#elif __has_include("RCTViewManager.h")
|
|
14
|
+
#import "RCTViewManager.h"
|
|
10
15
|
#elif __has_include(<React/RCTUIManager.h>)
|
|
11
16
|
#import <React/RCTUIManager.h>
|
|
12
17
|
#else
|