react-native-inapp-inspector 2.0.1 → 2.0.2

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.
Files changed (47) hide show
  1. package/README.md +10 -0
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  4. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  5. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  6. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  7. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  8. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  9. package/android/.gradle/8.9/gc.properties +0 -0
  10. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  11. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  12. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  13. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  14. package/android/.gradle/9.2.0/gc.properties +0 -0
  15. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  16. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  17. package/android/.gradle/vcs-1/gc.properties +0 -0
  18. package/android/build/reports/problems/problems-report.html +659 -0
  19. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +23 -0
  20. package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
  21. package/dist/commonjs/components/Inspector/TelemetryConsentModal.d.ts +3 -0
  22. package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +212 -0
  23. package/dist/commonjs/constants/version.d.ts +1 -1
  24. package/dist/commonjs/constants/version.js +1 -1
  25. package/dist/commonjs/helpers/index.d.ts +1 -0
  26. package/dist/commonjs/helpers/index.js +1 -0
  27. package/dist/commonjs/helpers/telemetry.d.ts +99 -0
  28. package/dist/commonjs/helpers/telemetry.js +398 -0
  29. package/dist/commonjs/index.d.ts +2 -0
  30. package/dist/commonjs/index.js +23 -1
  31. package/dist/commonjs/native/NativeInspector.d.ts +5 -0
  32. package/dist/commonjs/native/NativeInspector.js +3 -2
  33. package/dist/esm/components/Inspector/MainScreen.js +4 -0
  34. package/dist/esm/components/Inspector/TelemetryConsentModal.d.ts +3 -0
  35. package/dist/esm/components/Inspector/TelemetryConsentModal.js +175 -0
  36. package/dist/esm/constants/version.d.ts +1 -1
  37. package/dist/esm/constants/version.js +1 -1
  38. package/dist/esm/helpers/index.d.ts +1 -0
  39. package/dist/esm/helpers/index.js +1 -0
  40. package/dist/esm/helpers/telemetry.d.ts +99 -0
  41. package/dist/esm/helpers/telemetry.js +380 -0
  42. package/dist/esm/index.d.ts +2 -0
  43. package/dist/esm/index.js +13 -1
  44. package/dist/esm/native/NativeInspector.d.ts +5 -0
  45. package/dist/esm/native/NativeInspector.js +3 -2
  46. package/ios/{NetworkInspectorModule.m → NetworkInspectorModule.mm} +175 -119
  47. package/package.json +2 -2
package/dist/esm/index.js CHANGED
@@ -8,7 +8,7 @@ import ErrorBoundary from './components/ErrorBoundary';
8
8
  import MainScreen from './components/Inspector/MainScreen';
9
9
  import { InspectorContext, animateNextLayout, } from './components/Inspector/InspectorContext';
10
10
  // Helpers
11
- import { formatDisplayUrl, getNavigationInfo, deduplicateLogs, getDomainColor, getEventCategory, matchNetworkLogQuery, } from './helpers';
11
+ import { formatDisplayUrl, getNavigationInfo, deduplicateLogs, getDomainColor, getEventCategory, matchNetworkLogQuery, sendSessionTelemetryPing, trackInspectorOpen, } from './helpers';
12
12
  // #5 — settings persistence
13
13
  import { loadSettings, saveSettings, setCustomStorage, clearPersistedSettings, calculateRamBasedLimits, } from './helpers/settingsStore';
14
14
  import { getNativeSystemMetrics, pushNativeLogRecord, fetchNativeCachedPage, } from './native/NativeInspector';
@@ -699,6 +699,14 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
699
699
  }, [unreadPulseAnim]);
700
700
  const isNativeModule = useMemo(() => isNativeModuleAvailable(), []);
701
701
  const useNativeFab = (Platform.OS === 'ios' || Platform.OS === 'android') && isNativeModule;
702
+ // Send anonymous initialization heartbeat to GA4 Measurement Protocol
703
+ useEffect(() => {
704
+ sendSessionTelemetryPing({
705
+ environment,
706
+ hasNavigation: Boolean(navigationRef),
707
+ hasAppIcon: Boolean(appIcon),
708
+ });
709
+ }, [environment, navigationRef, appIcon]);
702
710
  // 100% Native Main-Thread Floating Button Lifecycle
