@ansight/react-native 1.3.0-preview.3 → 1.3.0-preview.8
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 +69 -8
- package/index.d.ts +34 -2
- package/index.js +63 -0
- package/ios/AnsightReactNative.swift +66 -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.8`
|
|
81
|
+
- Maven: `ai.ansight:ansight-android:1.3.0-preview.8`
|
|
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.8"
|
|
71
|
+
implementation("ai.ansight:ansight-android:1.3.0-preview.8")
|
|
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")) {
|
|
@@ -751,6 +783,10 @@ class AnsightReactNativeModule(
|
|
|
751
783
|
AnsightSessionJpegCaptureOptions.DefaultCaptureGpuBackedSurfaces,
|
|
752
784
|
),
|
|
753
785
|
mode = sessionJpegCaptureMode(jpeg.stringValue("mode")),
|
|
786
|
+
captureKeyboardPresence = jpeg.booleanValue(
|
|
787
|
+
"captureKeyboardPresence",
|
|
788
|
+
AnsightSessionJpegCaptureOptions.DefaultCaptureKeyboardPresence,
|
|
789
|
+
),
|
|
754
790
|
)
|
|
755
791
|
},
|
|
756
792
|
)
|
|
@@ -768,6 +804,24 @@ class AnsightReactNativeModule(
|
|
|
768
804
|
},
|
|
769
805
|
)
|
|
770
806
|
}
|
|
807
|
+
if (map.hasKey("crashCapture")) {
|
|
808
|
+
options = options.copy(
|
|
809
|
+
crashCapture = if (map.isFalse("crashCapture")) {
|
|
810
|
+
options.crashCapture.copy(enabled = false)
|
|
811
|
+
} else {
|
|
812
|
+
val crash = map.getMapOrNull("crashCapture")
|
|
813
|
+
AnsightCrashCaptureOptions(
|
|
814
|
+
enabled = crash.booleanValue("enabled", true),
|
|
815
|
+
studioHandoffEnabled = crash.booleanValue("studioHandoffEnabled", true),
|
|
816
|
+
offlineCaptureAttachmentEnabled = crash.booleanValue("offlineCaptureAttachmentEnabled", true),
|
|
817
|
+
maximumPendingReports = crash.intValue("maximumPendingReports", 8),
|
|
818
|
+
retentionDays = crash.intValue("retentionDays", 7),
|
|
819
|
+
maximumBreadcrumbs = crash.intValue("maximumBreadcrumbs", 64),
|
|
820
|
+
maximumTraceBytes = crash.intValue("maximumTraceBytes", 1_048_576),
|
|
821
|
+
)
|
|
822
|
+
},
|
|
823
|
+
)
|
|
824
|
+
}
|
|
771
825
|
if (map.hasString("toolGuard")) {
|
|
772
826
|
options = options.copy(toolGuard = toolGuard(map.stringValue("toolGuard")))
|
|
773
827
|
}
|
|
@@ -931,14 +985,18 @@ class AnsightReactNativeModule(
|
|
|
931
985
|
AnsightSessionJpegCaptureOptions.DefaultCaptureGpuBackedSurfaces,
|
|
932
986
|
),
|
|
933
987
|
mode = sessionJpegCaptureMode(map.stringValue("mode")),
|
|
988
|
+
captureKeyboardPresence = map.booleanValue(
|
|
989
|
+
"captureKeyboardPresence",
|
|
990
|
+
AnsightSessionJpegCaptureOptions.DefaultCaptureKeyboardPresence,
|
|
991
|
+
),
|
|
934
992
|
)
|
|
935
993
|
}
|
|
936
994
|
|
|
937
995
|
private fun sessionJpegCaptureMode(value: String?): AnsightSessionJpegCaptureMode =
|
|
938
|
-
|
|
939
|
-
AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree
|
|
940
|
-
|
|
941
|
-
AnsightSessionJpegCaptureMode.ScreenshotOnly
|
|
996
|
+
when (value) {
|
|
997
|
+
"screenshotAndVisualTree" -> AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree
|
|
998
|
+
"screenshotWithVisualTreeOnTouch" -> AnsightSessionJpegCaptureMode.ScreenshotWithVisualTreeOnTouch
|
|
999
|
+
else -> AnsightSessionJpegCaptureMode.ScreenshotOnly
|
|
942
1000
|
}
|
|
943
1001
|
|
|
944
1002
|
private fun toolDefinition(map: ReadableMap): ToolDefinition =
|
|
@@ -1111,6 +1169,8 @@ class AnsightReactNativeModule(
|
|
|
1111
1169
|
putInt("retentionPeriodSeconds", options.retentionPeriodSeconds)
|
|
1112
1170
|
putBoolean("enableFramesPerSecond", options.enableFramesPerSecond)
|
|
1113
1171
|
putBoolean("enableBatteryLevel", options.enableBatteryLevel)
|
|
1172
|
+
putBoolean("enableOpenFileHandleTracking", options.enableOpenFileHandleTracking)
|
|
1173
|
+
putBoolean("enableJniReferenceCountTracking", options.enableJniReferenceCountTracking)
|
|
1114
1174
|
putMap("defaultMemoryChannels", mapOf(
|
|
1115
1175
|
"managedHeap" to options.defaultMemoryChannels.javaHeap,
|
|
1116
1176
|
"javaHeap" to options.defaultMemoryChannels.javaHeap,
|
|
@@ -1127,10 +1187,11 @@ class AnsightReactNativeModule(
|
|
|
1127
1187
|
"quality" to capture.quality,
|
|
1128
1188
|
"maxWidth" to capture.maxWidth,
|
|
1129
1189
|
"captureGpuBackedSurfaces" to capture.captureGpuBackedSurfaces,
|
|
1130
|
-
"
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
"
|
|
1190
|
+
"captureKeyboardPresence" to capture.captureKeyboardPresence,
|
|
1191
|
+
"mode" to when (capture.mode) {
|
|
1192
|
+
AnsightSessionJpegCaptureMode.ScreenshotAndVisualTree -> "screenshotAndVisualTree"
|
|
1193
|
+
AnsightSessionJpegCaptureMode.ScreenshotWithVisualTreeOnTouch -> "screenshotWithVisualTreeOnTouch"
|
|
1194
|
+
else -> "screenshotOnly"
|
|
1134
1195
|
},
|
|
1135
1196
|
).toWritableMap())
|
|
1136
1197
|
} ?: putNull("sessionJpegCapture")
|
package/index.d.ts
CHANGED
|
@@ -37,7 +37,8 @@ export interface AnsightSessionJpegCaptureOptions {
|
|
|
37
37
|
quality?: number;
|
|
38
38
|
maxWidth?: number;
|
|
39
39
|
captureGpuBackedSurfaces?: boolean;
|
|
40
|
-
|
|
40
|
+
captureKeyboardPresence?: boolean;
|
|
41
|
+
mode?: "screenshotOnly" | "screenshotAndVisualTree" | "screenshotWithVisualTreeOnTouch";
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export interface AnsightTouchCaptureOptions {
|
|
@@ -110,6 +111,8 @@ export interface AnsightOptions {
|
|
|
110
111
|
retentionPeriodSeconds?: number;
|
|
111
112
|
enableFramesPerSecond?: boolean;
|
|
112
113
|
enableBatteryLevel?: boolean;
|
|
114
|
+
enableOpenFileHandleTracking?: boolean;
|
|
115
|
+
enableJniReferenceCountTracking?: boolean;
|
|
113
116
|
defaultMemoryChannels?: {
|
|
114
117
|
managedHeap?: boolean;
|
|
115
118
|
physicalFootprint?: boolean;
|
|
@@ -121,6 +124,7 @@ export interface AnsightOptions {
|
|
|
121
124
|
reactNativeMemory?: false | AnsightReactNativeMemoryOptions;
|
|
122
125
|
sessionJpegCapture?: false | AnsightSessionJpegCaptureOptions;
|
|
123
126
|
touchCapture?: false | AnsightTouchCaptureOptions;
|
|
127
|
+
crashCapture?: false | AnsightCrashCaptureOptions;
|
|
124
128
|
lifecycleCapture?: {
|
|
125
129
|
enabled?: boolean;
|
|
126
130
|
captureAppLifecycle?: boolean;
|
|
@@ -153,6 +157,25 @@ export interface AnsightOptions {
|
|
|
153
157
|
lifecycle?: boolean;
|
|
154
158
|
}
|
|
155
159
|
|
|
160
|
+
export interface AnsightCrashCaptureOptions {
|
|
161
|
+
enabled?: boolean;
|
|
162
|
+
studioHandoffEnabled?: boolean;
|
|
163
|
+
offlineCaptureAttachmentEnabled?: boolean;
|
|
164
|
+
maximumPendingReports?: number;
|
|
165
|
+
retentionDays?: number;
|
|
166
|
+
maximumBreadcrumbs?: number;
|
|
167
|
+
maximumTraceBytes?: number;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface AnsightCrashCandidate {
|
|
171
|
+
runtime?: string;
|
|
172
|
+
kind?: string;
|
|
173
|
+
message?: string;
|
|
174
|
+
stack?: string;
|
|
175
|
+
fatal?: boolean;
|
|
176
|
+
metadata?: string | Record<string, string>;
|
|
177
|
+
}
|
|
178
|
+
|
|
156
179
|
export interface AnsightOperationResult {
|
|
157
180
|
success: boolean;
|
|
158
181
|
message: string;
|
|
@@ -251,6 +274,10 @@ export class AnsightOptionsBuilder {
|
|
|
251
274
|
withoutFramesPerSecond(): this;
|
|
252
275
|
withBatteryLevel(): this;
|
|
253
276
|
withoutBatteryLevel(): this;
|
|
277
|
+
withOpenFileHandleTracking(): this;
|
|
278
|
+
withoutOpenFileHandleTracking(): this;
|
|
279
|
+
withJniReferenceCountTracking(): this;
|
|
280
|
+
withoutJniReferenceCountTracking(): this;
|
|
254
281
|
withRetentionPeriodSeconds(retentionPeriodSeconds: number): this;
|
|
255
282
|
withAdditionalChannels(additionalChannels: AnsightChannel[]): this;
|
|
256
283
|
addAdditionalChannel(additionalChannel: AnsightChannel): this;
|
|
@@ -264,11 +291,14 @@ export class AnsightOptionsBuilder {
|
|
|
264
291
|
quality?: number,
|
|
265
292
|
maxWidth?: number | null,
|
|
266
293
|
captureGpuBackedSurfaces?: boolean,
|
|
267
|
-
mode?: "screenshotOnly" | "screenshotAndVisualTree"
|
|
294
|
+
mode?: "screenshotOnly" | "screenshotAndVisualTree" | "screenshotWithVisualTreeOnTouch",
|
|
295
|
+
captureKeyboardPresence?: boolean
|
|
268
296
|
): this;
|
|
269
297
|
withoutSessionJpegCapture(): this;
|
|
270
298
|
withTouchCapture(touchCapture?: AnsightTouchCaptureOptions): this;
|
|
271
299
|
withoutTouchCapture(): this;
|
|
300
|
+
withCrashCapture(crashCapture?: AnsightCrashCaptureOptions): this;
|
|
301
|
+
withoutCrashCapture(): this;
|
|
272
302
|
withLifecycleCapture(lifecycleCapture?: NonNullable<AnsightOptions["lifecycleCapture"]>): this;
|
|
273
303
|
withToolGuard(toolGuard: NonNullable<AnsightOptions["toolGuard"]>): this;
|
|
274
304
|
withToolsDisabled(): this;
|
|
@@ -512,6 +542,7 @@ export function metric(value: number, channel?: number): Promise<AnsightDebugSna
|
|
|
512
542
|
export function recordMetric(value: number, channel?: number): Promise<AnsightDebugSnapshot>;
|
|
513
543
|
export function event(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
|
|
514
544
|
export function recordEvent(input: string | { label: string; type?: string; details?: string; channel?: number }): Promise<AnsightDebugSnapshot>;
|
|
545
|
+
export function recordCrashCandidate(input?: AnsightCrashCandidate): Promise<{ candidateId?: string }>;
|
|
515
546
|
export function screenViewed(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
|
|
516
547
|
export function trackRoute(name: string, details?: Record<string, string>): Promise<AnsightDebugSnapshot>;
|
|
517
548
|
export function setAppLifecycleState(state: AnsightLifecycleState): Promise<AnsightDebugSnapshot>;
|
|
@@ -585,6 +616,7 @@ declare const Ansight: {
|
|
|
585
616
|
recordMetric: typeof recordMetric;
|
|
586
617
|
event: typeof event;
|
|
587
618
|
recordEvent: typeof recordEvent;
|
|
619
|
+
recordCrashCandidate: typeof recordCrashCandidate;
|
|
588
620
|
screenViewed: typeof screenViewed;
|
|
589
621
|
trackRoute: typeof trackRoute;
|
|
590
622
|
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;
|
|
@@ -269,6 +294,7 @@ class AnsightOptionsBuilder {
|
|
|
269
294
|
maxWidth: arguments.length > 2 ? arguments[2] : 480,
|
|
270
295
|
captureGpuBackedSurfaces: arguments.length > 3 ? arguments[3] : true,
|
|
271
296
|
mode: arguments.length > 4 ? arguments[4] : "screenshotOnly",
|
|
297
|
+
captureKeyboardPresence: arguments.length > 5 ? arguments[5] : false,
|
|
272
298
|
};
|
|
273
299
|
return this;
|
|
274
300
|
}
|
|
@@ -276,6 +302,7 @@ class AnsightOptionsBuilder {
|
|
|
276
302
|
intervalMilliseconds: 2000,
|
|
277
303
|
quality: 60,
|
|
278
304
|
maxWidth: 480,
|
|
305
|
+
captureKeyboardPresence: false,
|
|
279
306
|
mode: "screenshotOnly",
|
|
280
307
|
...(optionsOrIntervalMilliseconds || {}),
|
|
281
308
|
};
|
|
@@ -297,6 +324,16 @@ class AnsightOptionsBuilder {
|
|
|
297
324
|
return this;
|
|
298
325
|
}
|
|
299
326
|
|
|
327
|
+
withCrashCapture(crashCapture = {}) {
|
|
328
|
+
this._options.crashCapture = { ...crashCapture, enabled: true };
|
|
329
|
+
return this;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
withoutCrashCapture() {
|
|
333
|
+
this._options.crashCapture = false;
|
|
334
|
+
return this;
|
|
335
|
+
}
|
|
336
|
+
|
|
300
337
|
withLifecycleCapture(lifecycleCapture = {}) {
|
|
301
338
|
this._options.lifecycleCapture = { ...lifecycleCapture };
|
|
302
339
|
return this;
|
|
@@ -2218,6 +2255,14 @@ function installErrorHandlers(options = {}) {
|
|
|
2218
2255
|
|
|
2219
2256
|
if (global.ErrorUtils && global.ErrorUtils.setGlobalHandler) {
|
|
2220
2257
|
global.ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
2258
|
+
nativeModule.recordCrashCandidate({
|
|
2259
|
+
runtime: "react-native-javascript",
|
|
2260
|
+
kind: "unhandled_javascript_error",
|
|
2261
|
+
message: error && error.message,
|
|
2262
|
+
stack: error && error.stack,
|
|
2263
|
+
fatal: !!isFatal,
|
|
2264
|
+
metadata: JSON.stringify({ name: error && error.name }),
|
|
2265
|
+
}).catch(() => {});
|
|
2221
2266
|
nativeModule.recordEvent({
|
|
2222
2267
|
label: error && error.message ? error.message : "Unhandled JavaScript error",
|
|
2223
2268
|
type: "Exception",
|
|
@@ -2240,6 +2285,13 @@ function installErrorHandlers(options = {}) {
|
|
|
2240
2285
|
global.__ansightUnhandledRejectionTrackingInstalled = true;
|
|
2241
2286
|
global.addEventListener("unhandledrejection", (event) => {
|
|
2242
2287
|
const reason = event && event.reason;
|
|
2288
|
+
nativeModule.recordCrashCandidate({
|
|
2289
|
+
runtime: "react-native-javascript",
|
|
2290
|
+
kind: "unhandled_promise_rejection",
|
|
2291
|
+
message: reason && reason.message ? reason.message : String(reason),
|
|
2292
|
+
stack: reason && reason.stack,
|
|
2293
|
+
fatal: false,
|
|
2294
|
+
}).catch(() => {});
|
|
2243
2295
|
nativeModule.recordEvent({
|
|
2244
2296
|
label: reason && reason.message ? reason.message : "Unhandled JavaScript promise rejection",
|
|
2245
2297
|
type: "Exception",
|
|
@@ -2334,6 +2386,16 @@ function recordEvent(input) {
|
|
|
2334
2386
|
return nativeModule.recordEvent(input || {});
|
|
2335
2387
|
}
|
|
2336
2388
|
|
|
2389
|
+
function recordCrashCandidate(input = {}) {
|
|
2390
|
+
const metadata = input.metadata && typeof input.metadata === "object"
|
|
2391
|
+
? JSON.stringify(input.metadata)
|
|
2392
|
+
: input.metadata;
|
|
2393
|
+
return nativeModule.recordCrashCandidate({
|
|
2394
|
+
...input,
|
|
2395
|
+
metadata,
|
|
2396
|
+
});
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2337
2399
|
function screenViewed(name, details) {
|
|
2338
2400
|
return nativeModule.screenViewed(name, details || {});
|
|
2339
2401
|
}
|
|
@@ -2376,6 +2438,7 @@ const Ansight = {
|
|
|
2376
2438
|
recordMetric: (value, channel = 255) => nativeModule.recordMetric(value, channel),
|
|
2377
2439
|
event: recordEvent,
|
|
2378
2440
|
recordEvent,
|
|
2441
|
+
recordCrashCandidate,
|
|
2379
2442
|
screenViewed,
|
|
2380
2443
|
trackRoute,
|
|
2381
2444
|
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,14 @@ 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,
|
|
980
|
+
captureKeyboardPresence: boolValue(
|
|
981
|
+
jpeg,
|
|
982
|
+
"captureKeyboardPresence",
|
|
983
|
+
defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureKeyboardPresence
|
|
984
|
+
)
|
|
948
985
|
)
|
|
949
986
|
}
|
|
950
987
|
}
|
|
@@ -960,6 +997,21 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
960
997
|
)
|
|
961
998
|
}
|
|
962
999
|
}
|
|
1000
|
+
if let raw = dictionary?["crashCapture"] {
|
|
1001
|
+
if (raw as? Bool) == false {
|
|
1002
|
+
options.crashCapture.enabled = false
|
|
1003
|
+
} else if let crash = raw as? NSDictionary {
|
|
1004
|
+
options.crashCapture = AnsightCrashCaptureOptions(
|
|
1005
|
+
enabled: boolValue(crash, "enabled", defaultValue: true),
|
|
1006
|
+
studioHandoffEnabled: boolValue(crash, "studioHandoffEnabled", defaultValue: true),
|
|
1007
|
+
offlineCaptureAttachmentEnabled: boolValue(crash, "offlineCaptureAttachmentEnabled", defaultValue: true),
|
|
1008
|
+
maximumPendingReports: intValue(crash, "maximumPendingReports", defaultValue: 8),
|
|
1009
|
+
retentionDays: intValue(crash, "retentionDays", defaultValue: 7),
|
|
1010
|
+
maximumBreadcrumbs: intValue(crash, "maximumBreadcrumbs", defaultValue: 64),
|
|
1011
|
+
maximumTraceBytes: intValue(crash, "maximumTraceBytes", defaultValue: 1_048_576)
|
|
1012
|
+
)
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
963
1015
|
if let lifecycle = dictionary?["lifecycleCapture"] as? NSDictionary {
|
|
964
1016
|
options.lifecycleCapture = AnsightLifecycleCaptureOptions(
|
|
965
1017
|
enabled: boolValue(lifecycle, "enabled", defaultValue: options.lifecycleCapture.enabled),
|
|
@@ -1271,9 +1323,14 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
1271
1323
|
"captureGpuBackedSurfaces",
|
|
1272
1324
|
defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureGpuBackedSurfaces
|
|
1273
1325
|
),
|
|
1274
|
-
mode:
|
|
1275
|
-
|
|
1276
|
-
|
|
1326
|
+
mode: AnsightSessionJpegCaptureMode(
|
|
1327
|
+
rawValue: stringValue(dictionary, "mode") ?? ""
|
|
1328
|
+
) ?? .screenshotOnly,
|
|
1329
|
+
captureKeyboardPresence: boolValue(
|
|
1330
|
+
dictionary,
|
|
1331
|
+
"captureKeyboardPresence",
|
|
1332
|
+
defaultValue: AnsightSessionJpegCaptureOptions.defaultCaptureKeyboardPresence
|
|
1333
|
+
)
|
|
1277
1334
|
)
|
|
1278
1335
|
}
|
|
1279
1336
|
|
|
@@ -1283,6 +1340,8 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
1283
1340
|
"retentionPeriodSeconds": options.retentionPeriodSeconds,
|
|
1284
1341
|
"enableFramesPerSecond": options.enableFramesPerSecond,
|
|
1285
1342
|
"enableBatteryLevel": options.enableBatteryLevel,
|
|
1343
|
+
"enableOpenFileHandleTracking": options.enableOpenFileHandleTracking,
|
|
1344
|
+
"enableJniReferenceCountTracking": false,
|
|
1286
1345
|
"defaultMemoryChannels": [
|
|
1287
1346
|
"managedHeap": options.defaultMemoryChannels.contains(.managedHeap),
|
|
1288
1347
|
"javaHeap": options.defaultMemoryChannels.contains(.managedHeap),
|
|
@@ -1322,6 +1381,7 @@ final class AnsightReactNative: RCTEventEmitter {
|
|
|
1322
1381
|
"quality": capture.quality,
|
|
1323
1382
|
"maxWidth": capture.maxWidth as Any,
|
|
1324
1383
|
"captureGpuBackedSurfaces": capture.captureGpuBackedSurfaces,
|
|
1384
|
+
"captureKeyboardPresence": capture.captureKeyboardPresence,
|
|
1325
1385
|
"mode": capture.mode.rawValue,
|
|
1326
1386
|
]
|
|
1327
1387
|
} else {
|
|
@@ -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
|