react-native-userleap 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +53 -44
- package/android/src/main/java/com/userleap/reactnative/UserLeapModule.kt +336 -0
- package/index.d.ts +90 -0
- package/index.js +157 -6
- package/ios/UserLeapBindings.h +5 -4
- package/ios/UserLeapBindings.mm +459 -0
- package/package.json +11 -2
- package/react-native-userleap.podspec +10 -3
- package/src/NativeUserLeapBindings.ts +95 -0
- package/android/src/main/java/com/userleap/reactnative/UserLeapModule.java +0 -387
- package/ios/UserLeapBindings.m +0 -287
package/android/build.gradle
CHANGED
|
@@ -1,81 +1,90 @@
|
|
|
1
1
|
// android/build.gradle
|
|
2
|
-
// based on:
|
|
3
2
|
//
|
|
4
|
-
//
|
|
5
|
-
// original location:
|
|
6
|
-
// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle
|
|
3
|
+
// Modernized for React Native 0.85:
|
|
7
4
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
// - Applies the `com.facebook.react` plugin so RN's codegen runs against
|
|
6
|
+
// our TurboModule spec in `../src/` and generates the Java abstract base
|
|
7
|
+
// class our Kotlin module inherits from plus the C++ JNI glue the New
|
|
8
|
+
// Architecture autolinking links against. Codegen is configured by the
|
|
9
|
+
// `react { ... }` block below. `jsRootDir` MUST point at the isolated
|
|
10
|
+
// `src/` dir (not the package root) so codegen scans only our spec and
|
|
11
|
+
// not the sibling `example/` app's node_modules.
|
|
12
|
+
// - Applies the Kotlin plugin so `UserLeapModule.kt` compiles.
|
|
13
|
+
// - Sets `namespace` (required by Android Gradle Plugin 8+).
|
|
14
|
+
// - Targets Java 17 / Kotlin (matches RN 0.85's host-app build).
|
|
15
|
+
//
|
|
16
|
+
// Versions for compileSdk / buildTools / NDK / Java are pulled from the
|
|
17
|
+
// host application's rootProject.ext via safeExtGet, so consumers can
|
|
18
|
+
// override them centrally without editing this file.
|
|
19
|
+
|
|
15
20
|
def safeExtGet(prop, fallback) {
|
|
16
21
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
17
22
|
}
|
|
23
|
+
|
|
18
24
|
buildscript {
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
// ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
|
|
25
|
+
// Standalone-only block: dependencies here only apply when the
|
|
26
|
+
// wrapper is opened directly in Android Studio. Consuming apps
|
|
27
|
+
// provide their own AGP / Kotlin classpath via their root build.
|
|
23
28
|
if (project == rootProject) {
|
|
24
29
|
repositories {
|
|
25
30
|
google()
|
|
26
|
-
|
|
31
|
+
mavenCentral()
|
|
27
32
|
}
|
|
28
33
|
dependencies {
|
|
29
|
-
classpath
|
|
34
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
35
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20"
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
}
|
|
39
|
+
|
|
33
40
|
apply plugin: 'com.android.library'
|
|
41
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
42
|
+
apply plugin: 'com.facebook.react'
|
|
43
|
+
|
|
34
44
|
android {
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
namespace "com.userleap.reactnative"
|
|
46
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 36)
|
|
47
|
+
buildToolsVersion safeExtGet('buildToolsVersion', '35.0.0')
|
|
48
|
+
|
|
37
49
|
compileOptions {
|
|
38
|
-
sourceCompatibility JavaVersion.
|
|
39
|
-
targetCompatibility JavaVersion.
|
|
50
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
51
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
kotlinOptions {
|
|
55
|
+
jvmTarget = '17'
|
|
40
56
|
}
|
|
57
|
+
|
|
41
58
|
defaultConfig {
|
|
42
|
-
minSdkVersion safeExtGet('minSdkVersion',
|
|
43
|
-
targetSdkVersion safeExtGet('targetSdkVersion',
|
|
44
|
-
versionCode 1
|
|
45
|
-
versionName "1.0"
|
|
59
|
+
minSdkVersion safeExtGet('minSdkVersion', 24)
|
|
60
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 36)
|
|
46
61
|
}
|
|
62
|
+
|
|
47
63
|
lintOptions {
|
|
48
64
|
abortOnError false
|
|
49
65
|
}
|
|
50
66
|
}
|
|
67
|
+
|
|
68
|
+
react {
|
|
69
|
+
jsRootDir = file("../src/")
|
|
70
|
+
libraryName = "RNUserLeapBindingsSpec"
|
|
71
|
+
codegenJavaPackageName = "com.userleap.reactnative"
|
|
72
|
+
}
|
|
73
|
+
|
|
51
74
|
repositories {
|
|
52
|
-
|
|
53
|
-
maven {
|
|
54
|
-
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
55
|
-
url "$rootDir/../node_modules/react-native/android"
|
|
56
|
-
}
|
|
57
|
-
maven {
|
|
58
|
-
// Android JSC is installed from npm
|
|
59
|
-
url "$rootDir/../node_modules/jsc-android/dist"
|
|
60
|
-
}
|
|
61
|
-
mavenCentral {
|
|
62
|
-
// We don't want to fetch react-native from Maven Central as there are
|
|
63
|
-
// older versions over there.
|
|
64
|
-
content {
|
|
65
|
-
excludeGroup "com.facebook.react"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
75
|
+
mavenCentral()
|
|
68
76
|
google()
|
|
69
77
|
maven { url 'https://www.jitpack.io' }
|
|
70
78
|
}
|
|
79
|
+
|
|
71
80
|
dependencies {
|
|
72
|
-
implementation 'com.facebook.react:react-native:+'
|
|
81
|
+
implementation 'com.facebook.react:react-native:+'
|
|
73
82
|
implementation "androidx.webkit:webkit:1.8.0"
|
|
74
83
|
|
|
75
84
|
// Use conditional logic for local vs Maven
|
|
76
85
|
if (findProject(':userleap-android-sdk') != null) {
|
|
77
86
|
implementation project(':userleap-android-sdk')
|
|
78
87
|
} else {
|
|
79
|
-
implementation ("com.userleap:userleap-android-sdk:2.
|
|
88
|
+
implementation ("com.userleap:userleap-android-sdk:2.27.0") // update this version on android updates
|
|
80
89
|
}
|
|
81
|
-
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
package com.userleap.reactnative
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import androidx.fragment.app.FragmentActivity
|
|
6
|
+
import com.facebook.react.bridge.Arguments
|
|
7
|
+
import com.facebook.react.bridge.Callback
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
|
+
import com.facebook.react.bridge.ReadableArray
|
|
10
|
+
import com.facebook.react.bridge.ReadableMap
|
|
11
|
+
import com.facebook.react.bridge.WritableMap
|
|
12
|
+
import com.userleap.EventListener
|
|
13
|
+
import com.userleap.EventName
|
|
14
|
+
import com.userleap.EventPayload
|
|
15
|
+
import com.userleap.SprigEvent
|
|
16
|
+
import com.userleap.SprigSurveyResult
|
|
17
|
+
import com.userleap.SurveyState
|
|
18
|
+
import com.userleap.UserLeap
|
|
19
|
+
import com.userleap.SprigUserInterfaceMode
|
|
20
|
+
import org.json.JSONObject
|
|
21
|
+
|
|
22
|
+
class UserLeapModule(reactContext: ReactApplicationContext) :
|
|
23
|
+
NativeUserLeapBindingsSpec(reactContext) {
|
|
24
|
+
|
|
25
|
+
private val reactContext: ReactApplicationContext = reactContext
|
|
26
|
+
|
|
27
|
+
// listenerLock guards activeListeners and `alive` so init-time registration and invalidate() cannot race.
|
|
28
|
+
private val listenerLock = Any()
|
|
29
|
+
private val activeListeners: MutableMap<EventName, EventListener> = HashMap()
|
|
30
|
+
@Volatile private var alive = true
|
|
31
|
+
|
|
32
|
+
init {
|
|
33
|
+
synchronized(listenerLock) {
|
|
34
|
+
registerAllNativeListeners()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Tear down SDK subscriptions here so a late callback can't hit a dead module ("emit after invalidation").
|
|
39
|
+
override fun invalidate() {
|
|
40
|
+
synchronized(listenerLock) {
|
|
41
|
+
alive = false
|
|
42
|
+
unregisterAllNativeListeners()
|
|
43
|
+
}
|
|
44
|
+
super.invalidate()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun toCamelCase(upperSnakeCase: String): String {
|
|
48
|
+
val parts = upperSnakeCase.lowercase().split("_")
|
|
49
|
+
val sb = StringBuilder(parts[0])
|
|
50
|
+
for (i in 1 until parts.size) {
|
|
51
|
+
sb.append(parts[i].replaceFirstChar { it.uppercase() })
|
|
52
|
+
}
|
|
53
|
+
return sb.toString()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private fun surveyResultToWritableMap(result: SprigSurveyResult): WritableMap {
|
|
57
|
+
val map = Arguments.createMap()
|
|
58
|
+
map.putString("surveyState", result.surveyState.name)
|
|
59
|
+
map.putInt("surveyId", result.surveyId)
|
|
60
|
+
return map
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun wrapResultCallback(callback: Callback?): ((SprigSurveyResult) -> Unit)? {
|
|
64
|
+
if (callback == null) return null
|
|
65
|
+
return { result -> callback.invoke(surveyResultToWritableMap(result)) }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private fun stringifyMap(map: ReadableMap?): Map<String, String> {
|
|
69
|
+
if (map == null) return emptyMap()
|
|
70
|
+
return map.toHashMap()
|
|
71
|
+
.entries
|
|
72
|
+
.filter { it.key != null && it.value != null }
|
|
73
|
+
.associate { it.key!! to it.value.toString() }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private fun getFragmentActivity(): FragmentActivity? {
|
|
77
|
+
val activity: Activity? = currentActivity
|
|
78
|
+
return activity as? FragmentActivity
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun visitorIdentifier(): Double {
|
|
82
|
+
return UserLeap.visitorIdentifier?.toDouble() ?: 0.0
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
override fun visitorIdentifierString(): String {
|
|
86
|
+
return UserLeap.visitorIdentifierString ?: ""
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override fun getSdkVersion(): String {
|
|
90
|
+
return UserLeap.sdkVersion
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun configure(environmentId: String, configuration: ReadableMap) {
|
|
94
|
+
UserLeap.configure(
|
|
95
|
+
reactContext,
|
|
96
|
+
environmentId,
|
|
97
|
+
stringifyMap(configuration),
|
|
98
|
+
getFragmentActivity()
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
override fun setPreviewKey(previewKey: String) {
|
|
103
|
+
UserLeap.setPreviewKey(previewKey)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override fun setUserIdentifier(identifier: String) {
|
|
107
|
+
UserLeap.setUserIdentifier(identifier)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override fun setEmailAddress(emailAddress: String) {
|
|
111
|
+
UserLeap.setEmailAddress(emailAddress)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
override fun logout() {
|
|
115
|
+
UserLeap.logout()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
override fun setVisitorAttribute(key: String, value: String) {
|
|
119
|
+
UserLeap.setVisitorAttribute(key, value)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override fun setVisitorAttributes(attributes: ReadableMap) {
|
|
123
|
+
UserLeap.setVisitorAttributes(stringifyMap(attributes))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
override fun removeVisitorAttributes(keys: ReadableArray) {
|
|
127
|
+
val list = keys.toArrayList().mapNotNull { it?.toString() }
|
|
128
|
+
UserLeap.removeVisitorAttributes(list)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
override fun setVisitorAttributesAndIdentify(
|
|
132
|
+
attributes: ReadableMap,
|
|
133
|
+
userId: String?,
|
|
134
|
+
partnerAnonymousId: String?
|
|
135
|
+
) {
|
|
136
|
+
UserLeap.setVisitorAttributes(
|
|
137
|
+
stringifyMap(attributes),
|
|
138
|
+
userId,
|
|
139
|
+
partnerAnonymousId
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override fun presentSurvey() {
|
|
144
|
+
UserLeap.presentSurvey(null)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override fun dismissActiveSurvey() {
|
|
148
|
+
UserLeap.dismissActiveSurvey()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
override fun pauseDisplayingSurveys() {
|
|
152
|
+
UserLeap.pauseDisplayingSurveys()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override fun unpauseDisplayingSurveys() {
|
|
156
|
+
UserLeap.unpauseDisplayingSurveys()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override fun trackAndPresent(eventName: String) {
|
|
160
|
+
// The SDK requires a FragmentActivity; bail out gracefully if the current activity isn't one.
|
|
161
|
+
val activity = getFragmentActivity()
|
|
162
|
+
if (activity == null) {
|
|
163
|
+
Log.w(TAG, "trackAndPresent('$eventName') skipped: current activity is not a FragmentActivity")
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
UserLeap.trackAndPresent(eventName, activity)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
override fun trackIdentifyAndPresent(
|
|
170
|
+
eventName: String,
|
|
171
|
+
userId: String?,
|
|
172
|
+
partnerAnonymousId: String?
|
|
173
|
+
) {
|
|
174
|
+
val activity = getFragmentActivity()
|
|
175
|
+
if (activity == null) {
|
|
176
|
+
Log.w(TAG, "trackIdentifyAndPresent('$eventName') skipped: current activity is not a FragmentActivity")
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
UserLeap.trackAndPresent(eventName, userId, partnerAnonymousId, activity)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override fun overrideUserInterfaceMode(mode: Double) {
|
|
183
|
+
val modeInt = mode.toInt()
|
|
184
|
+
SprigUserInterfaceMode.values().firstOrNull { it.value == modeInt }?.let {
|
|
185
|
+
UserLeap.overrideUserInterfaceMode(it)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
override fun trackEvent(eventName: String, surveyResultCallback: Callback) {
|
|
190
|
+
trackEventAndIdentify(eventName, null, null, surveyResultCallback)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
override fun trackEventWithProperties(
|
|
194
|
+
eventName: String,
|
|
195
|
+
userId: String?,
|
|
196
|
+
partnerAnonymousId: String?,
|
|
197
|
+
properties: ReadableMap,
|
|
198
|
+
surveyResultCallback: Callback
|
|
199
|
+
) {
|
|
200
|
+
val payload = EventPayload(
|
|
201
|
+
eventName,
|
|
202
|
+
userId,
|
|
203
|
+
partnerAnonymousId,
|
|
204
|
+
stringifyMap(properties),
|
|
205
|
+
wrapResultCallback(surveyResultCallback),
|
|
206
|
+
null, // shouldShowSurveyCallback
|
|
207
|
+
null // deprecated callback
|
|
208
|
+
)
|
|
209
|
+
UserLeap.track(payload)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
override fun trackEventAndIdentify(
|
|
213
|
+
eventName: String,
|
|
214
|
+
userId: String?,
|
|
215
|
+
partnerAnonymousId: String?,
|
|
216
|
+
surveyResultCallback: Callback
|
|
217
|
+
) {
|
|
218
|
+
val payload = EventPayload(
|
|
219
|
+
eventName,
|
|
220
|
+
userId,
|
|
221
|
+
partnerAnonymousId,
|
|
222
|
+
null, // properties
|
|
223
|
+
wrapResultCallback(surveyResultCallback),
|
|
224
|
+
null, // shouldShowSurveyCallback
|
|
225
|
+
null // deprecated callback
|
|
226
|
+
)
|
|
227
|
+
UserLeap.track(payload)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Callback is `Callback?`: the RN bridge can pass null at runtime, so guard before invoking it.
|
|
231
|
+
override fun track(eventName: String, surveyStateCallback: Callback?) {
|
|
232
|
+
trackAndIdentify(eventName, null, null, surveyStateCallback)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
override fun trackWithProperties(
|
|
236
|
+
eventName: String,
|
|
237
|
+
userId: String?,
|
|
238
|
+
partnerAnonymousId: String?,
|
|
239
|
+
properties: ReadableMap,
|
|
240
|
+
surveyStateCallback: Callback?
|
|
241
|
+
) {
|
|
242
|
+
UserLeap.track(
|
|
243
|
+
eventName,
|
|
244
|
+
userId,
|
|
245
|
+
partnerAnonymousId,
|
|
246
|
+
stringifyMap(properties)
|
|
247
|
+
) { state: SurveyState -> surveyStateCallback?.invoke(state.name) }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
override fun trackAndIdentify(
|
|
251
|
+
eventName: String,
|
|
252
|
+
userId: String?,
|
|
253
|
+
partnerAnonymousId: String?,
|
|
254
|
+
surveyStateCallback: Callback?
|
|
255
|
+
) {
|
|
256
|
+
UserLeap.track(eventName, userId, partnerAnonymousId) {
|
|
257
|
+
state: SurveyState -> surveyStateCallback?.invoke(state.name)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
override fun getSupportedEventNames(): com.facebook.react.bridge.WritableArray {
|
|
262
|
+
val array = Arguments.createArray()
|
|
263
|
+
for (eventName in EventName.values()) {
|
|
264
|
+
if (eventName == EventName.REPLAY_EVENTS_UPLOADED_COMPLETED) continue
|
|
265
|
+
array.pushString(toCamelCase(eventName.name))
|
|
266
|
+
}
|
|
267
|
+
return array
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Caller must hold listenerLock.
|
|
271
|
+
private fun registerAllNativeListeners() {
|
|
272
|
+
if (!alive) return
|
|
273
|
+
for (eventName in EventName.values()) {
|
|
274
|
+
// Skip the deprecated alias - it would double-fire alongside REPLAY_EVENTS_UPLOAD_COMPLETED.
|
|
275
|
+
if (eventName == EventName.REPLAY_EVENTS_UPLOADED_COMPLETED) continue
|
|
276
|
+
if (activeListeners.containsKey(eventName)) continue
|
|
277
|
+
|
|
278
|
+
val listener = EventListener { event -> emitEventToJS(event) }
|
|
279
|
+
activeListeners[eventName] = listener
|
|
280
|
+
try {
|
|
281
|
+
UserLeap.addEventListener(eventName, listener)
|
|
282
|
+
} catch (t: Throwable) {
|
|
283
|
+
Log.w(TAG, "Failed to register native listener for $eventName", t)
|
|
284
|
+
activeListeners.remove(eventName)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Caller must hold listenerLock.
|
|
290
|
+
private fun unregisterAllNativeListeners() {
|
|
291
|
+
for ((eventName, listener) in activeListeners) {
|
|
292
|
+
try {
|
|
293
|
+
UserLeap.removeEventListener(eventName, listener)
|
|
294
|
+
} catch (t: Throwable) {
|
|
295
|
+
Log.w(TAG, "Failed to remove native listener for $eventName", t)
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
activeListeners.clear()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private fun emitEventToJS(event: SprigEvent) {
|
|
302
|
+
if (!alive) return
|
|
303
|
+
|
|
304
|
+
val jsName = toCamelCase(event.name.name)
|
|
305
|
+
val json = buildEventJson(event)
|
|
306
|
+
val envelope = Arguments.createMap().apply {
|
|
307
|
+
putString("name", jsName)
|
|
308
|
+
putString("json", json)
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
emitOnSprigEvent(envelope)
|
|
312
|
+
} catch (t: Throwable) {
|
|
313
|
+
Log.w(TAG, "Failed to emit '$jsName' to JS", t)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private fun buildEventJson(event: SprigEvent): String {
|
|
318
|
+
return try {
|
|
319
|
+
if (event.name == EventName.LOGGING_EVENT) {
|
|
320
|
+
JSONObject()
|
|
321
|
+
.put("message", event.logMessage ?: "")
|
|
322
|
+
.put("level", event.logLevel.toString().lowercase())
|
|
323
|
+
.toString()
|
|
324
|
+
} else {
|
|
325
|
+
event.data?.toString() ?: "{}"
|
|
326
|
+
}
|
|
327
|
+
} catch (t: Throwable) {
|
|
328
|
+
Log.w(TAG, "Failed to build JSON payload for ${event.name}", t)
|
|
329
|
+
"{}"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
companion object {
|
|
334
|
+
private const val TAG = "UserLeapModule"
|
|
335
|
+
}
|
|
336
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -11,6 +11,84 @@ declare namespace UserLeap {
|
|
|
11
11
|
dark: number;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/** Lifecycle event names for {@link addEventListener}. */
|
|
15
|
+
const SprigEventName: {
|
|
16
|
+
sdkReady: "sdkReady";
|
|
17
|
+
visitorIdUpdated: "visitorIdUpdated";
|
|
18
|
+
surveyHeight: "surveyHeight";
|
|
19
|
+
surveyStateReturned: "surveyStateReturned";
|
|
20
|
+
surveyWillPresent: "surveyWillPresent";
|
|
21
|
+
surveyPresented: "surveyPresented";
|
|
22
|
+
surveyAppeared: "surveyAppeared";
|
|
23
|
+
questionAnswered: "questionAnswered";
|
|
24
|
+
surveyCloseRequested: "surveyCloseRequested";
|
|
25
|
+
surveyWillClose: "surveyWillClose";
|
|
26
|
+
surveyClosed: "surveyClosed";
|
|
27
|
+
surveyCompleted: "surveyCompleted";
|
|
28
|
+
replayCapture: "replayCapture";
|
|
29
|
+
replayCaptureStarted: "replayCaptureStarted";
|
|
30
|
+
replayCaptureStopped: "replayCaptureStopped";
|
|
31
|
+
replayCaptureCompleted: "replayCaptureCompleted";
|
|
32
|
+
replayRenderingCompleted: "replayRenderingCompleted";
|
|
33
|
+
replayUploadCompleted: "replayUploadCompleted";
|
|
34
|
+
replayEventsUploadCompleted: "replayEventsUploadCompleted";
|
|
35
|
+
loggingEvent: "loggingEvent";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type SprigEventNameValue =
|
|
39
|
+
| "sdkReady"
|
|
40
|
+
| "visitorIdUpdated"
|
|
41
|
+
| "surveyHeight"
|
|
42
|
+
| "surveyStateReturned"
|
|
43
|
+
| "surveyWillPresent"
|
|
44
|
+
| "surveyPresented"
|
|
45
|
+
| "surveyAppeared"
|
|
46
|
+
| "questionAnswered"
|
|
47
|
+
| "surveyCloseRequested"
|
|
48
|
+
| "surveyWillClose"
|
|
49
|
+
| "surveyClosed"
|
|
50
|
+
| "surveyCompleted"
|
|
51
|
+
| "replayCapture"
|
|
52
|
+
| "replayCaptureStarted"
|
|
53
|
+
| "replayCaptureStopped"
|
|
54
|
+
| "replayCaptureCompleted"
|
|
55
|
+
| "replayRenderingCompleted"
|
|
56
|
+
| "replayUploadCompleted"
|
|
57
|
+
| "replayEventsUploadCompleted"
|
|
58
|
+
| "loggingEvent";
|
|
59
|
+
|
|
60
|
+
interface SprigEventSubscription {
|
|
61
|
+
remove(): void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Severity tag on an emitted `loggingEvent` (read-only — host apps receive it,
|
|
66
|
+
* they don't set it). Android emits the real level; iOS has no log-level
|
|
67
|
+
* concept and always reports "info".
|
|
68
|
+
*/
|
|
69
|
+
type SprigLogLevel = "info" | "debug" | "warning" | "error" | "critical";
|
|
70
|
+
|
|
71
|
+
/** Canonical payload for `loggingEvent`. */
|
|
72
|
+
interface SprigLoggingEventData {
|
|
73
|
+
type: "loggingEvent";
|
|
74
|
+
message: string;
|
|
75
|
+
level: SprigLogLevel;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface SprigEventData {
|
|
79
|
+
/** Echoes the event name (e.g. "surveyPresented"). */
|
|
80
|
+
type?: string;
|
|
81
|
+
/** Survey identifier when the event is survey-scoped. */
|
|
82
|
+
surveyId?: number;
|
|
83
|
+
/** Survey state when the event carries one (e.g. surveyStateReturned). */
|
|
84
|
+
surveyState?: string;
|
|
85
|
+
/** Log message text on `loggingEvent`. */
|
|
86
|
+
message?: string;
|
|
87
|
+
/** Log level on `loggingEvent`. */
|
|
88
|
+
level?: SprigLogLevel;
|
|
89
|
+
[key: string]: any;
|
|
90
|
+
}
|
|
91
|
+
|
|
14
92
|
function overrideUserInterfaceMode(mode: SprigUserInterfaceMode): void;
|
|
15
93
|
function visitorIdentifier(): number;
|
|
16
94
|
function visitorIdentifierString(): string;
|
|
@@ -60,5 +138,17 @@ declare namespace UserLeap {
|
|
|
60
138
|
function unpauseDisplayingSurveys(): void;
|
|
61
139
|
function trackAndPresent(event: string): void;
|
|
62
140
|
function trackIdentifyAndPresent(event: string, userId: string | undefined, partnerAnonymousId: string | undefined): void;
|
|
141
|
+
|
|
142
|
+
/** Subscribe to a native SDK lifecycle event; `.remove()` unsubscribes only this listener. */
|
|
143
|
+
function addEventListener(
|
|
144
|
+
eventName: SprigEventNameValue,
|
|
145
|
+
callback: (data: SprigEventData) => void
|
|
146
|
+
): SprigEventSubscription;
|
|
147
|
+
|
|
148
|
+
/** Remove every listener for the given event name, or all listeners if no name is given. */
|
|
149
|
+
function removeAllEventListeners(eventName?: SprigEventNameValue): void;
|
|
150
|
+
|
|
151
|
+
/** Lifecycle event names this platform's SDK emits (cached; `[]` when unavailable). */
|
|
152
|
+
function getSupportedEventNames(): SprigEventNameValue[];
|
|
63
153
|
}
|
|
64
154
|
export default UserLeap;
|