react-native-inapp-inspector 1.1.34 → 2.0.0
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 +123 -101
- package/android/build.gradle +13 -1
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +904 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.kt +17 -0
- package/dist/commonjs/components/ConsoleLogCard.js +57 -56
- package/dist/commonjs/components/CopyButton.js +10 -1
- package/dist/commonjs/components/ErrorBoundary.js +3 -0
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +7 -3
- package/dist/commonjs/components/Inspector/BundleTab.js +20 -20
- package/dist/commonjs/components/Inspector/ConsoleTab.js +1 -1
- package/dist/commonjs/components/Inspector/CrashDetail.js +16 -12
- package/dist/commonjs/components/Inspector/CrashTab.js +97 -90
- package/dist/commonjs/components/Inspector/InspectorHeader.js +28 -24
- package/dist/commonjs/components/Inspector/MainScreen.js +20 -103
- package/dist/commonjs/components/Inspector/NetworkTab.js +143 -10
- package/dist/commonjs/components/Inspector/PerformanceTab.js +96 -3
- package/dist/commonjs/components/Inspector/ReduxDetail.js +24 -19
- package/dist/commonjs/components/Inspector/ReduxTab.js +30 -18
- package/dist/commonjs/components/Inspector/SettingsPanel.js +1578 -754
- package/dist/commonjs/components/Inspector/TabBar.js +6 -3
- package/dist/commonjs/components/LogCard.js +27 -9
- package/dist/commonjs/components/MetaAccordion.js +42 -0
- package/dist/commonjs/components/NetworkIcons.d.ts +10 -0
- package/dist/commonjs/components/NetworkIcons.js +53 -1
- package/dist/commonjs/components/Toast.js +3 -3
- package/dist/commonjs/components/TouchableScale.d.ts +5 -2
- package/dist/commonjs/components/TouchableScale.js +30 -32
- package/dist/commonjs/constants/index.d.ts +1 -2
- package/dist/commonjs/constants/index.js +4 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.d.ts +6 -0
- package/dist/commonjs/customHooks/analyticsLogger.js +16 -5
- package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +2 -0
- package/dist/commonjs/customHooks/bundleAnalyzer.js +26 -17
- package/dist/commonjs/customHooks/consoleLogger.d.ts +2 -0
- package/dist/commonjs/customHooks/consoleLogger.js +10 -1
- package/dist/commonjs/customHooks/crashHandler.d.ts +2 -0
- package/dist/commonjs/customHooks/crashHandler.js +17 -1
- package/dist/commonjs/customHooks/networkLogger.d.ts +2 -0
- package/dist/commonjs/customHooks/networkLogger.js +12 -1
- package/dist/commonjs/customHooks/performanceTracker.d.ts +3 -1
- package/dist/commonjs/customHooks/performanceTracker.js +18 -4
- package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
- package/dist/commonjs/customHooks/reduxLogger.js +10 -1
- package/dist/commonjs/helpers/index.js +10 -1
- package/dist/commonjs/helpers/settingsStore.d.ts +9 -0
- package/dist/commonjs/helpers/settingsStore.js +59 -3
- package/dist/commonjs/i18n/locales/en.json +96 -28
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +307 -73
- package/dist/commonjs/native/NativeInspector.d.ts +125 -0
- package/dist/commonjs/native/NativeInspector.js +313 -0
- package/dist/commonjs/native/NativeNetworkInspector.d.ts +22 -0
- package/dist/commonjs/native/NativeNetworkInspector.js +4 -0
- package/dist/commonjs/styles/AppColors.d.ts +28 -0
- package/dist/commonjs/styles/AppColors.js +30 -0
- package/dist/commonjs/styles/index.js +6 -6
- package/dist/commonjs/types/enums.d.ts +1 -1
- package/dist/commonjs/types/interfaces.d.ts +9 -0
- package/dist/esm/components/ConsoleLogCard.js +58 -57
- package/dist/esm/components/CopyButton.js +10 -1
- package/dist/esm/components/ErrorBoundary.js +3 -0
- package/dist/esm/components/Inspector/AnalyticsTab.js +7 -3
- package/dist/esm/components/Inspector/BundleTab.js +20 -20
- package/dist/esm/components/Inspector/ConsoleTab.js +1 -1
- package/dist/esm/components/Inspector/CrashDetail.js +16 -12
- package/dist/esm/components/Inspector/CrashTab.js +97 -90
- package/dist/esm/components/Inspector/InspectorHeader.js +29 -25
- package/dist/esm/components/Inspector/MainScreen.js +21 -71
- package/dist/esm/components/Inspector/NetworkTab.js +145 -12
- package/dist/esm/components/Inspector/PerformanceTab.js +96 -3
- package/dist/esm/components/Inspector/ReduxDetail.js +24 -19
- package/dist/esm/components/Inspector/ReduxTab.js +30 -18
- package/dist/esm/components/Inspector/SettingsPanel.js +1582 -758
- package/dist/esm/components/Inspector/TabBar.js +7 -4
- package/dist/esm/components/LogCard.js +27 -9
- package/dist/esm/components/MetaAccordion.js +42 -0
- package/dist/esm/components/NetworkIcons.d.ts +10 -0
- package/dist/esm/components/NetworkIcons.js +42 -0
- package/dist/esm/components/Toast.js +3 -3
- package/dist/esm/components/TouchableScale.d.ts +5 -2
- package/dist/esm/components/TouchableScale.js +31 -33
- package/dist/esm/constants/index.d.ts +1 -2
- package/dist/esm/constants/index.js +4 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.d.ts +6 -0
- package/dist/esm/customHooks/analyticsLogger.js +12 -4
- package/dist/esm/customHooks/bundleAnalyzer.d.ts +2 -0
- package/dist/esm/customHooks/bundleAnalyzer.js +23 -16
- package/dist/esm/customHooks/consoleLogger.d.ts +2 -0
- package/dist/esm/customHooks/consoleLogger.js +7 -0
- package/dist/esm/customHooks/crashHandler.d.ts +2 -0
- package/dist/esm/customHooks/crashHandler.js +14 -0
- package/dist/esm/customHooks/networkLogger.d.ts +2 -0
- package/dist/esm/customHooks/networkLogger.js +9 -0
- package/dist/esm/customHooks/performanceTracker.d.ts +3 -1
- package/dist/esm/customHooks/performanceTracker.js +15 -3
- package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
- package/dist/esm/customHooks/reduxLogger.js +7 -0
- package/dist/esm/helpers/index.js +10 -1
- package/dist/esm/helpers/settingsStore.d.ts +9 -0
- package/dist/esm/helpers/settingsStore.js +58 -3
- package/dist/esm/i18n/locales/en.json +96 -28
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +279 -59
- package/dist/esm/native/NativeInspector.d.ts +125 -0
- package/dist/esm/native/NativeInspector.js +289 -0
- package/dist/esm/native/NativeNetworkInspector.d.ts +22 -0
- package/dist/esm/native/NativeNetworkInspector.js +2 -0
- package/dist/esm/styles/AppColors.d.ts +28 -0
- package/dist/esm/styles/AppColors.js +30 -0
- package/dist/esm/styles/index.js +6 -6
- package/dist/esm/types/enums.d.ts +1 -1
- package/dist/esm/types/interfaces.d.ts +9 -0
- package/ios/NetworkInspectorModule.h +6 -0
- package/ios/NetworkInspectorModule.m +720 -5
- package/package.json +15 -3
- package/react-native-inapp-inspector.podspec +7 -2
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +0 -97
- package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +0 -28
|
@@ -6,6 +6,265 @@
|
|
|
6
6
|
static NetworkInspectorModule *sharedInstance = nil;
|
|
7
7
|
static NSUncaughtExceptionHandler *previousUncaughtExceptionHandler = NULL;
|
|
8
8
|
|
|
9
|
+
@interface InAppInspectorFloatingView : UIView
|
|
10
|
+
@property (nonatomic, copy) void (^onTapBlock)(void);
|
|
11
|
+
@property (nonatomic, strong) UIView *badgeDot;
|
|
12
|
+
- (void)updateBadgeVisible:(BOOL)visible;
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
@interface InAppInspectorOwlView : UIView
|
|
16
|
+
@end
|
|
17
|
+
|
|
18
|
+
@implementation InAppInspectorOwlView
|
|
19
|
+
|
|
20
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
21
|
+
if (self = [super initWithFrame:frame]) {
|
|
22
|
+
self.backgroundColor = [UIColor clearColor];
|
|
23
|
+
self.userInteractionEnabled = NO;
|
|
24
|
+
}
|
|
25
|
+
return self;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
- (void)drawRect:(CGRect)rect {
|
|
29
|
+
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
|
30
|
+
if (!ctx) return;
|
|
31
|
+
|
|
32
|
+
CGFloat w = rect.size.width;
|
|
33
|
+
CGFloat scale = w / 256.0;
|
|
34
|
+
|
|
35
|
+
CGContextSaveGState(ctx);
|
|
36
|
+
CGContextScaleCTM(ctx, scale, scale);
|
|
37
|
+
|
|
38
|
+
// 1. Owl Body with Ears
|
|
39
|
+
UIBezierPath *bodyPath = [UIBezierPath bezierPath];
|
|
40
|
+
[bodyPath moveToPoint:CGPointMake(62, 150)];
|
|
41
|
+
[bodyPath addCurveToPoint:CGPointMake(90, 58) controlPoint1:CGPointMake(58, 104) controlPoint2:CGPointMake(70, 70)];
|
|
42
|
+
[bodyPath addLineToPoint:CGPointMake(98, 42)]; // Left ear
|
|
43
|
+
[bodyPath addLineToPoint:CGPointMake(116, 62)];
|
|
44
|
+
[bodyPath addQuadCurveToPoint:CGPointMake(140, 62) controlPoint:CGPointMake(128, 57)];
|
|
45
|
+
[bodyPath addLineToPoint:CGPointMake(158, 42)]; // Right ear
|
|
46
|
+
[bodyPath addLineToPoint:CGPointMake(166, 58)];
|
|
47
|
+
[bodyPath addCurveToPoint:CGPointMake(194, 150) controlPoint1:CGPointMake(186, 70) controlPoint2:CGPointMake(198, 104)];
|
|
48
|
+
[bodyPath addCurveToPoint:CGPointMake(152, 212) controlPoint1:CGPointMake(198, 180) controlPoint2:CGPointMake(184, 204)];
|
|
49
|
+
[bodyPath addCurveToPoint:CGPointMake(104, 212) controlPoint1:CGPointMake(140, 216) controlPoint2:CGPointMake(116, 216)];
|
|
50
|
+
[bodyPath addCurveToPoint:CGPointMake(62, 150) controlPoint1:CGPointMake(72, 204) controlPoint2:CGPointMake(58, 180)];
|
|
51
|
+
[bodyPath closePath];
|
|
52
|
+
|
|
53
|
+
[[UIColor colorWithRed:32.0/255.0 green:46.0/255.0 blue:85.0/255.0 alpha:1.0] setFill];
|
|
54
|
+
[bodyPath fill];
|
|
55
|
+
|
|
56
|
+
[[UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:1.0] setStroke];
|
|
57
|
+
bodyPath.lineWidth = 4.0;
|
|
58
|
+
[bodyPath stroke];
|
|
59
|
+
|
|
60
|
+
// 2. Wings
|
|
61
|
+
UIBezierPath *leftWing = [UIBezierPath bezierPath];
|
|
62
|
+
[leftWing moveToPoint:CGPointMake(74, 124)];
|
|
63
|
+
[leftWing addCurveToPoint:CGPointMake(86, 204) controlPoint1:CGPointMake(58, 154) controlPoint2:CGPointMake(60, 190)];
|
|
64
|
+
[leftWing addCurveToPoint:CGPointMake(88, 126) controlPoint1:CGPointMake(79, 176) controlPoint2:CGPointMake(77, 148)];
|
|
65
|
+
[leftWing closePath];
|
|
66
|
+
[[UIColor colorWithRed:26.0/255.0 green:37.0/255.0 blue:69.0/255.0 alpha:1.0] setFill];
|
|
67
|
+
[leftWing fill];
|
|
68
|
+
|
|
69
|
+
UIBezierPath *rightWing = [UIBezierPath bezierPath];
|
|
70
|
+
[rightWing moveToPoint:CGPointMake(182, 124)];
|
|
71
|
+
[rightWing addCurveToPoint:CGPointMake(170, 204) controlPoint1:CGPointMake(198, 154) controlPoint2:CGPointMake(196, 190)];
|
|
72
|
+
[rightWing addCurveToPoint:CGPointMake(168, 126) controlPoint1:CGPointMake(177, 176) controlPoint2:CGPointMake(179, 148)];
|
|
73
|
+
[rightWing closePath];
|
|
74
|
+
[[UIColor colorWithRed:26.0/255.0 green:37.0/255.0 blue:69.0/255.0 alpha:1.0] setFill];
|
|
75
|
+
[rightWing fill];
|
|
76
|
+
|
|
77
|
+
// 3. Belly Plate
|
|
78
|
+
UIBezierPath *belly = [UIBezierPath bezierPath];
|
|
79
|
+
[belly moveToPoint:CGPointMake(128, 126)];
|
|
80
|
+
[belly addCurveToPoint:CGPointMake(162, 174) controlPoint1:CGPointMake(151, 126) controlPoint2:CGPointMake(164, 148)];
|
|
81
|
+
[belly addCurveToPoint:CGPointMake(128, 212) controlPoint1:CGPointMake(160, 198) controlPoint2:CGPointMake(146, 212)];
|
|
82
|
+
[belly addCurveToPoint:CGPointMake(94, 174) controlPoint1:CGPointMake(110, 212) controlPoint2:CGPointMake(96, 198)];
|
|
83
|
+
[belly addCurveToPoint:CGPointMake(128, 126) controlPoint1:CGPointMake(92, 148) controlPoint2:CGPointMake(105, 126)];
|
|
84
|
+
[belly closePath];
|
|
85
|
+
[[UIColor colorWithRed:51.0/255.0 green:71.0/255.0 blue:122.0/255.0 alpha:1.0] setFill];
|
|
86
|
+
[belly fill];
|
|
87
|
+
|
|
88
|
+
// 4. Chest Screen `< / >`
|
|
89
|
+
UIBezierPath *screen = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(107, 161, 42, 32) cornerRadius:8];
|
|
90
|
+
[[UIColor colorWithRed:12.0/255.0 green:20.0/255.0 blue:38.0/255.0 alpha:1.0] setFill];
|
|
91
|
+
[screen fill];
|
|
92
|
+
[[UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:0.8] setStroke];
|
|
93
|
+
screen.lineWidth = 2.0;
|
|
94
|
+
[screen stroke];
|
|
95
|
+
|
|
96
|
+
UIBezierPath *codeLines = [UIBezierPath bezierPath];
|
|
97
|
+
[codeLines moveToPoint:CGPointMake(122, 170)];
|
|
98
|
+
[codeLines addLineToPoint:CGPointMake(115, 177)];
|
|
99
|
+
[codeLines addLineToPoint:CGPointMake(122, 184)];
|
|
100
|
+
[codeLines moveToPoint:CGPointMake(134, 170)];
|
|
101
|
+
[codeLines addLineToPoint:CGPointMake(141, 177)];
|
|
102
|
+
[codeLines addLineToPoint:CGPointMake(134, 184)];
|
|
103
|
+
[codeLines moveToPoint:CGPointMake(130, 168)];
|
|
104
|
+
[codeLines addLineToPoint:CGPointMake(126, 186)];
|
|
105
|
+
[[UIColor colorWithRed:143.0/255.0 green:208.0/255.0 blue:236.0/255.0 alpha:1.0] setStroke];
|
|
106
|
+
codeLines.lineWidth = 3.0;
|
|
107
|
+
codeLines.lineCapStyle = kCGLineCapRound;
|
|
108
|
+
codeLines.lineJoinStyle = kCGLineJoinRound;
|
|
109
|
+
[codeLines stroke];
|
|
110
|
+
|
|
111
|
+
// 5. Normal Right Eye
|
|
112
|
+
UIBezierPath *rightEye = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(136, 90, 34, 34)];
|
|
113
|
+
[[UIColor colorWithRed:251.0/255.0 green:191.0/255.0 blue:36.0/255.0 alpha:1.0] setFill];
|
|
114
|
+
[rightEye fill];
|
|
115
|
+
[[UIColor colorWithRed:26.0/255.0 green:18.0/255.0 blue:5.0/255.0 alpha:1.0] setStroke];
|
|
116
|
+
rightEye.lineWidth = 2.2;
|
|
117
|
+
[rightEye stroke];
|
|
118
|
+
|
|
119
|
+
UIBezierPath *rightPupil = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(145, 100, 16, 16)];
|
|
120
|
+
[[UIColor colorWithRed:10.0/255.0 green:14.0/255.0 blue:24.0/255.0 alpha:1.0] setFill];
|
|
121
|
+
[rightPupil fill];
|
|
122
|
+
|
|
123
|
+
UIBezierPath *rightGlint = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(153, 98, 6, 6)];
|
|
124
|
+
[[UIColor whiteColor] setFill];
|
|
125
|
+
[rightGlint fill];
|
|
126
|
+
|
|
127
|
+
// 6. Beak
|
|
128
|
+
UIBezierPath *beak = [UIBezierPath bezierPath];
|
|
129
|
+
[beak moveToPoint:CGPointMake(123.5, 123)];
|
|
130
|
+
[beak addQuadCurveToPoint:CGPointMake(132.5, 123) controlPoint:CGPointMake(128, 121)];
|
|
131
|
+
[beak addQuadCurveToPoint:CGPointMake(128, 134.5) controlPoint:CGPointMake(131, 132)];
|
|
132
|
+
[beak addQuadCurveToPoint:CGPointMake(123.5, 123) controlPoint:CGPointMake(125, 132)];
|
|
133
|
+
[beak closePath];
|
|
134
|
+
[[UIColor colorWithRed:251.0/255.0 green:146.0/255.0 blue:60.0/255.0 alpha:1.0] setFill];
|
|
135
|
+
[beak fill];
|
|
136
|
+
|
|
137
|
+
// 7. Magnifier Debug Left Eye
|
|
138
|
+
UIBezierPath *leftEye = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(75, 83, 40, 40)];
|
|
139
|
+
[[UIColor colorWithRed:251.0/255.0 green:191.0/255.0 blue:36.0/255.0 alpha:1.0] setFill];
|
|
140
|
+
[leftEye fill];
|
|
141
|
+
[[UIColor colorWithRed:26.0/255.0 green:18.0/255.0 blue:5.0/255.0 alpha:1.0] setStroke];
|
|
142
|
+
leftEye.lineWidth = 2.6;
|
|
143
|
+
[leftEye stroke];
|
|
144
|
+
|
|
145
|
+
UIBezierPath *leftPupil = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(85, 94, 20, 20)];
|
|
146
|
+
[[UIColor colorWithRed:10.0/255.0 green:14.0/255.0 blue:24.0/255.0 alpha:1.0] setFill];
|
|
147
|
+
[leftPupil fill];
|
|
148
|
+
|
|
149
|
+
UIBezierPath *leftGlint = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(95, 92, 7, 7)];
|
|
150
|
+
[[UIColor whiteColor] setFill];
|
|
151
|
+
[leftGlint fill];
|
|
152
|
+
|
|
153
|
+
// Magnifier Lens Ring & Handle
|
|
154
|
+
UIBezierPath *handle = [UIBezierPath bezierPath];
|
|
155
|
+
[handle moveToPoint:CGPointMake(75, 123)];
|
|
156
|
+
[handle addLineToPoint:CGPointMake(54, 147)];
|
|
157
|
+
[[UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:1.0] setStroke];
|
|
158
|
+
handle.lineWidth = 8.5;
|
|
159
|
+
handle.lineCapStyle = kCGLineCapRound;
|
|
160
|
+
[handle stroke];
|
|
161
|
+
|
|
162
|
+
UIBezierPath *lensRing = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(67, 75, 56, 56)];
|
|
163
|
+
lensRing.lineWidth = 7.0;
|
|
164
|
+
[lensRing stroke];
|
|
165
|
+
|
|
166
|
+
// Rosy Cheeks
|
|
167
|
+
UIBezierPath *leftCheek = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(74, 121, 18, 12)];
|
|
168
|
+
[[UIColor colorWithRed:251.0/255.0 green:113.0/255.0 blue:133.0/255.0 alpha:0.5] setFill];
|
|
169
|
+
[leftCheek fill];
|
|
170
|
+
|
|
171
|
+
UIBezierPath *rightCheek = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(158, 116, 18, 12)];
|
|
172
|
+
[[UIColor colorWithRed:251.0/255.0 green:113.0/255.0 blue:133.0/255.0 alpha:0.5] setFill];
|
|
173
|
+
[rightCheek fill];
|
|
174
|
+
|
|
175
|
+
CGContextRestoreGState(ctx);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@end
|
|
179
|
+
|
|
180
|
+
@implementation InAppInspectorFloatingView
|
|
181
|
+
|
|
182
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
183
|
+
self = [super initWithFrame:frame];
|
|
184
|
+
if (self) {
|
|
185
|
+
self.layer.cornerRadius = frame.size.width / 2.0;
|
|
186
|
+
self.layer.masksToBounds = NO;
|
|
187
|
+
self.backgroundColor = [UIColor colorWithRed:15.0/255.0 green:23.0/255.0 blue:42.0/255.0 alpha:0.95];
|
|
188
|
+
|
|
189
|
+
// Glow shadow
|
|
190
|
+
self.layer.shadowColor = [UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:0.65].CGColor;
|
|
191
|
+
self.layer.shadowOffset = CGSizeMake(0, 5);
|
|
192
|
+
self.layer.shadowRadius = 10;
|
|
193
|
+
self.layer.shadowOpacity = 1.0;
|
|
194
|
+
self.layer.borderWidth = 2.2;
|
|
195
|
+
self.layer.borderColor = [UIColor colorWithRed:56.0/255.0 green:189.0/255.0 blue:248.0/255.0 alpha:0.9].CGColor;
|
|
196
|
+
|
|
197
|
+
// Native drawn Inspector Owl icon (Enhanced & Larger)
|
|
198
|
+
CGFloat iconSize = frame.size.width * 0.94;
|
|
199
|
+
CGFloat iconOffset = (frame.size.width - iconSize) / 2.0;
|
|
200
|
+
InAppInspectorOwlView *owlView = [[InAppInspectorOwlView alloc] initWithFrame:CGRectMake(iconOffset, iconOffset, iconSize, iconSize)];
|
|
201
|
+
[self addSubview:owlView];
|
|
202
|
+
|
|
203
|
+
// Status dot badge
|
|
204
|
+
_badgeDot = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width - 14, 4, 10, 10)];
|
|
205
|
+
_badgeDot.layer.cornerRadius = 5;
|
|
206
|
+
_badgeDot.backgroundColor = [UIColor colorWithRed:34.0/255.0 green:197.0/255.0 blue:94.0/255.0 alpha:1.0];
|
|
207
|
+
_badgeDot.layer.borderColor = [UIColor colorWithRed:15.0/255.0 green:23.0/255.0 blue:42.0/255.0 alpha:1.0].CGColor;
|
|
208
|
+
_badgeDot.layer.borderWidth = 1.5;
|
|
209
|
+
_badgeDot.hidden = YES;
|
|
210
|
+
[self addSubview:_badgeDot];
|
|
211
|
+
|
|
212
|
+
// Gestures (Main UI thread only)
|
|
213
|
+
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
|
214
|
+
[self addGestureRecognizer:pan];
|
|
215
|
+
|
|
216
|
+
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
|
|
217
|
+
[self addGestureRecognizer:tap];
|
|
218
|
+
|
|
219
|
+
[tap requireGestureRecognizerToFail:pan];
|
|
220
|
+
}
|
|
221
|
+
return self;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
- (void)updateBadgeVisible:(BOOL)visible {
|
|
225
|
+
self.badgeDot.hidden = !visible;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
- (void)handleTap:(UITapGestureRecognizer *)gesture {
|
|
229
|
+
if (gesture.state == UIGestureRecognizerStateEnded) {
|
|
230
|
+
if (self.onTapBlock) {
|
|
231
|
+
self.onTapBlock();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
- (void)handlePan:(UIPanGestureRecognizer *)pan {
|
|
237
|
+
UIView *superview = self.superview;
|
|
238
|
+
if (!superview) return;
|
|
239
|
+
|
|
240
|
+
CGPoint translation = [pan translationInView:superview];
|
|
241
|
+
CGPoint newCenter = CGPointMake(self.center.x + translation.x, self.center.y + translation.y);
|
|
242
|
+
|
|
243
|
+
CGFloat halfW = self.bounds.size.width / 2.0;
|
|
244
|
+
CGFloat halfH = self.bounds.size.height / 2.0;
|
|
245
|
+
CGFloat minX = halfW + 10;
|
|
246
|
+
CGFloat maxX = superview.bounds.size.width - halfW - 10;
|
|
247
|
+
CGFloat minY = halfH + 44;
|
|
248
|
+
CGFloat maxY = superview.bounds.size.height - halfH - 44;
|
|
249
|
+
|
|
250
|
+
newCenter.x = MAX(minX, MIN(maxX, newCenter.x));
|
|
251
|
+
newCenter.y = MAX(minY, MIN(maxY, newCenter.y));
|
|
252
|
+
|
|
253
|
+
self.center = newCenter;
|
|
254
|
+
[pan setTranslation:CGPointZero inView:superview];
|
|
255
|
+
|
|
256
|
+
if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
|
|
257
|
+
CGFloat targetX = (self.center.x < superview.bounds.size.width / 2.0) ? minX : maxX;
|
|
258
|
+
[UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.75 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
|
259
|
+
self.center = CGPointMake(targetX, self.center.y);
|
|
260
|
+
} completion:nil];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@end
|
|
265
|
+
|
|
266
|
+
static InAppInspectorFloatingView *floatingButtonView = nil;
|
|
267
|
+
|
|
9
268
|
static void NativeSignalHandler(int signalNumber) {
|
|
10
269
|
void* callstack[128];
|
|
11
270
|
int frames = backtrace(callstack, 128);
|
|
@@ -58,22 +317,57 @@ static void NativeExceptionHandler(NSException *exception) {
|
|
|
58
317
|
|
|
59
318
|
@implementation NetworkInspectorModule {
|
|
60
319
|
bool hasListeners;
|
|
320
|
+
CADisplayLink *displayLink;
|
|
321
|
+
CFTimeInterval lastFpsTimestamp;
|
|
322
|
+
NSInteger frameCount;
|
|
323
|
+
double currentCalculatedFps;
|
|
324
|
+
dispatch_queue_t _networkQueue;
|
|
325
|
+
dispatch_queue_t _consoleQueue;
|
|
326
|
+
dispatch_queue_t _analyticsQueue;
|
|
327
|
+
dispatch_queue_t _reduxQueue;
|
|
328
|
+
dispatch_queue_t _crashQueue;
|
|
329
|
+
dispatch_queue_t _metricsQueue;
|
|
330
|
+
NSMutableArray *_nativeNetworkLogs;
|
|
331
|
+
NSMutableArray *_nativeConsoleLogs;
|
|
332
|
+
NSMutableArray *_nativeAnalyticsEvents;
|
|
333
|
+
NSMutableArray *_nativeCrashRecords;
|
|
61
334
|
}
|
|
62
335
|
|
|
63
336
|
RCT_EXPORT_MODULE(NetworkInspectorModule);
|
|
64
337
|
|
|
65
|
-
+ (BOOL)requiresMainQueueSetup {
|
|
66
|
-
return YES;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
338
|
- (instancetype)init {
|
|
70
339
|
if (self = [super init]) {
|
|
71
340
|
sharedInstance = self;
|
|
341
|
+
self->currentCalculatedFps = 60.0;
|
|
342
|
+
self->_networkQueue = dispatch_queue_create("com.inappinspector.network", DISPATCH_QUEUE_SERIAL);
|
|
343
|
+
self->_consoleQueue = dispatch_queue_create("com.inappinspector.console", DISPATCH_QUEUE_SERIAL);
|
|
344
|
+
self->_analyticsQueue = dispatch_queue_create("com.inappinspector.analytics", DISPATCH_QUEUE_SERIAL);
|
|
345
|
+
self->_reduxQueue = dispatch_queue_create("com.inappinspector.redux", DISPATCH_QUEUE_SERIAL);
|
|
346
|
+
self->_crashQueue = dispatch_queue_create("com.inappinspector.crash", DISPATCH_QUEUE_SERIAL);
|
|
347
|
+
self->_metricsQueue = dispatch_queue_create("com.inappinspector.metrics", DISPATCH_QUEUE_SERIAL);
|
|
348
|
+
self->_nativeNetworkLogs = [NSMutableArray array];
|
|
349
|
+
self->_nativeConsoleLogs = [NSMutableArray array];
|
|
350
|
+
self->_nativeAnalyticsEvents = [NSMutableArray array];
|
|
351
|
+
self->_nativeCrashRecords = [NSMutableArray array];
|
|
72
352
|
[self installHandlers];
|
|
353
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
354
|
+
selector:@selector(handleMotionShakeNotification:)
|
|
355
|
+
name:@"RCTShowDevMenuNotification"
|
|
356
|
+
object:nil];
|
|
73
357
|
}
|
|
74
358
|
return self;
|
|
75
359
|
}
|
|
76
360
|
|
|
361
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
362
|
+
return YES;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
- (void)handleMotionShakeNotification:(NSNotification *)notification {
|
|
366
|
+
if (hasListeners) {
|
|
367
|
+
[self sendEventWithName:@"onDeviceShake" body:@{}];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
77
371
|
- (void)startObserving {
|
|
78
372
|
hasListeners = YES;
|
|
79
373
|
}
|
|
@@ -83,7 +377,7 @@ RCT_EXPORT_MODULE(NetworkInspectorModule);
|
|
|
83
377
|
}
|
|
84
378
|
|
|
85
379
|
- (NSArray<NSString *> *)supportedEvents {
|
|
86
|
-
return @[@"onNativeCrash"];
|
|
380
|
+
return @[@"onNativeCrash", @"onFloatingButtonPress", @"onDeviceShake"];
|
|
87
381
|
}
|
|
88
382
|
|
|
89
383
|
- (void)installHandlers {
|
|
@@ -122,4 +416,425 @@ RCT_EXPORT_METHOD(enableNativeCrashProtection:(RCTPromiseResolveBlock)resolve
|
|
|
122
416
|
resolve(@(YES));
|
|
123
417
|
}
|
|
124
418
|
|
|
419
|
+
RCT_EXPORT_METHOD(getDeviceMetrics:(RCTPromiseResolveBlock)resolve
|
|
420
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
421
|
+
NSMutableDictionary *metrics = [NSMutableDictionary dictionary];
|
|
422
|
+
|
|
423
|
+
// 1. Memory / RAM Metrics
|
|
424
|
+
unsigned long long physicalMemory = [NSProcessInfo processInfo].physicalMemory;
|
|
425
|
+
[metrics setObject:@(physicalMemory) forKey:@"totalRAM"];
|
|
426
|
+
|
|
427
|
+
// App Resident Memory via mach task
|
|
428
|
+
struct mach_task_basic_info info;
|
|
429
|
+
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
|
|
430
|
+
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) {
|
|
431
|
+
[metrics setObject:@(info.resident_size) forKey:@"residentMemory"];
|
|
432
|
+
[metrics setObject:@(info.virtual_size) forKey:@"virtualMemory"];
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Free Memory
|
|
436
|
+
mach_port_t host_port = mach_host_self();
|
|
437
|
+
mach_msg_type_number_t host_size = sizeof(vm_statistics64_data_t) / sizeof(integer_t);
|
|
438
|
+
vm_size_t pagesize;
|
|
439
|
+
vm_statistics64_data_t vm_stat;
|
|
440
|
+
host_page_size(host_port, &pagesize);
|
|
441
|
+
if (host_statistics64(host_port, HOST_VM_INFO64, (host_info64_t)&vm_stat, &host_size) == KERN_SUCCESS) {
|
|
442
|
+
unsigned long long freeMem = (vm_stat.free_count + vm_stat.inactive_count) * pagesize;
|
|
443
|
+
[metrics setObject:@(freeMem) forKey:@"freeRAM"];
|
|
444
|
+
[metrics setObject:@(physicalMemory - freeMem) forKey:@"usedRAM"];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// 2. Storage Metrics
|
|
448
|
+
NSError *error = nil;
|
|
449
|
+
NSDictionary *fsAttrs = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:&error];
|
|
450
|
+
if (fsAttrs) {
|
|
451
|
+
NSNumber *freeSize = [fsAttrs objectForKey:NSFileSystemFreeSize];
|
|
452
|
+
NSNumber *totalSize = [fsAttrs objectForKey:NSFileSystemSize];
|
|
453
|
+
if (freeSize) [metrics setObject:freeSize forKey:@"freeStorage"];
|
|
454
|
+
if (totalSize) [metrics setObject:totalSize forKey:@"totalStorage"];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// 3. Battery Level & State
|
|
458
|
+
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
|
459
|
+
float batteryLevel = [UIDevice currentDevice].batteryLevel;
|
|
460
|
+
if (batteryLevel >= 0.0f) {
|
|
461
|
+
[metrics setObject:@(batteryLevel * 100.0f) forKey:@"batteryPercent"];
|
|
462
|
+
}
|
|
463
|
+
UIDeviceBatteryState bState = [UIDevice currentDevice].batteryState;
|
|
464
|
+
BOOL isCharging = (bState == UIDeviceBatteryStateCharging || bState == UIDeviceBatteryStateFull);
|
|
465
|
+
[metrics setObject:@(isCharging) forKey:@"isCharging"];
|
|
466
|
+
|
|
467
|
+
// 4. Device & Hardware Identifiers
|
|
468
|
+
[metrics setObject:[UIDevice currentDevice].model forKey:@"deviceModel"];
|
|
469
|
+
[metrics setObject:[UIDevice currentDevice].systemName forKey:@"deviceBrand"];
|
|
470
|
+
[metrics setObject:[UIDevice currentDevice].systemVersion forKey:@"osVersion"];
|
|
471
|
+
[metrics setObject:@"arm64" forKey:@"cpuAbi"];
|
|
472
|
+
|
|
473
|
+
resolve(metrics);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
RCT_EXPORT_METHOD(showFloatingButton:(NSDictionary *)options
|
|
477
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
478
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
479
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
480
|
+
UIWindow *targetWindow = nil;
|
|
481
|
+
if (@available(iOS 13.0, *)) {
|
|
482
|
+
for (UIWindowScene *scene in [UIApplication sharedApplication].connectedScenes) {
|
|
483
|
+
if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
|
|
484
|
+
for (UIWindow *w in scene.windows) {
|
|
485
|
+
if (w.isKeyWindow) {
|
|
486
|
+
targetWindow = w;
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (targetWindow) break;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (!targetWindow) {
|
|
495
|
+
targetWindow = [UIApplication sharedApplication].keyWindow;
|
|
496
|
+
if (!targetWindow && [UIApplication sharedApplication].windows.count > 0) {
|
|
497
|
+
targetWindow = [UIApplication sharedApplication].windows.firstObject;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (!targetWindow) {
|
|
502
|
+
resolve(@(NO));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
CGFloat size = 64.0;
|
|
507
|
+
if (options && options[@"size"]) {
|
|
508
|
+
size = [options[@"size"] doubleValue];
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
CGFloat initialX = targetWindow.bounds.size.width - size - 20.0;
|
|
512
|
+
CGFloat initialY = targetWindow.bounds.size.height - size - 110.0;
|
|
513
|
+
if (options && options[@"x"]) {
|
|
514
|
+
initialX = [options[@"x"] doubleValue];
|
|
515
|
+
}
|
|
516
|
+
if (options && options[@"y"]) {
|
|
517
|
+
initialY = [options[@"y"] doubleValue];
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (floatingButtonView == nil) {
|
|
521
|
+
floatingButtonView = [[InAppInspectorFloatingView alloc] initWithFrame:CGRectMake(initialX, initialY, size, size)];
|
|
522
|
+
__weak NetworkInspectorModule *weakSelf = self;
|
|
523
|
+
floatingButtonView.onTapBlock = ^{
|
|
524
|
+
NetworkInspectorModule *strongSelf = weakSelf;
|
|
525
|
+
if (strongSelf && strongSelf->hasListeners) {
|
|
526
|
+
[strongSelf sendEventWithName:@"onFloatingButtonPress" body:@{}];
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (floatingButtonView.superview == nil) {
|
|
532
|
+
[targetWindow addSubview:floatingButtonView];
|
|
533
|
+
} else {
|
|
534
|
+
[targetWindow bringSubviewToFront:floatingButtonView];
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
floatingButtonView.hidden = NO;
|
|
538
|
+
floatingButtonView.alpha = 0.0;
|
|
539
|
+
[UIView animateWithDuration:0.2 animations:^{
|
|
540
|
+
floatingButtonView.alpha = 1.0;
|
|
541
|
+
}];
|
|
542
|
+
|
|
543
|
+
resolve(@(YES));
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
RCT_EXPORT_METHOD(hideFloatingButton:(RCTPromiseResolveBlock)resolve
|
|
548
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
549
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
550
|
+
if (floatingButtonView != nil) {
|
|
551
|
+
[UIView animateWithDuration:0.15 animations:^{
|
|
552
|
+
floatingButtonView.alpha = 0.0;
|
|
553
|
+
} completion:^(BOOL finished) {
|
|
554
|
+
floatingButtonView.hidden = YES;
|
|
555
|
+
}];
|
|
556
|
+
}
|
|
557
|
+
resolve(@(YES));
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
RCT_EXPORT_METHOD(setFloatingButtonBadge:(BOOL)hasBadge
|
|
562
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
563
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
564
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
565
|
+
if (floatingButtonView != nil) {
|
|
566
|
+
[floatingButtonView updateBadgeVisible:hasBadge];
|
|
567
|
+
}
|
|
568
|
+
resolve(@(YES));
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
RCT_EXPORT_METHOD(setFloatingButtonPosition:(double)x y:(double)y
|
|
573
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
574
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
575
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
576
|
+
if (floatingButtonView != nil && floatingButtonView.superview != nil) {
|
|
577
|
+
floatingButtonView.frame = CGRectMake(x, y, floatingButtonView.frame.size.width, floatingButtonView.frame.size.height);
|
|
578
|
+
}
|
|
579
|
+
resolve(@(YES));
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
RCT_EXPORT_METHOD(startFpsMonitoring:(RCTPromiseResolveBlock)resolve
|
|
584
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
585
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
586
|
+
if (self->displayLink == nil) {
|
|
587
|
+
self->lastFpsTimestamp = 0;
|
|
588
|
+
self->frameCount = 0;
|
|
589
|
+
self->currentCalculatedFps = 60.0;
|
|
590
|
+
self->displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleFpsTick:)];
|
|
591
|
+
[self->displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
592
|
+
}
|
|
593
|
+
resolve(@(YES));
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
- (void)handleFpsTick:(CADisplayLink *)link {
|
|
598
|
+
if (self->lastFpsTimestamp == 0) {
|
|
599
|
+
self->lastFpsTimestamp = link.timestamp;
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
self->frameCount++;
|
|
603
|
+
CFTimeInterval elapsed = link.timestamp - self->lastFpsTimestamp;
|
|
604
|
+
if (elapsed >= 0.5) {
|
|
605
|
+
self->currentCalculatedFps = (double)self->frameCount / elapsed;
|
|
606
|
+
self->frameCount = 0;
|
|
607
|
+
self->lastFpsTimestamp = link.timestamp;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
RCT_EXPORT_METHOD(stopFpsMonitoring:(RCTPromiseResolveBlock)resolve
|
|
612
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
613
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
614
|
+
if (self->displayLink != nil) {
|
|
615
|
+
[self->displayLink invalidate];
|
|
616
|
+
self->displayLink = nil;
|
|
617
|
+
}
|
|
618
|
+
resolve(@(YES));
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
RCT_EXPORT_METHOD(getFpsMetrics:(RCTPromiseResolveBlock)resolve
|
|
623
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
624
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
625
|
+
[dict setObject:@(self->currentCalculatedFps > 0 ? self->currentCalculatedFps : 60.0) forKey:@"fps"];
|
|
626
|
+
[dict setObject:@(60.0) forKey:@"targetFps"];
|
|
627
|
+
resolve(dict);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
RCT_EXPORT_METHOD(getNativeStorageItem:(NSString *)key
|
|
631
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
632
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
633
|
+
NSString *prefKey = [NSString stringWithFormat:@"inapp_inspector_%@", key ?: @""];
|
|
634
|
+
NSString *val = [[NSUserDefaults standardUserDefaults] stringForKey:prefKey];
|
|
635
|
+
resolve(val ?: [NSNull null]);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
RCT_EXPORT_METHOD(setNativeStorageItem:(NSString *)key
|
|
639
|
+
value:(NSString *)value
|
|
640
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
641
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
642
|
+
NSString *prefKey = [NSString stringWithFormat:@"inapp_inspector_%@", key ?: @""];
|
|
643
|
+
if (value == nil || [value isKindOfClass:[NSNull class]]) {
|
|
644
|
+
[[NSUserDefaults standardUserDefaults] removeObjectForKey:prefKey];
|
|
645
|
+
} else {
|
|
646
|
+
[[NSUserDefaults standardUserDefaults] setObject:value forKey:prefKey];
|
|
647
|
+
}
|
|
648
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
649
|
+
resolve(@(YES));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
RCT_EXPORT_METHOD(triggerHaptic:(NSString *)style
|
|
653
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
654
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
655
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
656
|
+
if (@available(iOS 10.0, *)) {
|
|
657
|
+
NSString *s = [style lowercaseString] ?: @"light";
|
|
658
|
+
if ([s isEqualToString:@"medium"]) {
|
|
659
|
+
UIImpactFeedbackGenerator *gen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
|
|
660
|
+
[gen prepare];
|
|
661
|
+
[gen impactOccurred];
|
|
662
|
+
} else if ([s isEqualToString:@"heavy"]) {
|
|
663
|
+
UIImpactFeedbackGenerator *gen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy];
|
|
664
|
+
[gen prepare];
|
|
665
|
+
[gen impactOccurred];
|
|
666
|
+
} else if ([s isEqualToString:@"success"]) {
|
|
667
|
+
UINotificationFeedbackGenerator *gen = [[UINotificationFeedbackGenerator alloc] init];
|
|
668
|
+
[gen prepare];
|
|
669
|
+
[gen notificationOccurred:UINotificationFeedbackTypeSuccess];
|
|
670
|
+
} else if ([s isEqualToString:@"warning"]) {
|
|
671
|
+
UINotificationFeedbackGenerator *gen = [[UINotificationFeedbackGenerator alloc] init];
|
|
672
|
+
[gen prepare];
|
|
673
|
+
[gen notificationOccurred:UINotificationFeedbackTypeWarning];
|
|
674
|
+
} else if ([s isEqualToString:@"error"]) {
|
|
675
|
+
UINotificationFeedbackGenerator *gen = [[UINotificationFeedbackGenerator alloc] init];
|
|
676
|
+
[gen prepare];
|
|
677
|
+
[gen notificationOccurred:UINotificationFeedbackTypeError];
|
|
678
|
+
} else {
|
|
679
|
+
UIImpactFeedbackGenerator *gen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
|
680
|
+
[gen prepare];
|
|
681
|
+
[gen impactOccurred];
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
resolve(@(YES));
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
RCT_EXPORT_METHOD(getNativeSystemMetrics:(RCTPromiseResolveBlock)resolve
|
|
689
|
+
rejecter:(RCTPromiseRejectBlock)reject) {
|
|
690
|
+
dispatch_async(self->_metricsQueue, ^{
|
|
691
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
692
|
+
|
|
693
|
+
if (@available(iOS 11.0, *)) {
|
|
694
|
+
NSProcessInfoThermalState thermal = [[NSProcessInfo processInfo] thermalState];
|
|
695
|
+
NSString *thermalStr = @"nominal";
|
|
696
|
+
if (thermal == NSProcessInfoThermalStateFair) thermalStr = @"fair";
|
|
697
|
+
else if (thermal == NSProcessInfoThermalStateSerious) thermalStr = @"serious";
|
|
698
|
+
else if (thermal == NSProcessInfoThermalStateCritical) thermalStr = @"critical";
|
|
699
|
+
[dict setObject:thermalStr forKey:@"thermalState"];
|
|
700
|
+
} else {
|
|
701
|
+
[dict setObject:@"nominal" forKey:@"thermalState"];
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
struct mach_task_basic_info info;
|
|
705
|
+
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
|
|
706
|
+
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
|
|
707
|
+
if (kerr == KERN_SUCCESS) {
|
|
708
|
+
double ramMB = (double)info.resident_size / (1024.0 * 1024.0);
|
|
709
|
+
[dict setObject:@(ramMB) forKey:@"residentRamMb"];
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
[dict setObject:@(self->currentCalculatedFps > 0 ? self->currentCalculatedFps : 60.0) forKey:@"fps"];
|
|
713
|
+
[dict setObject:@([[NSProcessInfo processInfo] activeProcessorCount]) forKey:@"activeCpuCores"];
|
|
714
|
+
[dict setObject:@([[NSProcessInfo processInfo] physicalMemory] / (1024.0 * 1024.0)) forKey:@"totalPhysicalRamMb"];
|
|
715
|
+
|
|
716
|
+
resolve(dict);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
RCT_EXPORT_METHOD(pushNativeLogRecord:(NSString *)pageKey
|
|
721
|
+
jsonPayload:(NSString *)jsonPayload
|
|
722
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
723
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
724
|
+
if (!jsonPayload || jsonPayload.length == 0) {
|
|
725
|
+
resolve(@(NO));
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
dispatch_queue_t targetQueue = self->_networkQueue;
|
|
730
|
+
NSMutableArray *targetStore = self->_nativeNetworkLogs;
|
|
731
|
+
if ([pageKey isEqualToString:@"logs"]) {
|
|
732
|
+
targetQueue = self->_consoleQueue;
|
|
733
|
+
targetStore = self->_nativeConsoleLogs;
|
|
734
|
+
} else if ([pageKey isEqualToString:@"analytics"]) {
|
|
735
|
+
targetQueue = self->_analyticsQueue;
|
|
736
|
+
targetStore = self->_nativeAnalyticsEvents;
|
|
737
|
+
} else if ([pageKey isEqualToString:@"crash"]) {
|
|
738
|
+
targetQueue = self->_crashQueue;
|
|
739
|
+
targetStore = self->_nativeCrashRecords;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
dispatch_async(targetQueue, ^{
|
|
743
|
+
NSData *data = [jsonPayload dataUsingEncoding:NSUTF8StringEncoding];
|
|
744
|
+
NSDictionary *dict = nil;
|
|
745
|
+
if (data) {
|
|
746
|
+
dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
id itemId = dict ? dict[@"id"] : nil;
|
|
750
|
+
BOOL updated = NO;
|
|
751
|
+
|
|
752
|
+
if (itemId != nil) {
|
|
753
|
+
NSString *idPattern = [NSString stringWithFormat:@"\"id\":%@", itemId];
|
|
754
|
+
NSString *idStrPattern = [NSString stringWithFormat:@"\"id\":\"%@\"", itemId];
|
|
755
|
+
for (NSUInteger i = 0; i < targetStore.count; i++) {
|
|
756
|
+
NSString *existingJson = targetStore[i];
|
|
757
|
+
if ([existingJson containsString:idPattern] || [existingJson containsString:idStrPattern]) {
|
|
758
|
+
[targetStore replaceObjectAtIndex:i withObject:jsonPayload];
|
|
759
|
+
updated = YES;
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (!updated) {
|
|
766
|
+
[targetStore insertObject:jsonPayload atIndex:0];
|
|
767
|
+
if (targetStore.count > 2000) {
|
|
768
|
+
[targetStore removeLastObject];
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
resolve(@(YES));
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
RCT_EXPORT_METHOD(getNativeCachedPage:(NSString *)pageKey
|
|
776
|
+
offset:(NSInteger)offset
|
|
777
|
+
limit:(NSInteger)limit
|
|
778
|
+
query:(NSString *)query
|
|
779
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
780
|
+
reject:(RCTPromiseRejectBlock)reject) {
|
|
781
|
+
dispatch_queue_t targetQueue = self->_networkQueue;
|
|
782
|
+
NSMutableArray *targetStore = self->_nativeNetworkLogs;
|
|
783
|
+
if ([pageKey isEqualToString:@"logs"]) {
|
|
784
|
+
targetQueue = self->_consoleQueue;
|
|
785
|
+
targetStore = self->_nativeConsoleLogs;
|
|
786
|
+
} else if ([pageKey isEqualToString:@"analytics"]) {
|
|
787
|
+
targetQueue = self->_analyticsQueue;
|
|
788
|
+
targetStore = self->_nativeAnalyticsEvents;
|
|
789
|
+
} else if ([pageKey isEqualToString:@"crash"]) {
|
|
790
|
+
targetQueue = self->_crashQueue;
|
|
791
|
+
targetStore = self->_nativeCrashRecords;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
dispatch_async(targetQueue, ^{
|
|
795
|
+
NSMutableArray *results = [NSMutableArray array];
|
|
796
|
+
NSString *cleanQuery = query ? [query stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].lowercaseString : @"";
|
|
797
|
+
|
|
798
|
+
NSInteger startIndex = MAX(0, offset);
|
|
799
|
+
NSInteger itemsCollected = 0;
|
|
800
|
+
NSInteger actualLimit = limit > 0 ? limit : 50;
|
|
801
|
+
|
|
802
|
+
for (NSInteger i = startIndex; i < targetStore.count && itemsCollected < actualLimit; i++) {
|
|
803
|
+
NSString *itemJson = targetStore[i];
|
|
804
|
+
if (cleanQuery.length > 0) {
|
|
805
|
+
if ([itemJson.lowercaseString containsString:cleanQuery]) {
|
|
806
|
+
[results addObject:itemJson];
|
|
807
|
+
itemsCollected++;
|
|
808
|
+
}
|
|
809
|
+
} else {
|
|
810
|
+
[results addObject:itemJson];
|
|
811
|
+
itemsCollected++;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
NSError *error = nil;
|
|
816
|
+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{
|
|
817
|
+
@"pageKey": pageKey ?: @"apis",
|
|
818
|
+
@"total": @(targetStore.count),
|
|
819
|
+
@"offset": @(offset),
|
|
820
|
+
@"items": results
|
|
821
|
+
} options:0 error:&error];
|
|
822
|
+
|
|
823
|
+
if (error || !jsonData) {
|
|
824
|
+
resolve(@"{\"items\":[],\"total\":0}");
|
|
825
|
+
} else {
|
|
826
|
+
NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
|
827
|
+
resolve(jsonStr);
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
833
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
834
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
835
|
+
{
|
|
836
|
+
return std::make_shared<facebook::react::NativeNetworkInspectorSpecJSI>(params);
|
|
837
|
+
}
|
|
838
|
+
#endif
|
|
839
|
+
|
|
125
840
|
@end
|