703
711
  useEffect(() => {
704
712
  if (!useNativeFab || !isEnabled || !enabled) {
@@ -753,6 +761,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
753
761
  ? defaultTab
754
762
  : 'apis';
755
763
  setActiveTab(target);
764
+ // Track inspector opened event in GA4
765
+ trackInspectorOpen({ activeTab: target });
756
766
  // Instant synchronization of data collected while modal was closed
757
767
  if (latestNetworkLogsRef.current.length > 0) {
758
768
  const deduped = deduplicateLogs(latestNetworkLogsRef.current);
@@ -1739,4 +1749,6 @@ export { getEventCategory, registerGAPlugin, } from './helpers/gaAnalyticsRegist
1739
1749
  export { usePerformanceTracker, useComponentProfiler, useNavigationProfiler, trackComponentRender, trackNavigationTransition, trackHeavyTask, measureAsync, getHermesMemoryStats, registerComponentProfile, subscribeRenderProfiles, getRenderProfiles, logPerformanceEvent, clearPerformanceEvents, subscribePerformanceEvents, getPerformanceEvents, getInitialRenderProfiles, getInitialPerformanceEvents, generateFixSnippet, } from './customHooks/performanceTracker';
1740
1750
  export { InspectLog, InspectTrackTime, InspectCatch, } from './decorators';
1741
1751
  export { getNativeDeviceMetrics, enableNativeCrashProtection, subscribeNativeCrashes, showNativeFloatingButton, hideNativeFloatingButton, setNativeFloatingButtonBadge, subscribeNativeFloatingButtonPress, subscribeNativeDeviceShake, startNativeFpsMonitoring, stopNativeFpsMonitoring, getNativeFpsMetrics, getNativeStorageItem, setNativeStorageItem, isNativeModuleAvailable, } from './native/NativeInspector';
1752
+ export { sendSessionTelemetryPing, trackTelemetryEvent, trackInspectorOpen, trackTabSwitch, trackLogExport, GA4_MEASUREMENT_ID, GA4_API_SECRET, } from './helpers';
1753
+ export { BrandSquareIcon, BrandCircleIcon, } from './components/NetworkIcons';
1742
1754
  export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimationType, SettingsPage, SettingsSubTab, LogFilter, ConsoleLogType, AnalyticsEventSource, GAEventCategory, StackFrameType, DiffResultType, BundleSubTab, PerformanceSubTab, CrashType, CrashExportFormat, CrashDetailSubTab, CrashFilterType, BreadcrumbType, } from './types';
@@ -17,6 +17,11 @@ export interface NativeDeviceMetrics {
17
17
  osVersion?: string;
18
18
  apiLevel?: number;
19
19
  cpuAbi?: string;
20
+ appName?: string;
21
+ appVersion?: string;
22
+ appBuild?: string;
23
+ appBundleId?: string;
24
+ appPackageName?: string;
20
25
  }
21
26
  export interface NativeCrashEvent {
22
27
  platform: 'android' | 'ios';
@@ -5,8 +5,9 @@ const NativeModule = NativeNetworkInspector || NativeModules.NetworkInspectorMod
5
5
  export const isNativeModuleAvailable = () => {
6
6
  return !!NativeModule;
7
7
  };
8
- const nativeEmitter = isNativeModuleAvailable()
9
- ? new NativeEventEmitter(NativeModule)
8
+ const eventTarget = NativeModules.NetworkInspectorModule || NativeNetworkInspector;
9
+ const nativeEmitter = eventTarget
10
+ ? new NativeEventEmitter(eventTarget)
10
11
  : null;
11
12
  /**
12
13
  * Retrieves low-level native hardware and system metrics (RAM, Heap, Disk, Battery, CPU).
@@ -21,6 +21,8 @@ static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler = NULL;
21
21
  if (self = [super initWithFrame:frame]) {
22
22
  self.backgroundColor = [UIColor clearColor];
23
23
  self.userInteractionEnabled = NO;
24
+ self.contentMode = UIViewContentModeRedraw;
25
+ self.clipsToBounds = NO;
24
26
  }
25
27
  return self;
26
28
  }
@@ -177,11 +179,9 @@ static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler = NULL;
177
179
 
178
180
  @end
179
181
 
180
- @interface InAppInspectorFloatingView ()
181
- @property (nonatomic, assign) CGPoint touchDownPoint;
182
- @property (nonatomic, assign) CGPoint initialCenter;
183
- @property (nonatomic, assign) NSTimeInterval touchDownTime;
184
- @property (nonatomic, assign) BOOL isDragging;
182
+ @interface InAppInspectorFloatingView () <UIGestureRecognizerDelegate>
183
+ @property (nonatomic, assign) CGPoint panStartCenter;
184
+ @property (nonatomic, assign) NSTimeInterval lastTapTime;
185
185
  @end
186
186
 
187
187
  @implementation InAppInspectorFloatingView
@@ -203,88 +203,100 @@ static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler = NULL;
203
203
  self.layer.borderWidth = 2.2;
204
204
  self.layer.borderColor = [UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:0.9].CGColor;
205
205
 
206
- // Native drawn Inspector Owl icon (Enhanced & Larger)
206
+ // Native drawn Inspector Owl icon
207
207
  CGFloat iconSize = frame.size.width * 0.94;
208
208
  CGFloat iconOffset = (frame.size.width - iconSize) / 2.0;
209
209
  InAppInspectorOwlView *owlView = [[InAppInspectorOwlView alloc] initWithFrame:CGRectMake(iconOffset, iconOffset, iconSize, iconSize)];
210
210
  owlView.userInteractionEnabled = NO;
211
211
  [self addSubview:owlView];
212
+
213
+ // Dedicated Tap Gesture Recognizer
214
+ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
215
+ tap.numberOfTapsRequired = 1;
216
+ tap.cancelsTouchesInView = NO;
217
+ tap.delegate = self;
218
+ [self addGestureRecognizer:tap];
219
+
220
+ // Dedicated Pan Gesture Recognizer
221
+ UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
222
+ pan.delegate = self;
223
+ [self addGestureRecognizer:pan];
212
224
  }
213
225
  return self;
214
226
  }
215
227
 
228
+ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
229
+ if (!self.userInteractionEnabled || self.hidden || self.alpha < 0.01) {
230
+ return nil;
231
+ }
232
+ if (CGRectContainsPoint(self.bounds, point)) {
233
+ return self;
234
+ }
235
+ return [super hitTest:point withEvent:event];
236
+ }
237
+
216
238
  - (void)updateBadgeVisible:(BOOL)visible {
217
- // Active badge dot removed
239
+ // Active badge dot
218
240
  }
219
241
 
220
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
221
- UITouch *touch = [touches anyObject];
222
- if (!touch) return;
223
-
224
- if (self.superview) {
225
- [self.superview bringSubviewToFront:self];
242
+ - (void)handleTapGesture:(UITapGestureRecognizer *)gesture {
243
+ if (gesture.state == UIGestureRecognizerStateEnded) {
244
+ [self triggerTapAction];
226
245
  }
227
-
228
- self.touchDownPoint = [touch locationInView:self.window];
229
- self.initialCenter = self.center;
230
- self.touchDownTime = CACurrentMediaTime();
231
- self.isDragging = NO;
232
-
246
+ }
247
+
248
+ - (void)triggerTapAction {
249
+ NSTimeInterval now = CACurrentMediaTime();
250
+ if (now - self.lastTapTime < 0.35) return;
251
+ self.lastTapTime = now;
252
+
253
+ if (@available(iOS 10.0, *)) {
254
+ UIImpactFeedbackGenerator *impact = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
255
+ [impact prepare];
256
+ [impact impactOccurred];
257
+ }
258
+
233
259
  [UIView animateWithDuration:0.08 animations:^{
234
- self.transform = CGAffineTransformMakeScale(0.92, 0.92);
260
+ self.transform = CGAffineTransformMakeScale(0.90, 0.90);
261
+ } completion:^(BOOL finished) {
262
+ [UIView animateWithDuration:0.10 animations:^{
263
+ self.transform = CGAffineTransformIdentity;
264
+ }];
235
265
  }];
266
+
267
+ if (self.onTapBlock) {
268
+ self.onTapBlock();
269
+ }
236
270
  }
237
271
 
238
- - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
239
- UITouch *touch = [touches anyObject];
272
+ - (void)handlePanGesture:(UIPanGestureRecognizer *)pan {
240
273
  UIView *superview = self.superview;
241
- if (!touch || !superview) return;
242
-
243
- CGPoint currentPoint = [touch locationInView:self.window];
244
- CGFloat dx = currentPoint.x - self.touchDownPoint.x;
245
- CGFloat dy = currentPoint.y - self.touchDownPoint.y;
246
- CGFloat distance = hypot(dx, dy);
247
-
248
- if (!self.isDragging && distance > 14.0) {
249
- self.isDragging = YES;
250
- }
251
-
252
- if (self.isDragging) {
274
+ if (!superview) return;
275
+
276
+ if (pan.state == UIGestureRecognizerStateBegan) {
277
+ self.panStartCenter = self.center;
278
+ [superview bringSubviewToFront:self];
279
+ [UIView animateWithDuration:0.1 animations:^{
280
+ self.transform = CGAffineTransformMakeScale(1.06, 1.06);
281
+ }];
282
+ } else if (pan.state == UIGestureRecognizerStateChanged) {
283
+ CGPoint translation = [pan translationInView:superview];
253
284
  CGFloat halfW = self.bounds.size.width / 2.0;
254
285
  CGFloat halfH = self.bounds.size.height / 2.0;
255
286
  CGFloat minX = halfW + 10.0;
256
287
  CGFloat maxX = superview.bounds.size.width - halfW - 10.0;
257
288
  CGFloat minY = halfH + 44.0;
258
289
  CGFloat maxY = superview.bounds.size.height - halfH - 44.0;
259
-
260
- CGPoint newCenter = CGPointMake(self.initialCenter.x + dx, self.initialCenter.y + dy);
290
+
291
+ CGPoint newCenter = CGPointMake(self.panStartCenter.x + translation.x, self.panStartCenter.y + translation.y);
261
292
  newCenter.x = MAX(minX, MIN(maxX, newCenter.x));
262
293
  newCenter.y = MAX(minY, MIN(maxY, newCenter.y));
263
294
  self.center = newCenter;
264
- }
265
- }
295
+ } else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
296
+ [UIView animateWithDuration:0.15 animations:^{
297
+ self.transform = CGAffineTransformIdentity;
298
+ }];
266
299
 
267
- - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
268
- UITouch *touch = [touches anyObject];
269
- UIView *superview = self.superview;
270
-
271
- [UIView animateWithDuration:0.12 animations:^{
272
- self.transform = CGAffineTransformIdentity;
273
- }];
274
-
275
- if (!touch || !superview) return;
276
-
277
- CGPoint currentPoint = [touch locationInView:self.window];
278
- CGFloat dx = currentPoint.x - self.touchDownPoint.x;
279
- CGFloat dy = currentPoint.y - self.touchDownPoint.y;
280
- CGFloat distance = hypot(dx, dy);
281
- NSTimeInterval elapsed = CACurrentMediaTime() - self.touchDownTime;
282
-
283
- if (!self.isDragging && distance < 24.0 && elapsed < 0.85) {
284
- if (self.onTapBlock) {
285
- self.onTapBlock();
286
- }
287
- } else if (self.isDragging) {
288
300
  CGFloat halfW = self.bounds.size.width / 2.0;
289
301
  CGFloat minX = halfW + 10.0;
290
302
  CGFloat maxX = superview.bounds.size.width - halfW - 10.0;
@@ -295,12 +307,6 @@ static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler = NULL;
295
307
  }
296
308
  }
297
309
 
298
- - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
299
- [UIView animateWithDuration:0.12 animations:^{
300
- self.transform = CGAffineTransformIdentity;
301
- }];
302
- }
303
-
304
310
  @end
305
311
 
306
312
  static InAppInspectorFloatingView *floatingButtonView = nil;
@@ -451,13 +457,13 @@ RCT_EXPORT_MODULE(NetworkInspectorModule);
451
457
  }
452
458
 
453
459
  RCT_EXPORT_METHOD(enableNativeCrashProtection:(RCTPromiseResolveBlock)resolve
454
- rejecter:(RCTPromiseRejectBlock)reject) {
460
+ reject:(RCTPromiseRejectBlock)reject) {
455
461
  [self installHandlers];
456
462
  resolve(@(YES));
457
463
  }
458
464
 
459
465
  RCT_EXPORT_METHOD(getDeviceMetrics:(RCTPromiseResolveBlock)resolve
460
- rejecter:(RCTPromiseRejectBlock)reject) {
466
+ reject:(RCTPromiseRejectBlock)reject) {
461
467
  NSMutableDictionary *metrics = [NSMutableDictionary dictionary];
462
468
 
463
469
  // 1. Memory / RAM Metrics
@@ -510,46 +516,66 @@ RCT_EXPORT_METHOD(getDeviceMetrics:(RCTPromiseResolveBlock)resolve
510
516
  [metrics setObject:[UIDevice currentDevice].systemVersion forKey:@"osVersion"];
511
517
  [metrics setObject:@"arm64" forKey:@"cpuAbi"];
512
518
 
519
+ // 5. Application Identifiers (Legal & Non-PII)
520
+ NSBundle *mainBundle = [NSBundle mainBundle];
521
+ NSString *appName = [mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: [mainBundle objectForInfoDictionaryKey:@"CFBundleName"];
522
+ NSString *appVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
523
+ NSString *appBuild = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
524
+ NSString *appBundleId = [mainBundle bundleIdentifier];
525
+ if (appName) [metrics setObject:appName forKey:@"appName"];
526
+ if (appVersion) [metrics setObject:appVersion forKey:@"appVersion"];
527
+ if (appBuild) [metrics setObject:appBuild forKey:@"appBuild"];
528
+ if (appBundleId) {
529
+ [metrics setObject:appBundleId forKey:@"appBundleId"];
530
+ [metrics setObject:appBundleId forKey:@"appPackageName"];
531
+ }
532
+
513
533
  resolve(metrics);
514
534
  }
515
535
 
516
- RCT_EXPORT_METHOD(showFloatingButton:(NSDictionary *)options
517
- resolver:(RCTPromiseResolveBlock)resolve
518
- rejecter:(RCTPromiseRejectBlock)reject) {
519
- dispatch_async(dispatch_get_main_queue(), ^{
520
- UIWindow *targetWindow = nil;
521
- if (@available(iOS 13.0, *)) {
522
- for (UIWindowScene *scene in [UIApplication sharedApplication].connectedScenes) {
523
- if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
524
- for (UIWindow *w in scene.windows) {
525
- if (w.isKeyWindow) {
526
- targetWindow = w;
527
- break;
528
- }
536
+ static UIWindow *GetAppActiveWindow(void) {
537
+ if (@available(iOS 13.0, *)) {
538
+ for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
539
+ if ([scene isKindOfClass:[UIWindowScene class]]) {
540
+ UIWindowScene *ws = (UIWindowScene *)scene;
541
+ for (UIWindow *w in ws.windows) {
542
+ if (w.isKeyWindow || w.windowLevel == UIWindowLevelNormal) {
543
+ return w;
529
544
  }
530
545
  }
531
- if (targetWindow) break;
546
+ if (ws.windows.count > 0) {
547
+ return ws.windows.firstObject;
548
+ }
532
549
  }
533
550
  }
534
- if (!targetWindow) {
535
- targetWindow = [UIApplication sharedApplication].keyWindow;
536
- if (!targetWindow && [UIApplication sharedApplication].windows.count > 0) {
537
- targetWindow = [UIApplication sharedApplication].windows.firstObject;
538
- }
551
+ }
552
+ for (UIWindow *w in [UIApplication sharedApplication].windows) {
553
+ if (w.isKeyWindow || w.windowLevel == UIWindowLevelNormal) {
554
+ return w;
539
555
  }
556
+ }
557
+ return [UIApplication sharedApplication].windows.firstObject;
558
+ }
540
559
 
541
- if (!targetWindow) {
542
- resolve(@(NO));
543
- return;
544
- }
560
+ RCT_EXPORT_METHOD(showFloatingButton:(NSDictionary *)options
561
+ resolve:(RCTPromiseResolveBlock)resolve
562
+ reject:(RCTPromiseRejectBlock)reject) {
563
+ dispatch_async(dispatch_get_main_queue(), ^{
564
+ UIWindow *targetWindow = GetAppActiveWindow();
565
+ CGRect screenBounds = targetWindow ? targetWindow.bounds : [UIScreen mainScreen].bounds;
566
+
567
+ CGFloat screenWidth = screenBounds.size.width > 0 ? screenBounds.size.width : [UIScreen mainScreen].bounds.size.width;
568
+ if (screenWidth <= 0) screenWidth = 393.0;
569
+ CGFloat screenHeight = screenBounds.size.height > 0 ? screenBounds.size.height : [UIScreen mainScreen].bounds.size.height;
570
+ if (screenHeight <= 0) screenHeight = 852.0;
545
571
 
546
572
  CGFloat size = 64.0;
547
573
  if (options && options[@"size"]) {
548
574
  size = [options[@"size"] doubleValue];
549
575
  }
550
576
 
551
- CGFloat initialX = targetWindow.bounds.size.width - size - 20.0;
552
- CGFloat initialY = targetWindow.bounds.size.height - size - 110.0;
577
+ CGFloat initialX = screenWidth - size - 20.0;
578
+ CGFloat initialY = screenHeight - size - 120.0;
553
579
  if (options && options[@"x"]) {
554
580
  initialX = [options[@"x"] doubleValue];
555
581
  }
@@ -559,6 +585,7 @@ RCT_EXPORT_METHOD(showFloatingButton:(NSDictionary *)options
559
585
 
560
586
  if (floatingButtonView == nil) {
561
587
  floatingButtonView = [[InAppInspectorFloatingView alloc] initWithFrame:CGRectMake(initialX, initialY, size, size)];
588
+ floatingButtonView.layer.zPosition = 999999;
562
589
  __weak NetworkInspectorModule *weakSelf = self;
563
590
  floatingButtonView.onTapBlock = ^{
564
591
  NetworkInspectorModule *strongSelf = weakSelf ?: sharedInstance;
@@ -566,26 +593,47 @@ RCT_EXPORT_METHOD(showFloatingButton:(NSDictionary *)options
566
593
  [strongSelf sendEventWithName:@"onFloatingButtonPress" body:@{}];
567
594
  }
568
595
  };
569
- }
570
-
571
- if (floatingButtonView.superview == nil) {
572
- [targetWindow addSubview:floatingButtonView];
573
596
  } else {
574
- [targetWindow bringSubviewToFront:floatingButtonView];
597
+ floatingButtonView.layer.zPosition = 999999;
598
+ floatingButtonView.frame = CGRectMake(initialX, initialY, size, size);
575
599
  }
576
-
577
- floatingButtonView.hidden = NO;
578
- floatingButtonView.alpha = 0.0;
579
- [UIView animateWithDuration:0.2 animations:^{
600
+
601
+ void (^attachToWindow)(void) = ^{
602
+ UIWindow *activeWin = GetAppActiveWindow();
603
+ if (!activeWin || !floatingButtonView) return;
604
+
605
+ CGRect winBounds = activeWin.bounds;
606
+ if (winBounds.size.width > 0 && winBounds.size.height > 0) {
607
+ CGRect curFrame = floatingButtonView.frame;
608
+ if (curFrame.origin.x <= 0 || curFrame.origin.x >= winBounds.size.width ||
609
+ curFrame.origin.y <= 0 || curFrame.origin.y >= winBounds.size.height) {
610
+ floatingButtonView.frame = CGRectMake(winBounds.size.width - curFrame.size.width - 20.0,
611
+ winBounds.size.height - curFrame.size.height - 120.0,
612
+ curFrame.size.width,
613
+ curFrame.size.height);
614
+ }
615
+ }
616
+
617
+ if (floatingButtonView.superview != activeWin) {
618
+ [activeWin addSubview:floatingButtonView];
619
+ }
620
+ [activeWin bringSubviewToFront:floatingButtonView];
621
+ floatingButtonView.hidden = NO;
580
622
  floatingButtonView.alpha = 1.0;
581
- }];
623
+ [floatingButtonView.subviews.firstObject setNeedsDisplay];
624
+ };
625
+
626
+ attachToWindow();
627
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), attachToWindow);
628
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.8 * NSEC_PER_SEC)), dispatch_get_main_queue(), attachToWindow);
629
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), attachToWindow);
582
630
 
583
631
  resolve(@(YES));
584
632
  });
585
633
  }
586
634
 
587
635
  RCT_EXPORT_METHOD(hideFloatingButton:(RCTPromiseResolveBlock)resolve
588
- rejecter:(RCTPromiseRejectBlock)reject) {
636
+ reject:(RCTPromiseRejectBlock)reject) {
589
637
  dispatch_async(dispatch_get_main_queue(), ^{
590
638
  if (floatingButtonView != nil) {
591
639
  [UIView animateWithDuration:0.15 animations:^{
@@ -599,8 +647,8 @@ RCT_EXPORT_METHOD(hideFloatingButton:(RCTPromiseResolveBlock)resolve
599
647
  }
600
648
 
601
649
  RCT_EXPORT_METHOD(setFloatingButtonBadge:(BOOL)hasBadge
602
- resolver:(RCTPromiseResolveBlock)resolve
603
- rejecter:(RCTPromiseRejectBlock)reject) {
650
+ resolve:(RCTPromiseResolveBlock)resolve
651
+ reject:(RCTPromiseRejectBlock)reject) {
604
652
  dispatch_async(dispatch_get_main_queue(), ^{
605
653
  if (floatingButtonView != nil) {
606
654
  [floatingButtonView updateBadgeVisible:hasBadge];
@@ -610,8 +658,8 @@ RCT_EXPORT_METHOD(setFloatingButtonBadge:(BOOL)hasBadge
610
658
  }
611
659
 
612
660
  RCT_EXPORT_METHOD(setFloatingButtonPosition:(double)x y:(double)y
613
- resolver:(RCTPromiseResolveBlock)resolve
614
- rejecter:(RCTPromiseRejectBlock)reject) {
661
+ resolve:(RCTPromiseResolveBlock)resolve
662
+ reject:(RCTPromiseRejectBlock)reject) {
615
663
  dispatch_async(dispatch_get_main_queue(), ^{
616
664
  if (floatingButtonView != nil && floatingButtonView.superview != nil) {
617
665
  floatingButtonView.frame = CGRectMake(x, y, floatingButtonView.frame.size.width, floatingButtonView.frame.size.height);
@@ -621,7 +669,7 @@ RCT_EXPORT_METHOD(setFloatingButtonPosition:(double)x y:(double)y
621
669
  }
622
670
 
623
671
  RCT_EXPORT_METHOD(startFpsMonitoring:(RCTPromiseResolveBlock)resolve
624
- rejecter:(RCTPromiseRejectBlock)reject) {
672
+ reject:(RCTPromiseRejectBlock)reject) {
625
673
  dispatch_async(dispatch_get_main_queue(), ^{
626
674
  if (self->displayLink == nil) {
627
675
  self->lastFpsTimestamp = 0;
@@ -649,7 +697,7 @@ RCT_EXPORT_METHOD(startFpsMonitoring:(RCTPromiseResolveBlock)resolve
649
697
  }
650
698
 
651
699
  RCT_EXPORT_METHOD(stopFpsMonitoring:(RCTPromiseResolveBlock)resolve
652
- rejecter:(RCTPromiseRejectBlock)reject) {
700
+ reject:(RCTPromiseRejectBlock)reject) {
653
701
  dispatch_async(dispatch_get_main_queue(), ^{
654
702
  if (self->displayLink != nil) {
655
703
  [self->displayLink invalidate];
@@ -660,7 +708,7 @@ RCT_EXPORT_METHOD(stopFpsMonitoring:(RCTPromiseResolveBlock)resolve
660
708
  }
661
709
 
662
710
  RCT_EXPORT_METHOD(getFpsMetrics:(RCTPromiseResolveBlock)resolve
663
- rejecter:(RCTPromiseRejectBlock)reject) {
711
+ reject:(RCTPromiseRejectBlock)reject) {
664
712
  NSMutableDictionary *dict = [NSMutableDictionary dictionary];
665
713
  [dict setObject:@(self->currentCalculatedFps > 0 ? self->currentCalculatedFps : 60.0) forKey:@"fps"];
666
714
  [dict setObject:@(60.0) forKey:@"targetFps"];
@@ -668,8 +716,8 @@ RCT_EXPORT_METHOD(getFpsMetrics:(RCTPromiseResolveBlock)resolve
668
716
  }
669
717
 
670
718
  RCT_EXPORT_METHOD(getNativeStorageItem:(NSString *)key
671
- resolver:(RCTPromiseResolveBlock)resolve
672
- rejecter:(RCTPromiseRejectBlock)reject) {
719
+ resolve:(RCTPromiseResolveBlock)resolve
720
+ reject:(RCTPromiseRejectBlock)reject) {
673
721
  NSString *prefKey = [NSString stringWithFormat:@"inapp_inspector_%@", key ?: @""];
674
722
  NSString *val = [[NSUserDefaults standardUserDefaults] stringForKey:prefKey];
675
723
  resolve(val ?: [NSNull null]);
@@ -677,8 +725,8 @@ RCT_EXPORT_METHOD(getNativeStorageItem:(NSString *)key
677
725
 
678
726
  RCT_EXPORT_METHOD(setNativeStorageItem:(NSString *)key
679
727
  value:(NSString *)value
680
- resolver:(RCTPromiseResolveBlock)resolve
681
- rejecter:(RCTPromiseRejectBlock)reject) {
728
+ resolve:(RCTPromiseResolveBlock)resolve
729
+ reject:(RCTPromiseRejectBlock)reject) {
682
730
  NSString *prefKey = [NSString stringWithFormat:@"inapp_inspector_%@", key ?: @""];
683
731
  if (value == nil || [value isKindOfClass:[NSNull class]]) {
684
732
  [[NSUserDefaults standardUserDefaults] removeObjectForKey:prefKey];
@@ -690,8 +738,8 @@ RCT_EXPORT_METHOD(setNativeStorageItem:(NSString *)key
690
738
  }
691
739
 
692
740
  RCT_EXPORT_METHOD(triggerHaptic:(NSString *)style
693
- resolver:(RCTPromiseResolveBlock)resolve
694
- rejecter:(RCTPromiseRejectBlock)reject) {
741
+ resolve:(RCTPromiseResolveBlock)resolve
742
+ reject:(RCTPromiseRejectBlock)reject) {
695
743
  dispatch_async(dispatch_get_main_queue(), ^{
696
744
  if (@available(iOS 10.0, *)) {
697
745
  NSString *s = [style lowercaseString] ?: @"light";
@@ -725,8 +773,16 @@ RCT_EXPORT_METHOD(triggerHaptic:(NSString *)style
725
773
  });
726
774
  }
727
775
 
776
+ RCT_EXPORT_METHOD(addListener:(NSString *)eventName) {
777
+ [super addListener:eventName];
778
+ }
779
+
780
+ RCT_EXPORT_METHOD(removeListeners:(double)count) {
781
+ [super removeListeners:count];
782
+ }
783
+
728
784
  RCT_EXPORT_METHOD(getNativeSystemMetrics:(RCTPromiseResolveBlock)resolve
729
- rejecter:(RCTPromiseRejectBlock)reject) {
785
+ reject:(RCTPromiseRejectBlock)reject) {
730
786
  dispatch_async(self->_metricsQueue, ^{
731
787
  NSMutableDictionary *dict = [NSMutableDictionary dictionary];
732
788
 
@@ -813,8 +869,8 @@ RCT_EXPORT_METHOD(pushNativeLogRecord:(NSString *)pageKey
813
869
  }
814
870
 
815
871
  RCT_EXPORT_METHOD(getNativeCachedPage:(NSString *)pageKey
816
- offset:(NSInteger)offset
817
- limit:(NSInteger)limit
872
+ offset:(double)offset
873
+ limit:(double)limit
818
874
  query:(NSString *)query
819
875
  resolve:(RCTPromiseResolveBlock)resolve
820
876
  reject:(RCTPromiseRejectBlock)reject) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-inapp-inspector",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "The zero-config, all-in-one in-app debugger for React Native & Expo. Inspect Network (fetch/axios), Console logs, Stack Traces, Redux State, Firebase Analytics, and JS Bundle size directly on device.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,7 +43,7 @@
43
43
  "scripts": {
44
44
  "clean": "rm -rf dist",
45
45
  "prebuild": "node scripts/gen-version.js",
46
- "build": "npm run clean && tsc && tsc -p tsconfig.esm.json",
46
+ "build": "npm run clean && tsc && tsc -p tsconfig.esm.json && node scripts/inject-telemetry.js",
47
47
  "watch": "tsc -w",
48
48
  "prepack": "npm run build",
49
49
  "publish": "node release.cjs",