@ansight/react-native 1.3.0-preview.3 → 1.3.0-preview.5
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 +15 -3
- package/android/build.gradle +2 -2
- package/android/src/main/kotlin/ai/ansight/reactnative/AnsightReactNativeModule.kt +60 -8
- package/index.d.ts +32 -2
- package/index.js +61 -0
- package/ios/AnsightReactNative.swift +55 -6
- package/ios/AnsightReactNativeModule.m +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,8 +77,8 @@ bundle; its API requires the native Ansight module.
|
|
|
77
77
|
|
|
78
78
|
This package version expects matching native SDK packages:
|
|
79
79
|
|
|
80
|
-
- CocoaPods: `Ansight`, `AnsightObjC` version `1.3.0-preview.
|
|
81
|
-
- Maven: `ai.ansight:ansight-android:1.3.0-preview.
|
|
80
|
+
- CocoaPods: `Ansight`, `AnsightObjC` version `1.3.0-preview.5`
|
|
81
|
+
- Maven: `ai.ansight:ansight-android:1.3.0-preview.5`
|
|
82
82
|
|
|
83
83
|
## Quickstart
|
|
84
84
|
|
|
@@ -136,10 +136,12 @@ The TypeScript `AnsightOptions` surface mirrors Android `AnsightOptions`, iOS
|
|
|
136
136
|
| `retentionPeriodSeconds` | Local metric/event retention window. |
|
|
137
137
|
| `enableFramesPerSecond` | Enables native FPS sampling. |
|
|
138
138
|
| `enableBatteryLevel` | Enables battery sampling where available. |
|
|
139
|
+
| `enableOpenFileHandleTracking` | Enables native process open-file-handle sampling. Disabled by default. |
|
|
140
|
+
| `enableJniReferenceCountTracking` | Enables JNI reference-count tracking where the runtime can supply it. Disabled by default. |
|
|
139
141
|
| `defaultMemoryChannels` | Selects built-in memory channels. Prefer `managedHeap`, `nativeHeap`, `residentSetSize`, and `physicalFootprint`; `javaHeap` and `rss` are accepted as Android/RN compatibility aliases. |
|
|
140
142
|
| `reactNativeMemory` | Controls native React Native runtime memory channels. Enabled by default; set to `false` to disable, or use `{ jsHeapUsed, jsHeapTotal }`. |
|
|
141
143
|
| `additionalChannels` | Registers custom metric channels. |
|
|
142
|
-
| `sessionJpegCapture` | Object to enable/configure capture, or `false` to disable. Supports `captureGpuBackedSurfaces`; on iOS it defaults to `true` so Metal, SceneKit, and similar GPU-backed views are included. |
|
|
144
|
+
| `sessionJpegCapture` | Object to enable/configure capture, or `false` to disable. `mode` accepts `screenshotOnly`, `screenshotAndVisualTree`, or `screenshotWithVisualTreeOnTouch`. Supports `captureGpuBackedSurfaces`; on iOS it defaults to `true` so Metal, SceneKit, and similar GPU-backed views are included. |
|
|
143
145
|
| `touchCapture` | Object to enable/configure capture, or `false` to disable. |
|
|
144
146
|
| `lifecycleCapture` | Native lifecycle and screen-view capture options. |
|
|
145
147
|
| `toolGuard` | `"disabled"`, `"readOnly"`, `"readWrite"`, or `"fullAccess"`. |
|
|
@@ -150,6 +152,11 @@ The TypeScript `AnsightOptions` surface mirrors Android `AnsightOptions`, iOS
|
|
|
150
152
|
| `remoteTools` | Native visual tree, file, database, preferences, reflection, and secure-storage tool options. |
|
|
151
153
|
| `lifecycle` | JS AppState tracking toggle. Defaults to true. |
|
|
152
154
|
|
|
155
|
+
Use `withOpenFileHandleTracking()` and `withJniReferenceCountTracking()` to
|
|
156
|
+
opt in through the builder. Matching `without...` methods disable the channels
|
|
157
|
+
again. Open handles are sampled by the native Android/iOS runtime. JNI counts
|
|
158
|
+
are available on Android only when the host integration can supply them.
|
|
159
|
+
|
|
153
160
|
Cellular host connections are disabled by default. The restriction applies to
|
|
154
161
|
enrollment and reconnect requests. Opt in only for a trusted development host
|
|
155
162
|
or personal hotspot:
|
|
@@ -175,6 +182,7 @@ await Ansight.initializeAndActivate({
|
|
|
175
182
|
quality: 60,
|
|
176
183
|
maxWidth: 480,
|
|
177
184
|
captureGpuBackedSurfaces: true,
|
|
185
|
+
mode: "screenshotWithVisualTreeOnTouch",
|
|
178
186
|
},
|
|
179
187
|
touchCapture: {
|
|
180
188
|
captureMoveEvents: true,
|
|
@@ -192,6 +200,10 @@ await Ansight.initializeAndActivate({
|
|
|
192
200
|
});
|
|
193
201
|
```
|
|
194
202
|
|
|
203
|
+
The touch mode captures native visual trees at gesture start, every 250 ms
|
|
204
|
+
throughout the gesture, and at the final up or cancel. It requires native touch
|
|
205
|
+
capture and visual-tree tools/providers to remain enabled.
|
|
206
|
+
|
|
195
207
|
On iOS, `captureGpuBackedSurfaces` defaults to `true` so Metal, SceneKit, and
|
|
196
208
|
similar GPU-backed views are included. Set it to `false` to use a lower-overhead
|
|
197
209
|
capture path when those surfaces are not needed.
|
package/android/build.gradle
CHANGED
|
@@ -67,6 +67,6 @@ repositories {
|
|
|
67
67
|
dependencies {
|
|
68
68
|
implementation("com.facebook.react:react-android")
|
|
69
69
|
def ansightAndroidVersion =
|
|
70
|
-
findProperty("ansightAndroidVersion") ?: "1.3.0-preview.
|
|
71
|
-
implementation("ai.ansight:ansight-android:1.3.0-preview.
|
|
70
|
+
findProperty("ansightAndroidVersion") ?: "1.3.0-preview.5"
|
|
71
|
+
implementation("ai.ansight:ansight-android:1.3.0-preview.5")
|
|
72
72
|
}
|
|
@@ -6,6 +6,7 @@ import ai.ansight.runtime.AndroidToolExecutionContext
|
|
|
6
6
|
import ai.ansight.runtime.AndroidToolResult
|
|
7
7
|
import ai.ansight.runtime.AnsightChannel
|
|
8
8
|
import ai.ansight.runtime.AnsightChannels
|
|
9
|
+
import ai.ansight.runtime.AnsightCrashCaptureOptions
|
|
9
10
|
import ai.ansight.runtime.AnsightHostAutoProbeOptions
|
|
10
11
|
import ai.ansight.runtime.AnsightHostConnectionOptions
|
|
11
12
|
import ai.ansight.runtime.AnsightLogCallback
|
|
@@ -225,6 +226,21 @@ class AnsightReactNativeModule(
|
|
|
225
226
|
}.resolve(promise)
|
|
226
227
|
}
|
|
227
228
|
|
|
229
|
+
@ReactMethod
|
|
230
|
+
fun recordCrashCandidate(input: ReadableMap, promise: Promise) {
|
|
231
|
+
runCatching {
|
|
232
|
+
val candidateId = AnsightRuntime.recordCrashCandidate(
|
|
233
|
+
runtime = input.stringValue("runtime") ?: "react-native-javascript",
|
|
234
|
+
kind = input.stringValue("kind") ?: "unhandled_javascript_error",
|
|
235
|
+
message = input.stringValue("message"),
|
|
236
|
+
stack = input.stringValue("stack"),
|
|
237
|
+
fatal = input.booleanValue("fatal", false),
|
|
238
|
+
metadataJson = input.stringValue("metadata"),
|
|
239
|
+
)
|
|
240
|
+
Arguments.createMap().apply { putString("candidateId", candidateId) }
|
|
241
|
+
}.resolve(promise)
|
|
242
|
+
}
|
|
243
|
+
|
|
228
244
|
@ReactMethod
|
|
229
245
|
fun screenViewed(name: String, details: ReadableMap?, promise: Promise) {
|
|
230
246
|
runCatching {
|
|
@@ -693,6 +709,22 @@ class AnsightReactNativeModule(
|
|
|
693
709
|
if (map.hasBoolean("enableBatteryLevel")) {
|
|
694
710
|
options = options.copy(enableBatteryLevel = map.booleanValue("enableBatteryLevel", options.enableBatteryLevel))
|
|
695
711
|
}
|
|
712
|
+
if (map.hasBoolean("enableOpenFileHandleTracking")) {
|
|
713
|
+
options = options.copy(
|
|
714
|
+
enableOpenFileHandleTracking = map.booleanValue(
|
|
715
|
+
"enableOpenFileHandleTracking",
|
|
716
|
+
options.enableOpenFileHandleTracking,
|
|
717
|
+
),
|
|
718
|
+
)
|
|
719
|
+
}
|
|
720
|
+
if (map.hasBoolean("enableJniReferenceCountTracking")) {
|
|
721
|
+
options = options.copy(
|
|
722
|
+
enableJniReferenceCountTracking = map.booleanValue(
|
|
723
|
+
"enableJniReferenceCountTracking",
|
|
724
|
+
options.enableJniReferenceCountTracking,
|
|
725
|
+
),
|
|
726
|
+
)
|
|
727
|
+
}
|
|
696
728
|
if (map.hasMap("defaultMemoryChannels")) {
|
|
697
729
|
val memory = map.getMapOrNull("defaultMemoryChannels")
|
|
698
730
|
val managedHeap = if (memory.hasBoolean("managedHeap")) {
|
|
@@ -768,6 +800,24 @@ class AnsightReactNativeModule(
|
|
|
768
800
|
},
|
|
769
801
|
)
|
|
770
802
|
}
|
|
803
|
+
if (map.hasKey("crashCapture")) {
|
|
804
|
+
options = options.copy(
|
|
805
|
+
crashCapture = if (map.isFalse("crashCapture")) {
|
|
806
|
+
options.crashCapture.copy(enabled = false)
|
|
807
|
+
} else {
|
|
808
|
+
val crash = map.getMapOrNull("crashCapture")
|
|
809
|
+
AnsightCrashCaptureOptions(
|
|
810
|
+
enabled = crash.booleanValue("enabled", true),
|
|
811
|
+
studioHandoffEnabled = crash.booleanValue("studioHandoffEnabled", true),
|
|
812
|
+
offlineCaptureAttachmentEnabled = crash.booleanValue("offlineCaptureAttachmentEnabled", true),
|
|
813
|
+
maximumPendingReports = crash.intValue("maximumPendingReports", 8),
|
|
814
|
+
retentionDays = crash.intValue("retentionDays", 7),
|
|
815
|
+
maximumBreadcrumbs = crash.intValue("maximumBreadcrumbs", 64),
|
|
816
|
+
maximumTraceBytes = crash.intValue("maximumTraceBytes", 1_048_576),
|
|
817
|
+
)
|
|
818
|
+
},
|
|
819
|
+
)
|
|
820
|
+
}
|
|
771
821
|
if (map.hasString("toolGuard")) {
|
|
772
822
|
options = options.copy(toolGuard = toolGuard(map.stringValue("toolGuard")))
|
|
773
823
|
}
|
|
@@ -935,10 +985,10 @@ class AnsightReactNativeModule(
|
|
|
935
985
|
}
|
|
936
986
|
|
|
937
987
|
private fun sessionJpegCaptureMode(value: String?): AnsightSessionJpegCaptureMode =
|
|
938
|
-
|
|
939
|
-
AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree
|
|
940
|
-
|
|
941
|
-
AnsightSessionJpegCaptureMode.ScreenshotOnly
|
|
988
|
+
when (value) {
|
|
989
|
+
"screenshotAndVisualTree" -> AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree
|
|
990
|
+
"screenshotWithVisualTreeOnTouch" -> AnsightSessionJpegCaptureMode.ScreenshotWithVisualTreeOnTouch
|
|
991
|
+
else -> AnsightSessionJpegCaptureMode.ScreenshotOnly
|
|
942
992
|
}
|
|
943
993
|
|
|
944
994
|
private fun toolDefinition(map: ReadableMap): ToolDefinition =
|
|
@@ -1111,6 +1161,8 @@ class AnsightReactNativeModule(
|
|
|
1111
1161
|
putInt("retentionPeriodSeconds", options.retentionPeriodSeconds)
|
|
1112
1162
|
putBoolean("enableFramesPerSecond", options.enableFramesPerSecond)
|
|
1113
1163
|
putBoolean("enableBatteryLevel", options.enableBatteryLevel)
|
|
1164
|
+
putBoolean("enableOpenFileHandleTracking", options.enableOpenFileHandleTracking)
|
|
1165
|
+
putBoolean("enableJniReferenceCountTracking", options.enableJniReferenceCountTracking)
|
|
1114
1166
|
putMap("defaultMemoryChannels", mapOf(
|
|
1115
1167
|
"managedHeap" to options.defaultMemoryChannels.javaHeap,
|
|
1116
1168
|
"javaHeap" to options.defaultMemoryChannels.javaHeap,
|
|
@@ -1127,10 +1179,10 @@ class AnsightReactNativeModule(
|
|
|
1127
1179
|
"quality" to capture.quality,
|
|
1128
1180
|
"maxWidth" to capture.maxWidth,
|
|
1129
1181
|
"captureGpuBackedSurfaces" to capture.captureGpuBackedSurfaces,
|
|
1130
|
-
"mode" to
|
|
1131
|
-
"screenshotAndVisualTree"
|
|
1132
|
-
|
|
1133
|
-
"screenshotOnly"
|
|
1182
|
+
"mode" to when (capture.mode) {
|
|
1183
|
+
AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree -> "screenshotAndVisualTree"
|
|
1184
|
+
AnsightSessionJpegCaptureMode.ScreenshotWithVisualTreeOnTouch -> "screenshotWithVisualTreeOnTouch"
|
|
1185
|
+
else -> "screenshotOnly"
|
|
1134
1186
|
},
|
|
1135
1187
|
).toWritableMap())
|
|
1136
1188
|
} ?: putNull("sessionJpegCapture")
|
package/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface AnsightSessionJpegCaptureOptions {
|
|
|
37
37
|
quality?: number;
|
|
38
38
|
maxWidth?: number;
|
|
39
39
|
captureGpuBackedSurfaces?: boolean;
|
|
40
|
-
mode?: "screenshotOnly" | "screenshotAndVisualTree";
|
|
40
|
+
mode?: "screenshotOnly" | "screenshotAndVisualTree" | "screenshotWithVisualTreeOnTouch";
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export interface AnsightTouchCaptureOptions {
|
|
@@ -110,6 +110,8 @@ export interface AnsightOptions {
|
|
|
110
110
|
retentionPeriodSeconds?: number;
|
|
111
111
|
enableFramesPerSecond?: boolean;
|
|
112
112
|
enableBatteryLevel?: boolean;
|
|
113
|
+
enableOpenFileHandleTracking?: boolean;
|
|
114
|
+
enableJniReferenceCountTracking?: boolean;
|
|
113
115
|
defaultMemoryChannels?: {
|
|
114
116
|
managedHeap?: boolean;
|
|
115
117
|
physicalFootprint?: boolean;
|
|
@@ -121,6 +123,7 @@ export interface AnsightOptions {
|
|
|
121
123
|
reactNativeMemory?: false | AnsightReactNativeMemoryOptions;
|
|
122
124
|
sessionJpegCapture?: false | AnsightSessionJpegCaptureOptions;
|
|
123
125
|
touchCapture?: false | AnsightTouchCaptureOptions;
|
|
126
|
+
crashCapture?: false | AnsightCrashCaptureOptions;
|
|
124
127
|
lifecycleCapture?: {
|
|
125
128
|
enabled?: boolean;
|
|
126
129
|
captureAppLifecycle?: boolean;
|
|
@@ -153,6 +156,25 @@ export interface AnsightOptions {
|
|
|
153
156
|
lifecycle?: boolean;
|
|
154
157
|
}
|
|
155
158
|
|
|
159
|
+
export interface AnsightCrashCaptureOptions {
|
|
160
|
+
enabled?: boolean;
|
|
161
|
+
studioHandoffEnabled?: boolean;
|
|
162
|
+
offlineCaptureAttachmentEnabled?: boolean;
|
|
163
|
+
maximumPendingReports?: number;
|
|
164
|
+
retentionDays?: number;
|
|
165
|
+
maximumBreadcrumbs?: number;
|
|
166
|
+
maximumTraceBytes?: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface AnsightCrashCandidate {
|
|
170
|
+
runtime?: string;
|
|
171
|
+
kind?: string;
|
|
172
|
+
message?: string;
|
|
173
|
+
stack?: string;
|
|
174
|
+
fatal?: boolean;
|
|
175
|
+
metadata?: string | Record<string, string>;
|
|
176
|
+
}
|
|
177
|
+
|
|
156
178
|
export interface AnsightOperationResult {
|
|
157
179
|
success: boolean;
|
|
158
180
|
message: string;
|
|
@@ -251,6 +273,10 @@ export class AnsightOptionsBuilder {
|
|
|
251
273
|
withoutFramesPerSecond(): this;
|
|
252
274
|
withBatteryLevel(): this;
|
|
253
275
|
withoutBatteryLevel(): this;
|
|
276
|
+
withOpenFileHandleTracking(): this;
|
|
277
|
+
withoutOpenFileHandleTracking(): this;
|
|
278
|
+
withJniReferenceCountTracking(): this;
|
|
279
|
+
withoutJniReferenceCountTracking(): this;
|
|
254
280
|
withRetentionPeriodSeconds(retentionPeriodSeconds: number): this;
|
|
255
281
|
withAdditionalChannels(additionalChannels: AnsightChannel[]): this;
|
|
256
282
|
addAdditionalChannel(additionalChannel: AnsightChannel): this;
|
|
@@ -264,11 +290,13 @@ export class AnsightOptionsBuilder {
|
|
|
264
290
|
quality?: number,
|
|
265
291
|
maxWidth?: number | null,
|
|
266
292
|
captureGpuBackedSurfaces?: boolean,
|
|
267
|
-
mode?: "screenshotOnly" | "screenshotAndVisualTree"
|
|
293
|
+
mode?: "screenshotOnly" | "screenshotAndVisualTree" | "screenshotWithVisualTreeOnTouch"
|
|
268
294
|
): this;
|
|
269
295
|
withoutSessionJpegCapture(): this;
|
|
270
296
|
withTouchCapture(touchCapture?: AnsightTouchCaptureOptions): this;
|
|
271
297
|
withoutTouchCapture(): this;
|
|
298
|
+
withCrashCapture(crashCapture?: AnsightCrashCaptureOptions): this;
|
|
299
|
+
withoutCrashCapture(): this;
|
|
272
300
|
withLifecycleCapture(lifecycleCapture?: NonNullable<AnsightOptions["lifecycleCapture"]>): this;
|
|
273
301
|
withToolGuard(toolGuard: NonNullable<AnsightOptions["toolGuard"]>): this;
|
|
274
302
|
withToolsDisabled(): this;
|
|
@@ -512,6 +540,7 @@ export function metric(value: number, channel?: number): Promise<AnsightDebugSna
|
|
|
512
540
|
export function recordMetric(value: number, channel?: number): Promise<AnsightDebugSnapshot>;
|
|
513
541
|
export function event(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
|
|
514
542
|
export function recordEvent(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
|
|
543
|
+
export function recordCrashCandidate(input?: AnsightCrashCandidate): Promise<{ candidateId?: string }>;
|
|
515
544
|
export function screenViewed(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
|
|
516
545
|
export function trackRoute(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
|
|
517
546
|
export function setAppLifecycleState(state: AnsightLifecycleState): Promise<AnsightDebugSnapshot>;
|
|
@@ -585,6 +614,7 @@ declare const Ansight: {
|
|
|
585
614
|
recordMetric: typeof recordMetric;
|
|
586
615
|
event: typeof event;
|
|
587
616
|
recordEvent: typeof recordEvent;
|
|
617
|
+
recordCrashCandidate: typeof recordCrashCandidate;
|
|
588
618
|
screenViewed: typeof screenViewed;
|
|
589
619
|
trackRoute: typeof trackRoute;
|
|
590
620
|
setAppLifecycleState: typeof setAppLifecycleState;
|
package/index.js
CHANGED
|
@@ -61,6 +61,9 @@ function cloneOptions(options = {}) {
|
|
|
61
61
|
if (options.touchCapture && typeof options.touchCapture === "object") {
|
|
62
62
|
clone.touchCapture = { ...options.touchCapture };
|
|
63
63
|
}
|
|
64
|
+
if (options.crashCapture && typeof options.crashCapture === "object") {
|
|
65
|
+
clone.crashCapture = { ...options.crashCapture };
|
|
66
|
+
}
|
|
64
67
|
if (options.lifecycleCapture) {
|
|
65
68
|
clone.lifecycleCapture = { ...options.lifecycleCapture };
|
|
66
69
|
}
|
|
@@ -157,6 +160,8 @@ class AnsightOptionsBuilder {
|
|
|
157
160
|
retentionPeriodSeconds: 120,
|
|
158
161
|
enableFramesPerSecond: true,
|
|
159
162
|
enableBatteryLevel: false,
|
|
163
|
+
enableOpenFileHandleTracking: false,
|
|
164
|
+
enableJniReferenceCountTracking: false,
|
|
160
165
|
sessionJpegCapture: {
|
|
161
166
|
intervalMilliseconds: 2000,
|
|
162
167
|
quality: 60,
|
|
@@ -209,6 +214,26 @@ class AnsightOptionsBuilder {
|
|
|
209
214
|
return this;
|
|
210
215
|
}
|
|
211
216
|
|
|
217
|
+
withOpenFileHandleTracking() {
|
|
218
|
+
this._options.enableOpenFileHandleTracking = true;
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
withoutOpenFileHandleTracking() {
|
|
223
|
+
this._options.enableOpenFileHandleTracking = false;
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
withJniReferenceCountTracking() {
|
|
228
|
+
this._options.enableJniReferenceCountTracking = true;
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
withoutJniReferenceCountTracking() {
|
|
233
|
+
this._options.enableJniReferenceCountTracking = false;
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
|
|
212
237
|
withRetentionPeriodSeconds(retentionPeriodSeconds) {
|
|
213
238
|
this._options.retentionPeriodSeconds = retentionPeriodSeconds;
|
|
214
239
|
return this;
|
|
@@ -297,6 +322,16 @@ class AnsightOptionsBuilder {
|
|
|
297
322
|
return this;
|
|
298
323
|
}
|
|
299
324
|
|
|
325
|
+
withCrashCapture(crashCapture = {}) {
|
|
326
|
+
this._options.crashCapture = { ...crashCapture, enabled: true };
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
withoutCrashCapture() {
|
|
331
|
+
this._options.crashCapture = false;
|
|
332
|
+
return this;
|
|
333
|
+
}
|
|
334
|
+
|
|
300
335
|
withLifecycleCapture(lifecycleCapture = {}) {
|
|
301
336
|
this._options.lifecycleCapture = { ...lifecycleCapture };
|
|
302
337
|
return this;
|
|
@@ -2218,6 +2253,14 @@ function installErrorHandlers(options = {}) {
|
|
|
2218
2253
|
|
|
2219
2254
|
if (global.ErrorUtils && global.ErrorUtils.setGlobalHandler) {
|
|
2220
2255
|
global.ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
2256
|
+
nativeModule.recordCrashCandidate({
|
|
2257
|
+
runtime: "react-native-javascript",
|
|
2258
|
+
kind: "unhandled_javascript_error",
|
|
2259
|
+
message: error && error.message,
|
|
2260
|
+
stack: error && error.stack,
|
|
2261
|
+
fatal: !!isFatal,
|
|
2262
|
+
metadata: JSON.stringify({ name: error && error.name }),
|
|
2263
|
+
}).catch(() => {});
|
|
2221
2264
|
nativeModule.recordEvent({
|
|
2222
2265
|
label: error && error.message ? error.message : "Unhandled JavaScript error",
|
|
2223
2266
|
type: "Exception",
|
|
@@ -2240,6 +2283,13 @@ function installErrorHandlers(options = {}) {
|
|
|
2240
2283
|
global.__ansightUnhandledRejectionTrackingInstalled = true;
|
|
2241
2284
|
global.addEventListener("unhandledrejection", (event) => {
|
|
2242
2285
|
const reason = event && event.reason;
|
|
2286
|
+
nativeModule.recordCrashCandidate({
|
|
2287
|
+
runtime: "react-native-javascript",
|
|
2288
|
+
kind: "unhandled_promise_rejection",
|
|
2289
|
+
message: reason && reason.message ? reason.message : String(reason),
|
|
2290
|
+
stack: reason && reason.stack,
|
|
2291
|
+
fatal: false,
|
|
2292
|
+
}).catch(() => {});
|
|
2243
2293
|
nativeModule.recordEvent({
|
|
2244
2294
|
label: reason && reason.message ? reason.message : "Unhandled JavaScript promise rejection",
|
|
2245
2295
|
type: "Exception",
|
|
@@ -2334,6 +2384,16 @@ function recordEvent(input) {
|
|
|
2334
2384
|
return nativeModule.recordEvent(input || {});
|
|
2335
2385
|
}
|
|
2336
2386
|
|
|
2387
|
+
function recordCrashCandidate(input = {}) {
|
|
2388
|
+
const metadata = input.metadata && typeof input.metadata === "object"
|
|
2389
|
+
? JSON.stringify(input.metadata)
|
|
2390
|
+
: input.metadata;
|
|
2391
|
+
return nativeModule.recordCrashCandidate({
|
|
2392
|
+
...input,
|
|
2393
|
+
metadata,
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2337
2397
|
function screenViewed(name, details) {
|
|
2338
2398
|
return nativeModule.screenViewed(name, details || {});
|
|
2339
2399
|
}
|
|
@@ -2376,6 +2436,7 @@ const Ansight = {
|
|
|
2376
2436
|
recordMetric: (value, channel = 255) => nativeModule.recordMetric(value, channel),
|
|
2377
2437
|
event: recordEvent,
|
|
2378
2438
|
recordEvent,
|
|
2439
|
+
recordCrashCandidate,
|
|
2379
2440
|
screenViewed,
|
|
2380
2441
|
trackRoute,
|
|
2381
2442
|
setAppLifecycleState: (state) => nativeModule.setAppLifecycleState(state),
|
|
@@ -292,6 +292,31 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
@objc(recordCrashCandidate:resolver:rejecter:)
|
|
296
|
+
func recordCrashCandidate(
|
|
297
|
+
_ input: NSDictionary,
|
|
298
|
+
resolver resolve: RCTPromiseResolveBlock,
|
|
299
|
+
rejecter reject: RCTPromiseRejectBlock
|
|
300
|
+
) {
|
|
301
|
+
let metadata: [String: String]
|
|
302
|
+
if let metadataJson = stringValue(input, "metadata"),
|
|
303
|
+
let data = metadataJson.data(using: .utf8),
|
|
304
|
+
let decoded = try? JSONDecoder().decode([String: String].self, from: data) {
|
|
305
|
+
metadata = decoded
|
|
306
|
+
} else {
|
|
307
|
+
metadata = [:]
|
|
308
|
+
}
|
|
309
|
+
let candidateId = AnsightRuntime.shared.recordCrashCandidate(
|
|
310
|
+
runtime: stringValue(input, "runtime") ?? "react-native-javascript",
|
|
311
|
+
kind: stringValue(input, "kind") ?? "unhandled_javascript_error",
|
|
312
|
+
message: stringValue(input, "message"),
|
|
313
|
+
stack: stringValue(input, "stack"),
|
|
314
|
+
fatal: boolValue(input, "fatal", defaultValue: false),
|
|
315
|
+
metadata: metadata
|
|
316
|
+
)
|
|
317
|
+
resolve(candidateId.map { ["candidateId": $0] } ?? [:])
|
|
318
|
+
}
|
|
319
|
+
|
|
295
320
|
@objc(screenViewed:details:resolver:rejecter:)
|
|
296
321
|
func screenViewed(
|
|
297
322
|
_ name: NSString,
|
|
@@ -895,6 +920,13 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
895
920
|
if hasBool(dictionary, "enableBatteryLevel") {
|
|
896
921
|
options.enableBatteryLevel = boolValue(dictionary, "enableBatteryLevel", defaultValue: options.enableBatteryLevel)
|
|
897
922
|
}
|
|
923
|
+
if hasBool(dictionary, "enableOpenFileHandleTracking") {
|
|
924
|
+
options.enableOpenFileHandleTracking = boolValue(
|
|
925
|
+
dictionary,
|
|
926
|
+
"enableOpenFileHandleTracking",
|
|
927
|
+
defaultValue: options.enableOpenFileHandleTracking
|
|
928
|
+
)
|
|
929
|
+
}
|
|
898
930
|
if let memory = dictionary?["defaultMemoryChannels"] as? NSDictionary {
|
|
899
931
|
var channels: DefaultMemoryChannels = []
|
|
900
932
|
if boolValue(memory, "managedHeap", defaultValue: boolValue(memory, "javaHeap", defaultValue: false)) {
|
|
@@ -942,9 +974,9 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
942
974
|
"captureGpuBackedSurfaces",
|
|
943
975
|
defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureGpuBackedSurfaces
|
|
944
976
|
),
|
|
945
|
-
mode:
|
|
946
|
-
|
|
947
|
-
|
|
977
|
+
mode: AnsightSessionJpegCaptureMode(
|
|
978
|
+
rawValue: stringValue(jpeg, "mode") ?? ""
|
|
979
|
+
) ?? .screenshotOnly
|
|
948
980
|
)
|
|
949
981
|
}
|
|
950
982
|
}
|
|
@@ -960,6 +992,21 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
960
992
|
)
|
|
961
993
|
}
|
|
962
994
|
}
|
|
995
|
+
if let raw = dictionary?["crashCapture"] {
|
|
996
|
+
if (raw as? Bool) == false {
|
|
997
|
+
options.crashCapture.enabled = false
|
|
998
|
+
} else if let crash = raw as? NSDictionary {
|
|
999
|
+
options.crashCapture = AnsightCrashCaptureOptions(
|
|
1000
|
+
enabled: boolValue(crash, "enabled", defaultValue: true),
|
|
1001
|
+
studioHandoffEnabled: boolValue(crash, "studioHandoffEnabled", defaultValue: true),
|
|
1002
|
+
offlineCaptureAttachmentEnabled: boolValue(crash, "offlineCaptureAttachmentEnabled", defaultValue: true),
|
|
1003
|
+
maximumPendingReports: intValue(crash, "maximumPendingReports", defaultValue: 8),
|
|
1004
|
+
retentionDays: intValue(crash, "retentionDays", defaultValue: 7),
|
|
1005
|
+
maximumBreadcrumbs: intValue(crash, "maximumBreadcrumbs", defaultValue: 64),
|
|
1006
|
+
maximumTraceBytes: intValue(crash, "maximumTraceBytes", defaultValue: 1_048_576)
|
|
1007
|
+
)
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
963
1010
|
if let lifecycle = dictionary?["lifecycleCapture"] as? NSDictionary {
|
|
964
1011
|
options.lifecycleCapture = AnsightLifecycleCaptureOptions(
|
|
965
1012
|
enabled: boolValue(lifecycle, "enabled", defaultValue: options.lifecycleCapture.enabled),
|
|
@@ -1271,9 +1318,9 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
1271
1318
|
"captureGpuBackedSurfaces",
|
|
1272
1319
|
defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureGpuBackedSurfaces
|
|
1273
1320
|
),
|
|
1274
|
-
mode:
|
|
1275
|
-
|
|
1276
|
-
|
|
1321
|
+
mode: AnsightSessionJpegCaptureMode(
|
|
1322
|
+
rawValue: stringValue(dictionary, "mode") ?? ""
|
|
1323
|
+
) ?? .screenshotOnly
|
|
1277
1324
|
)
|
|
1278
1325
|
}
|
|
1279
1326
|
|
|
@@ -1283,6 +1330,8 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
1283
1330
|
"retentionPeriodSeconds": options.retentionPeriodSeconds,
|
|
1284
1331
|
"enableFramesPerSecond": options.enableFramesPerSecond,
|
|
1285
1332
|
"enableBatteryLevel": options.enableBatteryLevel,
|
|
1333
|
+
"enableOpenFileHandleTracking": options.enableOpenFileHandleTracking,
|
|
1334
|
+
"enableJniReferenceCountTracking": false,
|
|
1286
1335
|
"defaultMemoryChannels": [
|
|
1287
1336
|
"managedHeap": options.defaultMemoryChannels.contains(.managedHeap),
|
|
1288
1337
|
"javaHeap": options.defaultMemoryChannels.contains(.managedHeap),
|
|
@@ -33,6 +33,10 @@ RCT_EXTERN_METHOD(recordEvent:(NSDictionary *)input
|
|
|
33
33
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
34
34
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
35
35
|
|
|
36
|
+
RCT_EXTERN_METHOD(recordCrashCandidate:(NSDictionary *)input
|
|
37
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
38
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
39
|
+
|
|
36
40
|
RCT_EXTERN_METHOD(screenViewed:(NSString *)name
|
|
37
41
|
details:(NSDictionary *)details
|
|
38
42
|
resolver:(RCTPromiseResolveBlock)resolve
|