@goliapkg/sentori-react-native 1.0.0-rc.1 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/sentori/SentoriForegroundActivity.kt +145 -0
- package/android/src/main/java/com/sentori/SentoriModule.kt +8 -0
- package/android/src/main/java/com/sentori/SentoriReplayCapture.kt +14 -21
- package/android/src/main/java/com/sentori/SentoriScreenshotCapture.kt +72 -36
- package/ios/SentoriModule.swift +7 -0
- package/ios/SentoriScreenshotCapture.swift +69 -3
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/native.d.ts +29 -0
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +43 -0
- package/lib/native.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/native.ts +61 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
package com.sentori
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.app.Application
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import java.lang.ref.WeakReference
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* v1.0.0-rc.2 — process-wide foreground-Activity tracker.
|
|
10
|
+
*
|
|
11
|
+
* Both [SentoriScreenshotCapture] and [SentoriReplayCapture] need a
|
|
12
|
+
* pointer to the currently-foregrounded Activity to drive their
|
|
13
|
+
* native captures. The previous implementation registered each
|
|
14
|
+
* helper's own `ActivityLifecycleCallbacks` inside
|
|
15
|
+
* [SentoriCrashHandler.register], which runs from the Expo module's
|
|
16
|
+
* `OnCreate` lifecycle — **after** the MainActivity has already been
|
|
17
|
+
* resumed in the typical Insight / Expo dev-launcher topology.
|
|
18
|
+
* `ActivityLifecycleCallbacks` does not back-fill the current state,
|
|
19
|
+
* it only forwards future events, so `lastActivity` would stay null
|
|
20
|
+
* for the entire session if the user never backgrounded the app.
|
|
21
|
+
*
|
|
22
|
+
* Fix mirrors the iOS keyWindow 4-layer fallback:
|
|
23
|
+
*
|
|
24
|
+
* 1. Lifecycle callbacks track resumed/started activities going
|
|
25
|
+
* forward (the same approach as before, kept).
|
|
26
|
+
* 2. **On first install** we also probe `ActivityThread` reflection
|
|
27
|
+
* to back-fill whatever Activity is currently foreground, so the
|
|
28
|
+
* already-resumed window is seen by the SDK from boot.
|
|
29
|
+
* 3. If reflection fails (e.g. on a future Android release that
|
|
30
|
+
* removes `ActivityThread` access), the lifecycle callbacks
|
|
31
|
+
* still catch the next foreground transition.
|
|
32
|
+
*
|
|
33
|
+
* `lastPath` carries the diagnostic provenance for `probeWireframe` /
|
|
34
|
+
* `probeScreenshot`, so the JS side (and Insight) can tell whether
|
|
35
|
+
* the SDK was working off a live lifecycle event or fell back to
|
|
36
|
+
* reflection.
|
|
37
|
+
*/
|
|
38
|
+
object SentoriForegroundActivity {
|
|
39
|
+
|
|
40
|
+
@Volatile private var lastActivity: WeakReference<Activity>? = null
|
|
41
|
+
@Volatile var lastPath: String = "none(not-yet-resolved)"
|
|
42
|
+
private set
|
|
43
|
+
|
|
44
|
+
/** Idempotent. Call from [SentoriCrashHandler.register]; subsequent
|
|
45
|
+
* calls are no-ops because the same callbacks object would be
|
|
46
|
+
* registered twice otherwise. */
|
|
47
|
+
@Volatile private var registered = false
|
|
48
|
+
|
|
49
|
+
@Synchronized
|
|
50
|
+
fun install(application: Application) {
|
|
51
|
+
if (registered) {
|
|
52
|
+
// Even on second install attempt, try the reflection
|
|
53
|
+
// back-fill again — process state may have advanced.
|
|
54
|
+
backfillFromActivityThread()
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
registered = true
|
|
58
|
+
application.registerActivityLifecycleCallbacks(object :
|
|
59
|
+
Application.ActivityLifecycleCallbacks {
|
|
60
|
+
override fun onActivityCreated(a: Activity, b: Bundle?) {
|
|
61
|
+
set(a, "lifecycle.created")
|
|
62
|
+
}
|
|
63
|
+
override fun onActivityStarted(a: Activity) {
|
|
64
|
+
set(a, "lifecycle.started")
|
|
65
|
+
}
|
|
66
|
+
override fun onActivityResumed(a: Activity) {
|
|
67
|
+
set(a, "lifecycle.resumed")
|
|
68
|
+
}
|
|
69
|
+
override fun onActivityPaused(a: Activity) {}
|
|
70
|
+
override fun onActivityStopped(a: Activity) {}
|
|
71
|
+
override fun onActivitySaveInstanceState(a: Activity, b: Bundle) {}
|
|
72
|
+
override fun onActivityDestroyed(a: Activity) {}
|
|
73
|
+
})
|
|
74
|
+
// Back-fill in case the Activity was already resumed before
|
|
75
|
+
// we got installed (the dev-launcher → MainActivity transition
|
|
76
|
+
// happens before the Expo module's OnCreate fires).
|
|
77
|
+
backfillFromActivityThread()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Public for tests + the helpers' own explicit `setActivity`
|
|
81
|
+
* paths (kept for backwards-compat). */
|
|
82
|
+
fun set(activity: Activity, source: String) {
|
|
83
|
+
lastActivity = WeakReference(activity)
|
|
84
|
+
lastPath = source
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun current(): Activity? {
|
|
88
|
+
val live = lastActivity?.get()
|
|
89
|
+
if (live != null) return live
|
|
90
|
+
// Last-ditch: try reflection again in case install() ran before
|
|
91
|
+
// any Activity existed. Cheap if it fails.
|
|
92
|
+
backfillFromActivityThread()
|
|
93
|
+
return lastActivity?.get()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Best-effort foreground-Activity lookup using non-SDK reflection.
|
|
98
|
+
* Walks `ActivityThread.sCurrentActivityThread.mActivities` (an
|
|
99
|
+
* `ArrayMap<IBinder, ActivityClientRecord>`) and finds the record
|
|
100
|
+
* whose `paused` field is false. This is what Stetho / LeakCanary
|
|
101
|
+
* / Firebase Performance do, with the same caveat that future
|
|
102
|
+
* Android versions may break it — failures are silent and the
|
|
103
|
+
* lifecycle-callbacks path still wins.
|
|
104
|
+
*
|
|
105
|
+
* Tagged via `lastPath = "reflection.activityThread"` so the JS
|
|
106
|
+
* probe can see when reflection had to step in.
|
|
107
|
+
*/
|
|
108
|
+
@Suppress("PrivateApi", "UNCHECKED_CAST")
|
|
109
|
+
private fun backfillFromActivityThread() {
|
|
110
|
+
try {
|
|
111
|
+
val activityThreadClass = Class.forName("android.app.ActivityThread")
|
|
112
|
+
val currentActivityThread = activityThreadClass
|
|
113
|
+
.getDeclaredMethod("currentActivityThread")
|
|
114
|
+
.also { it.isAccessible = true }
|
|
115
|
+
.invoke(null) ?: return
|
|
116
|
+
val activitiesField = activityThreadClass
|
|
117
|
+
.getDeclaredField("mActivities")
|
|
118
|
+
.also { it.isAccessible = true }
|
|
119
|
+
val activities = activitiesField.get(currentActivityThread) ?: return
|
|
120
|
+
|
|
121
|
+
// ArrayMap<IBinder, ActivityClientRecord> — iterate via reflection
|
|
122
|
+
// so we don't have to depend on the (also private) ArrayMap shape.
|
|
123
|
+
val valuesIter = (activities as? Map<*, *>)?.values?.iterator() ?: return
|
|
124
|
+
while (valuesIter.hasNext()) {
|
|
125
|
+
val record = valuesIter.next() ?: continue
|
|
126
|
+
val recordClass = record.javaClass
|
|
127
|
+
val pausedField = try {
|
|
128
|
+
recordClass.getDeclaredField("paused").also { it.isAccessible = true }
|
|
129
|
+
} catch (_: NoSuchFieldException) { null }
|
|
130
|
+
val activityField = try {
|
|
131
|
+
recordClass.getDeclaredField("activity").also { it.isAccessible = true }
|
|
132
|
+
} catch (_: NoSuchFieldException) { null } ?: continue
|
|
133
|
+
val paused = pausedField?.getBoolean(record) ?: false
|
|
134
|
+
val candidate = activityField.get(record) as? Activity ?: continue
|
|
135
|
+
if (!paused && !candidate.isFinishing && !candidate.isDestroyed) {
|
|
136
|
+
set(candidate, "reflection.activityThread")
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} catch (_: Throwable) {
|
|
141
|
+
// Reflection unavailable; the lifecycle-callbacks path
|
|
142
|
+
// will still catch the next foreground transition.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -39,6 +39,14 @@ class SentoriModule : Module() {
|
|
|
39
39
|
SentoriReplayCapture.probe()
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// v1.0.0-rc.2 — diagnostic readout for screenshot. Surfaces
|
|
43
|
+
// foreground-Activity provenance, decor-view state, and the
|
|
44
|
+
// last failure reason so the JS side can ship raw state back
|
|
45
|
+
// when screenshot returns null.
|
|
46
|
+
Function("probeScreenshot") {
|
|
47
|
+
SentoriScreenshotCapture.probe()
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
// v0.9.4 #1 — Mobile Vitals exposure.
|
|
43
51
|
Function("markJsBridgeReady") {
|
|
44
52
|
SentoriMobileVitals.markJsBridgeReady()
|
|
@@ -9,7 +9,6 @@ import android.widget.ImageView
|
|
|
9
9
|
import android.widget.TextView
|
|
10
10
|
import org.json.JSONArray
|
|
11
11
|
import org.json.JSONObject
|
|
12
|
-
import java.lang.ref.WeakReference
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* v0.9.6 #2 — wireframe session replay (Android side).
|
|
@@ -27,8 +26,6 @@ object SentoriReplayCapture {
|
|
|
27
26
|
|
|
28
27
|
private const val MAX_NODES = 800
|
|
29
28
|
|
|
30
|
-
@Volatile private var lastActivity: WeakReference<Activity>? = null
|
|
31
|
-
|
|
32
29
|
// v0.9.12 — diagnostic readout so the JS side can ask "why is the
|
|
33
30
|
// ring empty?" without parsing logcat. Mirrors the iOS side.
|
|
34
31
|
@Volatile private var lastDiagPath: String = "none(not-yet-called)"
|
|
@@ -36,39 +33,35 @@ object SentoriReplayCapture {
|
|
|
36
33
|
|
|
37
34
|
@JvmStatic
|
|
38
35
|
fun probe(): Map<String, Any> {
|
|
39
|
-
val activity =
|
|
36
|
+
val activity = SentoriForegroundActivity.current()
|
|
40
37
|
return mapOf(
|
|
41
38
|
"lastPath" to lastDiagPath,
|
|
42
39
|
"lastNodes" to lastDiagNodes,
|
|
43
|
-
"
|
|
44
|
-
"
|
|
40
|
+
"trackedSource" to SentoriForegroundActivity.lastPath,
|
|
41
|
+
"trackedActivity" to (activity?.javaClass?.name ?: "null"),
|
|
42
|
+
"decorViewFound" to (activity?.window?.decorView != null),
|
|
45
43
|
)
|
|
46
44
|
}
|
|
47
45
|
|
|
46
|
+
/** Backwards compat — pre-rc.2 callers that hand-fed an Activity
|
|
47
|
+
* through `setActivity` still work; we forward to the shared
|
|
48
|
+
* tracker so screenshot + replay both see it. */
|
|
48
49
|
@JvmStatic
|
|
49
50
|
fun setActivity(activity: Activity?) {
|
|
50
|
-
|
|
51
|
+
if (activity != null) SentoriForegroundActivity.set(activity, "manual.setActivity")
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
54
|
+
/** Idempotent. Wires the replay helper into the shared tracker;
|
|
55
|
+
* kept as a public entrypoint for backwards compat with existing
|
|
56
|
+
* call sites. */
|
|
55
57
|
@JvmStatic
|
|
56
58
|
fun register(application: android.app.Application) {
|
|
57
|
-
|
|
58
|
-
android.app.Application.ActivityLifecycleCallbacks {
|
|
59
|
-
override fun onActivityCreated(a: Activity, b: android.os.Bundle?) { setActivity(a) }
|
|
60
|
-
override fun onActivityStarted(a: Activity) { setActivity(a) }
|
|
61
|
-
override fun onActivityResumed(a: Activity) { setActivity(a) }
|
|
62
|
-
override fun onActivityPaused(a: Activity) {}
|
|
63
|
-
override fun onActivityStopped(a: Activity) {}
|
|
64
|
-
override fun onActivitySaveInstanceState(a: Activity, b: android.os.Bundle) {}
|
|
65
|
-
override fun onActivityDestroyed(a: Activity) {}
|
|
66
|
-
})
|
|
59
|
+
SentoriForegroundActivity.install(application)
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
@JvmStatic
|
|
70
63
|
fun captureWireframe(maskedIds: List<String>): String? {
|
|
71
|
-
val activity =
|
|
64
|
+
val activity = SentoriForegroundActivity.current()
|
|
72
65
|
if (activity == null) {
|
|
73
66
|
lastDiagPath = "activity.null"
|
|
74
67
|
return null
|
|
@@ -89,7 +82,7 @@ object SentoriReplayCapture {
|
|
|
89
82
|
val rootLoc = IntArray(2).also { root.getLocationInWindow(it) }
|
|
90
83
|
walk(root, false, maskedSet, rootLoc, rect, nodes)
|
|
91
84
|
|
|
92
|
-
lastDiagPath = "
|
|
85
|
+
lastDiagPath = "ok(${SentoriForegroundActivity.lastPath})"
|
|
93
86
|
lastDiagNodes = nodes.length()
|
|
94
87
|
|
|
95
88
|
val payload = JSONObject().apply {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
package com.sentori
|
|
2
2
|
|
|
3
|
-
import android.app.Activity
|
|
4
3
|
import android.app.Application
|
|
5
4
|
import android.graphics.Bitmap
|
|
6
5
|
import android.graphics.Canvas
|
|
7
6
|
import android.graphics.Color
|
|
8
7
|
import android.graphics.Paint
|
|
9
8
|
import android.os.Build
|
|
10
|
-
import android.os.Bundle
|
|
11
9
|
import android.os.Handler
|
|
12
10
|
import android.os.HandlerThread
|
|
13
11
|
import android.util.Base64
|
|
@@ -16,7 +14,6 @@ import android.view.View
|
|
|
16
14
|
import android.view.ViewGroup
|
|
17
15
|
import android.view.Window
|
|
18
16
|
import java.io.ByteArrayOutputStream
|
|
19
|
-
import java.lang.ref.WeakReference
|
|
20
17
|
import java.util.concurrent.CountDownLatch
|
|
21
18
|
import java.util.concurrent.TimeUnit
|
|
22
19
|
import org.json.JSONArray
|
|
@@ -60,36 +57,44 @@ object SentoriScreenshotCapture {
|
|
|
60
57
|
private const val MAX_NODES = 1500
|
|
61
58
|
private const val PIXEL_COPY_TIMEOUT_MS = 200L
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@Volatile private var
|
|
60
|
+
// v1.0.0-rc.2 — diagnostic readout so the JS side can ask
|
|
61
|
+
// "why did screenshot return null" without parsing logcat. Mirrors
|
|
62
|
+
// SentoriReplayCapture.probe() and the iOS Swift probe.
|
|
63
|
+
@Volatile private var lastDiagPath: String = "none(not-yet-called)"
|
|
64
|
+
@Volatile private var lastDiagW: Int = 0
|
|
65
|
+
@Volatile private var lastDiagH: Int = 0
|
|
68
66
|
|
|
69
67
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* `
|
|
68
|
+
* Snapshot of the most recent capture attempt — what code path
|
|
69
|
+
* resolved an Activity, what the decor view's dimensions were,
|
|
70
|
+
* and what call source the foreground tracker last saw the
|
|
71
|
+
* Activity from. Used by `probeNativeScreenshot()` on the JS
|
|
72
|
+
* side so Insight can ship raw diagnostic state back without
|
|
73
|
+
* needing logcat access.
|
|
74
|
+
*/
|
|
75
|
+
@JvmStatic
|
|
76
|
+
fun probe(): Map<String, Any> {
|
|
77
|
+
val tracked = SentoriForegroundActivity.current()
|
|
78
|
+
return mapOf(
|
|
79
|
+
"lastPath" to lastDiagPath,
|
|
80
|
+
"lastWidth" to lastDiagW,
|
|
81
|
+
"lastHeight" to lastDiagH,
|
|
82
|
+
"trackedSource" to SentoriForegroundActivity.lastPath,
|
|
83
|
+
"trackedActivity" to (tracked?.javaClass?.name ?: "null"),
|
|
84
|
+
"decorViewFound" to (tracked?.window?.decorView != null),
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Idempotent. Wires the screenshot helper into the shared
|
|
90
|
+
* foreground-activity tracker; kept as a public entrypoint for
|
|
91
|
+
* backwards compat with existing call sites (the crash handler
|
|
92
|
+
* still calls this), but the actual lifecycle subscription lives
|
|
93
|
+
* in [SentoriForegroundActivity].
|
|
74
94
|
*/
|
|
75
95
|
@JvmStatic
|
|
76
96
|
fun register(application: Application) {
|
|
77
|
-
|
|
78
|
-
Application.ActivityLifecycleCallbacks {
|
|
79
|
-
override fun onActivityCreated(a: Activity, b: Bundle?) {
|
|
80
|
-
lastActivity = WeakReference(a)
|
|
81
|
-
}
|
|
82
|
-
override fun onActivityStarted(a: Activity) {
|
|
83
|
-
lastActivity = WeakReference(a)
|
|
84
|
-
}
|
|
85
|
-
override fun onActivityResumed(a: Activity) {
|
|
86
|
-
lastActivity = WeakReference(a)
|
|
87
|
-
}
|
|
88
|
-
override fun onActivityPaused(a: Activity) {}
|
|
89
|
-
override fun onActivityStopped(a: Activity) {}
|
|
90
|
-
override fun onActivitySaveInstanceState(a: Activity, b: Bundle) {}
|
|
91
|
-
override fun onActivityDestroyed(a: Activity) {}
|
|
92
|
-
})
|
|
97
|
+
SentoriForegroundActivity.install(application)
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
/**
|
|
@@ -102,8 +107,16 @@ object SentoriScreenshotCapture {
|
|
|
102
107
|
*/
|
|
103
108
|
@JvmStatic
|
|
104
109
|
fun captureKeyWindow(): Map<String, Any>? {
|
|
105
|
-
val activity =
|
|
106
|
-
|
|
110
|
+
val activity = SentoriForegroundActivity.current()
|
|
111
|
+
if (activity == null) {
|
|
112
|
+
lastDiagPath = "activity.null"
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
val window = activity.window
|
|
116
|
+
if (window == null) {
|
|
117
|
+
lastDiagPath = "window.null"
|
|
118
|
+
return null
|
|
119
|
+
}
|
|
107
120
|
val out = mutableMapOf<String, Any>()
|
|
108
121
|
captureScreen(window, emptySet())?.let { (base64, mediaType) ->
|
|
109
122
|
out["screenshot"] = mapOf("base64" to base64, "mediaType" to mediaType)
|
|
@@ -120,8 +133,16 @@ object SentoriScreenshotCapture {
|
|
|
120
133
|
/// masked subview's frame on the captured bitmap.
|
|
121
134
|
@JvmStatic
|
|
122
135
|
fun captureScreenshotWithMask(maskedIds: List<String>): Map<String, String>? {
|
|
123
|
-
val activity =
|
|
124
|
-
|
|
136
|
+
val activity = SentoriForegroundActivity.current()
|
|
137
|
+
if (activity == null) {
|
|
138
|
+
lastDiagPath = "activity.null"
|
|
139
|
+
return null
|
|
140
|
+
}
|
|
141
|
+
val window = activity.window
|
|
142
|
+
if (window == null) {
|
|
143
|
+
lastDiagPath = "window.null"
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
125
146
|
val (base64, mediaType) = captureScreen(window, maskedIds.toHashSet()) ?: return null
|
|
126
147
|
return mapOf("base64" to base64, "mediaType" to mediaType)
|
|
127
148
|
}
|
|
@@ -135,12 +156,22 @@ object SentoriScreenshotCapture {
|
|
|
135
156
|
// requires the activity not to be torn down. Skip for
|
|
136
157
|
// now; v0.6.1 SDK can add the fallback if real-world
|
|
137
158
|
// data shows we have users below API 24.
|
|
159
|
+
lastDiagPath = "api.unsupported"
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
val decor = window.decorView
|
|
163
|
+
if (decor == null) {
|
|
164
|
+
lastDiagPath = "decorView.null"
|
|
138
165
|
return null
|
|
139
166
|
}
|
|
140
|
-
val decor = window.decorView ?: return null
|
|
141
167
|
val w = decor.width
|
|
142
168
|
val h = decor.height
|
|
143
|
-
|
|
169
|
+
lastDiagW = w
|
|
170
|
+
lastDiagH = h
|
|
171
|
+
if (w <= 0 || h <= 0) {
|
|
172
|
+
lastDiagPath = "decorView.zero-size"
|
|
173
|
+
return null
|
|
174
|
+
}
|
|
144
175
|
|
|
145
176
|
// Long-edge scale.
|
|
146
177
|
val longEdge = maxOf(w, h).toFloat()
|
|
@@ -175,12 +206,17 @@ object SentoriScreenshotCapture {
|
|
|
175
206
|
)
|
|
176
207
|
}
|
|
177
208
|
latch.await(PIXEL_COPY_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
|
178
|
-
} catch (
|
|
209
|
+
} catch (t: Throwable) {
|
|
210
|
+
lastDiagPath = "pixelCopy.threw:${t.javaClass.simpleName}"
|
|
179
211
|
return null
|
|
180
212
|
} finally {
|
|
181
213
|
handlerThread.quitSafely()
|
|
182
214
|
}
|
|
183
|
-
if (!success)
|
|
215
|
+
if (!success) {
|
|
216
|
+
lastDiagPath = "pixelCopy.notSuccess"
|
|
217
|
+
return null
|
|
218
|
+
}
|
|
219
|
+
lastDiagPath = "ok"
|
|
184
220
|
|
|
185
221
|
// v0.7.3 — paint black rectangles over masked subviews on the
|
|
186
222
|
// already-captured bitmap. We get window-relative coordinates
|
package/ios/SentoriModule.swift
CHANGED
|
@@ -38,6 +38,13 @@ public class SentoriModule: Module {
|
|
|
38
38
|
return SentoriReplayCapture.probe()
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// v1.0.0-rc.2 — diagnostic readout for screenshot. Same shape
|
|
42
|
+
// as Android side; lets Insight ship raw state back when the
|
|
43
|
+
// captureScreenshot path returns null.
|
|
44
|
+
Function("probeScreenshot") { () -> [String: Any] in
|
|
45
|
+
return SentoriScreenshotCapture.probe()
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
// v0.9.4 #1 — Mobile Vitals exposure.
|
|
42
49
|
Function("markJsBridgeReady") {
|
|
43
50
|
SentoriMobileVitals.markJsBridgeReady()
|
|
@@ -82,10 +82,15 @@ import UIKit
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
private static func captureWithMaskSync(maskedIds: [String]) -> [String: String]? {
|
|
85
|
-
guard let window =
|
|
85
|
+
guard let window = keyWindowDiag().window else {
|
|
86
|
+
lastDiagPath = "window.null"
|
|
87
|
+
return nil
|
|
88
|
+
}
|
|
86
89
|
guard let jpeg = renderJpegBase64(window: window, maskedIds: Set(maskedIds)) else {
|
|
90
|
+
lastDiagPath = "render.failed"
|
|
87
91
|
return nil
|
|
88
92
|
}
|
|
93
|
+
lastDiagPath = "ok"
|
|
89
94
|
return [
|
|
90
95
|
"base64": jpeg,
|
|
91
96
|
"mediaType": "image/jpeg",
|
|
@@ -94,8 +99,28 @@ import UIKit
|
|
|
94
99
|
|
|
95
100
|
// MARK: - Internals
|
|
96
101
|
|
|
102
|
+
// v1.0.0-rc.2 — diagnostic readout mirror of the replay-capture
|
|
103
|
+
// probe. The JS side calls `probeScreenshot()` to ship raw state
|
|
104
|
+
// back when screenshot returns null.
|
|
105
|
+
private static var lastDiagPath: String = "none(not-yet-called)"
|
|
106
|
+
|
|
107
|
+
@objc public static func probe() -> [String: Any] {
|
|
108
|
+
let (win, path) = keyWindowDiag()
|
|
109
|
+
return [
|
|
110
|
+
"lastPath": lastDiagPath,
|
|
111
|
+
"resolvedPath": path,
|
|
112
|
+
"windowFound": win != nil,
|
|
113
|
+
"rootViewControllerFound": win?.rootViewController != nil,
|
|
114
|
+
"boundsW": win.map { Double($0.bounds.width) } ?? 0.0,
|
|
115
|
+
"boundsH": win.map { Double($0.bounds.height) } ?? 0.0,
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
|
|
97
119
|
private static func captureSync() -> [String: Any]? {
|
|
98
|
-
guard let window =
|
|
120
|
+
guard let window = keyWindowDiag().window else {
|
|
121
|
+
lastDiagPath = "window.null"
|
|
122
|
+
return nil
|
|
123
|
+
}
|
|
99
124
|
var out: [String: Any] = [:]
|
|
100
125
|
if let jpeg = renderJpegBase64(window: window) {
|
|
101
126
|
out["screenshot"] = [
|
|
@@ -104,7 +129,48 @@ import UIKit
|
|
|
104
129
|
]
|
|
105
130
|
}
|
|
106
131
|
out["viewTree"] = walkTree(root: window)
|
|
107
|
-
|
|
132
|
+
if out.isEmpty {
|
|
133
|
+
lastDiagPath = "empty"
|
|
134
|
+
return nil
|
|
135
|
+
}
|
|
136
|
+
lastDiagPath = "ok"
|
|
137
|
+
return out
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// keyWindow with the same 4-tier resolution as the replay capture,
|
|
141
|
+
/// plus the diagnostic path tag for the probe. The original
|
|
142
|
+
/// single-pass `keyWindow()` is kept for source-compat callers but
|
|
143
|
+
/// new paths funnel through this so screenshot + replay agree on
|
|
144
|
+
/// which window they are pointing at.
|
|
145
|
+
private static func keyWindowDiag() -> (window: UIWindow?, path: String) {
|
|
146
|
+
if #available(iOS 13.0, *) {
|
|
147
|
+
let scenes = Array(UIApplication.shared.connectedScenes)
|
|
148
|
+
for scene in scenes where scene.activationState == .foregroundActive {
|
|
149
|
+
if let ws = scene as? UIWindowScene,
|
|
150
|
+
let key = ws.windows.first(where: { $0.isKeyWindow }) {
|
|
151
|
+
return (key, "scene.fg.key")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for scene in scenes where scene.activationState == .foregroundActive {
|
|
155
|
+
if let ws = scene as? UIWindowScene, let win = ws.windows.first {
|
|
156
|
+
return (win, "scene.fg.first")
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for scene in scenes where scene.activationState == .foregroundInactive {
|
|
160
|
+
if let ws = scene as? UIWindowScene, let win = ws.windows.first {
|
|
161
|
+
return (win, "scene.fgi.first")
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
for scene in scenes {
|
|
165
|
+
if let ws = scene as? UIWindowScene, let win = ws.windows.first {
|
|
166
|
+
return (win, "scene.any.first")
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if let leg = UIApplication.shared.windows.first {
|
|
171
|
+
return (leg, "legacy.first")
|
|
172
|
+
}
|
|
173
|
+
return (nil, "none")
|
|
108
174
|
}
|
|
109
175
|
|
|
110
176
|
private static func keyWindow() -> UIWindow? {
|
package/lib/index.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export { getColdStartMs, markTimeToFullDisplay, type TimeToFullDisplayHandle, }
|
|
|
61
61
|
export { MomentHandle, type MomentProperties, startMoment } from '@goliapkg/sentori-core';
|
|
62
62
|
export { bindState, recordState, type StateSnapshot, unbindState, } from './state-snapshots';
|
|
63
63
|
export { RageTapCapture } from './rage-tap';
|
|
64
|
-
export { probeNativeWireframe, startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
64
|
+
export { probeNativeScreenshot, probeNativeWireframe, startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
65
65
|
export { drainReplay, startReplay, stopReplay } from './replay';
|
|
66
66
|
export { endSession, markSessionCrashed, startSession, } from './session-tracker';
|
|
67
67
|
export { type NavigationRefLike, useTraceNavigation } from './navigation';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAOxG,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO5C,eAAO,MAAM,OAAO;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAOxG,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO5C,eAAO,MAAM,OAAO;;;;;;;;;;aAiG6P,CAAC;eAAmB,CAAC;YAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAnEtT,CAAC;AAEF,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,gBAAgB,EAChB,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxG,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EACL,SAAS,EACT,WAAW,EACX,KAAK,aAAa,EAClB,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE1E,YAAY,EACV,KAAK,EACL,YAAY,EACZ,KAAK,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,QAAQ,GACT,MAAM,SAAS,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -57,7 +57,7 @@ export { getColdStartMs, markTimeToFullDisplay, } from './mobile-vitals';
|
|
|
57
57
|
export { MomentHandle, startMoment } from '@goliapkg/sentori-core';
|
|
58
58
|
export { bindState, recordState, unbindState, } from './state-snapshots';
|
|
59
59
|
export { RageTapCapture } from './rage-tap';
|
|
60
|
-
export { probeNativeWireframe, startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
60
|
+
export { probeNativeScreenshot, probeNativeWireframe, startAnrWatchdog, stopAnrWatchdog, triggerNativeCrash, } from './native';
|
|
61
61
|
export { drainReplay, startReplay, stopReplay } from './replay';
|
|
62
62
|
export { endSession, markSessionCrashed, startSession, } from './session-tracker';
|
|
63
63
|
export { useTraceNavigation } from './navigation';
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/native.d.ts
CHANGED
|
@@ -107,4 +107,33 @@ export declare function probeNativeWireframe(): {
|
|
|
107
107
|
sceneCount: number;
|
|
108
108
|
windowCount: number;
|
|
109
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* v1.0.0-rc.2 — JS entry to the `probeScreenshot` native diagnostic.
|
|
112
|
+
* Same shape contract as [probeNativeWireframe]: returns a flat
|
|
113
|
+
* key/value bag the consumer can ship back as-is when screenshot
|
|
114
|
+
* capture returns null.
|
|
115
|
+
*
|
|
116
|
+
* path meaning
|
|
117
|
+
* ───────────────────────── ───────────────────────────────────────
|
|
118
|
+
* none(not-yet-called) captureScreenshot has never run
|
|
119
|
+
* ok capture succeeded
|
|
120
|
+
* activity.null Android: foreground tracker had no Activity
|
|
121
|
+
* window.null Android/iOS: Activity/scene has no window
|
|
122
|
+
* decorView.null Android: window had no decor view
|
|
123
|
+
* decorView.zero-size Android: decorView size <= 0 (mid-layout)
|
|
124
|
+
* api.unsupported Android: API < 24 (no PixelCopy)
|
|
125
|
+
* pixelCopy.notSuccess Android: PixelCopy completed but reported failure
|
|
126
|
+
* pixelCopy.threw:<class> Android: PixelCopy threw mid-request
|
|
127
|
+
* render.failed iOS: UIGraphicsImageRenderer returned nil
|
|
128
|
+
* empty iOS: walked tree but no view+screenshot output
|
|
129
|
+
*
|
|
130
|
+
* On Android the result also carries `trackedSource` (lifecycle.created /
|
|
131
|
+
* lifecycle.resumed / reflection.activityThread / manual.setActivity)
|
|
132
|
+
* so callers can tell whether the SDK back-filled via reflection.
|
|
133
|
+
*/
|
|
134
|
+
export declare function probeNativeScreenshot(): {
|
|
135
|
+
available: boolean;
|
|
136
|
+
lastPath: string;
|
|
137
|
+
raw: Record<string, unknown>;
|
|
138
|
+
};
|
|
110
139
|
//# sourceMappingURL=native.d.ts.map
|
package/lib/native.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyIH,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,IAAI,CAMP;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAQ5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IACzC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,IAAI,CAMP;AAED,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED,+DAA+D;AAC/D,wBAAgB,uBAAuB,IAAI,IAAI,CAM9C;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,IAAI,IAAI,GAAG,MAAM,CAOpD;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,IAAI,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMhF;AAED,iEAAiE;AACjE,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAED;;yBAEyB;AACzB,wBAAgB,wBAAwB,IAAI,IAAI,GAAG;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAMA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACnD,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCvD;AAED;;sEAEsE;AACtE,wBAAgB,uBAAuB,IAAI;IACzC,KAAK,EAAE,OAAO,CAAA;IACd,mBAAmB,EAAE,OAAO,CAAA;IAC5B,iBAAiB,EAAE,OAAO,CAAA;CAC3B,CAOA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAiCA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,IAAI;IACvC,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CAkBA"}
|
package/lib/native.js
CHANGED
|
@@ -251,4 +251,47 @@ export function probeNativeWireframe() {
|
|
|
251
251
|
};
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* v1.0.0-rc.2 — JS entry to the `probeScreenshot` native diagnostic.
|
|
256
|
+
* Same shape contract as [probeNativeWireframe]: returns a flat
|
|
257
|
+
* key/value bag the consumer can ship back as-is when screenshot
|
|
258
|
+
* capture returns null.
|
|
259
|
+
*
|
|
260
|
+
* path meaning
|
|
261
|
+
* ───────────────────────── ───────────────────────────────────────
|
|
262
|
+
* none(not-yet-called) captureScreenshot has never run
|
|
263
|
+
* ok capture succeeded
|
|
264
|
+
* activity.null Android: foreground tracker had no Activity
|
|
265
|
+
* window.null Android/iOS: Activity/scene has no window
|
|
266
|
+
* decorView.null Android: window had no decor view
|
|
267
|
+
* decorView.zero-size Android: decorView size <= 0 (mid-layout)
|
|
268
|
+
* api.unsupported Android: API < 24 (no PixelCopy)
|
|
269
|
+
* pixelCopy.notSuccess Android: PixelCopy completed but reported failure
|
|
270
|
+
* pixelCopy.threw:<class> Android: PixelCopy threw mid-request
|
|
271
|
+
* render.failed iOS: UIGraphicsImageRenderer returned nil
|
|
272
|
+
* empty iOS: walked tree but no view+screenshot output
|
|
273
|
+
*
|
|
274
|
+
* On Android the result also carries `trackedSource` (lifecycle.created /
|
|
275
|
+
* lifecycle.resumed / reflection.activityThread / manual.setActivity)
|
|
276
|
+
* so callers can tell whether the SDK back-filled via reflection.
|
|
277
|
+
*/
|
|
278
|
+
export function probeNativeScreenshot() {
|
|
279
|
+
const n = native();
|
|
280
|
+
if (!n || typeof n.probeScreenshot !== 'function') {
|
|
281
|
+
return { available: false, lastPath: 'native.unavailable', raw: {} };
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const r = n.probeScreenshot();
|
|
285
|
+
const raw = r && typeof r === 'object' && !Array.isArray(r) ? r : {};
|
|
286
|
+
const lastPath = typeof raw.lastPath === 'string' ? raw.lastPath : 'unknown';
|
|
287
|
+
return { available: true, lastPath, raw };
|
|
288
|
+
}
|
|
289
|
+
catch (e) {
|
|
290
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
291
|
+
// eslint-disable-next-line no-console
|
|
292
|
+
console.warn('[sentori] probeScreenshot threw', e);
|
|
293
|
+
}
|
|
294
|
+
return { available: false, lastPath: 'native.threw', raw: {} };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
254
297
|
//# sourceMappingURL=native.js.map
|
package/lib/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goliapkg/sentori-react-native",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
4
|
"description": "Sentori SDK for React Native \u2014 JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://sentori.golia.jp",
|
package/src/index.ts
CHANGED
package/src/native.ts
CHANGED
|
@@ -78,9 +78,20 @@ type SentoriNativeModule = {
|
|
|
78
78
|
probeWireframe?: () => {
|
|
79
79
|
lastPath: string
|
|
80
80
|
lastNodes: number
|
|
81
|
-
sceneCount
|
|
82
|
-
windowCount
|
|
81
|
+
sceneCount?: number
|
|
82
|
+
windowCount?: number
|
|
83
|
+
trackedSource?: string
|
|
84
|
+
trackedActivity?: string
|
|
85
|
+
decorViewFound?: boolean
|
|
83
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* v1.0.0-rc.2 — diagnostic mirror of probeWireframe for the
|
|
89
|
+
* screenshot path. Returned shape is best-effort cross-platform —
|
|
90
|
+
* Android carries `trackedActivity` / `decorViewFound` / dims,
|
|
91
|
+
* iOS carries `windowFound` / `rootViewControllerFound` / `bounds*`.
|
|
92
|
+
* Callers should treat unknown keys as missing.
|
|
93
|
+
*/
|
|
94
|
+
probeScreenshot?: () => Record<string, unknown>
|
|
84
95
|
/**
|
|
85
96
|
* Phase 22 sub-D / sub-E: cross-platform main-thread watchdog.
|
|
86
97
|
* Android: 5 s / 1 s defaults (matches the OS ANR threshold).
|
|
@@ -379,3 +390,51 @@ export function probeNativeWireframe(): {
|
|
|
379
390
|
}
|
|
380
391
|
}
|
|
381
392
|
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* v1.0.0-rc.2 — JS entry to the `probeScreenshot` native diagnostic.
|
|
396
|
+
* Same shape contract as [probeNativeWireframe]: returns a flat
|
|
397
|
+
* key/value bag the consumer can ship back as-is when screenshot
|
|
398
|
+
* capture returns null.
|
|
399
|
+
*
|
|
400
|
+
* path meaning
|
|
401
|
+
* ───────────────────────── ───────────────────────────────────────
|
|
402
|
+
* none(not-yet-called) captureScreenshot has never run
|
|
403
|
+
* ok capture succeeded
|
|
404
|
+
* activity.null Android: foreground tracker had no Activity
|
|
405
|
+
* window.null Android/iOS: Activity/scene has no window
|
|
406
|
+
* decorView.null Android: window had no decor view
|
|
407
|
+
* decorView.zero-size Android: decorView size <= 0 (mid-layout)
|
|
408
|
+
* api.unsupported Android: API < 24 (no PixelCopy)
|
|
409
|
+
* pixelCopy.notSuccess Android: PixelCopy completed but reported failure
|
|
410
|
+
* pixelCopy.threw:<class> Android: PixelCopy threw mid-request
|
|
411
|
+
* render.failed iOS: UIGraphicsImageRenderer returned nil
|
|
412
|
+
* empty iOS: walked tree but no view+screenshot output
|
|
413
|
+
*
|
|
414
|
+
* On Android the result also carries `trackedSource` (lifecycle.created /
|
|
415
|
+
* lifecycle.resumed / reflection.activityThread / manual.setActivity)
|
|
416
|
+
* so callers can tell whether the SDK back-filled via reflection.
|
|
417
|
+
*/
|
|
418
|
+
export function probeNativeScreenshot(): {
|
|
419
|
+
available: boolean
|
|
420
|
+
lastPath: string
|
|
421
|
+
raw: Record<string, unknown>
|
|
422
|
+
} {
|
|
423
|
+
const n = native()
|
|
424
|
+
if (!n || typeof n.probeScreenshot !== 'function') {
|
|
425
|
+
return { available: false, lastPath: 'native.unavailable', raw: {} }
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
const r = n.probeScreenshot()
|
|
429
|
+
const raw =
|
|
430
|
+
r && typeof r === 'object' && !Array.isArray(r) ? (r as Record<string, unknown>) : {}
|
|
431
|
+
const lastPath = typeof raw.lastPath === 'string' ? raw.lastPath : 'unknown'
|
|
432
|
+
return { available: true, lastPath, raw }
|
|
433
|
+
} catch (e) {
|
|
434
|
+
if (typeof __DEV__ !== 'undefined' && __DEV__) {
|
|
435
|
+
// eslint-disable-next-line no-console
|
|
436
|
+
console.warn('[sentori] probeScreenshot threw', e)
|
|
437
|
+
}
|
|
438
|
+
return { available: false, lastPath: 'native.threw', raw: {} }
|
|
439
|
+
}
|
|
440
|
+
}
|