@digia-engage/core 2.3.2 → 2.5.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/DigiaEngageReactNative.podspec +1 -1
- package/android/.project +28 -0
- package/android/build.gradle +1 -1
- package/android/local.properties +1 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaModule.kt +64 -6
- package/ios/DigiaEngageModule.m +8 -0
- package/ios/DigiaModule.swift +117 -8
- package/ios/RNEventBridgePlugin.swift +2 -0
- package/lib/commonjs/Digia.js +139 -100
- package/lib/commonjs/Digia.js.map +1 -1
- package/lib/commonjs/DigiaAnchorView.js +11 -1
- package/lib/commonjs/DigiaAnchorView.js.map +1 -1
- package/lib/commonjs/DigiaProvider.js +50 -1
- package/lib/commonjs/DigiaProvider.js.map +1 -1
- package/lib/commonjs/NativeDigiaEngage.js +3 -0
- package/lib/commonjs/NativeDigiaEngage.js.map +1 -1
- package/lib/commonjs/digiaAnchorRegistry.js +3 -1
- package/lib/commonjs/digiaAnchorRegistry.js.map +1 -1
- package/lib/commonjs/frequencyStore.js +3 -3
- package/lib/commonjs/frequencyStore.js.map +1 -1
- package/lib/commonjs/index.js +0 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/Digia.js +139 -100
- package/lib/module/Digia.js.map +1 -1
- package/lib/module/DigiaAnchorView.js +11 -1
- package/lib/module/DigiaAnchorView.js.map +1 -1
- package/lib/module/DigiaProvider.js +50 -1
- package/lib/module/DigiaProvider.js.map +1 -1
- package/lib/module/NativeDigiaEngage.js +3 -0
- package/lib/module/NativeDigiaEngage.js.map +1 -1
- package/lib/module/digiaAnchorRegistry.js +3 -1
- package/lib/module/digiaAnchorRegistry.js.map +1 -1
- package/lib/module/frequencyStore.js +3 -3
- package/lib/module/frequencyStore.js.map +1 -1
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/Digia.d.ts +17 -8
- package/lib/typescript/Digia.d.ts.map +1 -1
- package/lib/typescript/DigiaAnchorView.d.ts.map +1 -1
- package/lib/typescript/DigiaProvider.d.ts +3 -1
- package/lib/typescript/DigiaProvider.d.ts.map +1 -1
- package/lib/typescript/NativeDigiaEngage.d.ts +9 -0
- package/lib/typescript/NativeDigiaEngage.d.ts.map +1 -1
- package/lib/typescript/digiaAnchorRegistry.d.ts +1 -0
- package/lib/typescript/digiaAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/frequencyStore.d.ts +1 -1
- package/lib/typescript/frequencyStore.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -5
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/templateTypes.d.ts +24 -1
- package/lib/typescript/templateTypes.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +17 -13
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +8 -9
- package/src/Digia.ts +142 -114
- package/src/DigiaAnchorView.tsx +6 -1
- package/src/DigiaProvider.tsx +56 -1
- package/src/NativeDigiaEngage.ts +20 -0
- package/src/digiaAnchorRegistry.ts +3 -1
- package/src/frequencyStore.ts +4 -4
- package/src/index.ts +5 -5
- package/src/templateTypes.ts +31 -1
- package/src/types.ts +17 -13
|
@@ -28,7 +28,7 @@ Pod::Spec.new do |s|
|
|
|
28
28
|
s.dependency 'React-Core'
|
|
29
29
|
|
|
30
30
|
# ── Digia Engage iOS SDK ──────────────────────────────────────────────────
|
|
31
|
-
s.dependency 'DigiaEngage','~> 2.
|
|
31
|
+
s.dependency 'DigiaEngage','~> 2.4.0'
|
|
32
32
|
|
|
33
33
|
# ── New Architecture (Fabric / TurboModules) support ─────────────────────
|
|
34
34
|
install_modules_dependencies(s)
|
package/android/.project
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<projectDescription>
|
|
3
|
+
<name>digia-engage_core</name>
|
|
4
|
+
<comment>Project digia-engage_core created by Buildship.</comment>
|
|
5
|
+
<projects>
|
|
6
|
+
</projects>
|
|
7
|
+
<buildSpec>
|
|
8
|
+
<buildCommand>
|
|
9
|
+
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
|
10
|
+
<arguments>
|
|
11
|
+
</arguments>
|
|
12
|
+
</buildCommand>
|
|
13
|
+
</buildSpec>
|
|
14
|
+
<natures>
|
|
15
|
+
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
|
16
|
+
</natures>
|
|
17
|
+
<filteredResources>
|
|
18
|
+
<filter>
|
|
19
|
+
<id>1780322402778</id>
|
|
20
|
+
<name></name>
|
|
21
|
+
<type>30</type>
|
|
22
|
+
<matcher>
|
|
23
|
+
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
|
24
|
+
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
|
25
|
+
</matcher>
|
|
26
|
+
</filter>
|
|
27
|
+
</filteredResources>
|
|
28
|
+
</projectDescription>
|
package/android/build.gradle
CHANGED
|
@@ -71,7 +71,7 @@ android {
|
|
|
71
71
|
|
|
72
72
|
dependencies {
|
|
73
73
|
// Digia Engage Android library
|
|
74
|
-
implementation 'tech.digia:engage:2.
|
|
74
|
+
implementation 'tech.digia:engage:2.2.1'
|
|
75
75
|
|
|
76
76
|
// ── React Native ─────────────────────────────────────────────────────────
|
|
77
77
|
// React Native is provided by the host app; mark as compileOnly so it is
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sdk.dir=/Users/ram/Library/Android/sdk
|
|
@@ -29,6 +29,7 @@ import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
|
29
29
|
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
|
30
30
|
import androidx.savedstate.SavedStateRegistryOwner
|
|
31
31
|
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
32
|
+
import com.digia.engage.CEPTriggerPayload
|
|
32
33
|
import com.digia.engage.DiagnosticReport
|
|
33
34
|
import com.digia.engage.Digia
|
|
34
35
|
import com.digia.engage.DigiaCEPDelegate
|
|
@@ -126,6 +127,54 @@ internal class DigiaModule(
|
|
|
126
127
|
Digia.setCurrentScreen(name)
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
// ─── Analytics identity ───────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
@ReactMethod
|
|
133
|
+
fun setUserId(userId: String) {
|
|
134
|
+
Digia.setUserId(userId)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@ReactMethod
|
|
138
|
+
fun clearUserId() {
|
|
139
|
+
Digia.clearUserId()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ─── Analytics event forwarding (guide / JS-rendered campaigns) ───────────
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Records an analytics event originating from JS-rendered campaigns (guides).
|
|
146
|
+
* Native campaigns (nudge, inline, survey) are tracked internally by the SDK.
|
|
147
|
+
*/
|
|
148
|
+
@ReactMethod
|
|
149
|
+
fun trackEvent(
|
|
150
|
+
eventType: String,
|
|
151
|
+
campaignId: String,
|
|
152
|
+
campaignKey: String,
|
|
153
|
+
campaignType: String,
|
|
154
|
+
elementId: String?,
|
|
155
|
+
) {
|
|
156
|
+
android.util.Log.d("DigiaAnalytics", "[trackEvent] RN bridge received: type=$eventType campaignId=$campaignId campaignKey=$campaignKey campaignType=$campaignType elementId=$elementId")
|
|
157
|
+
val event = when (eventType) {
|
|
158
|
+
"impressed" -> DigiaExperienceEvent.Impressed
|
|
159
|
+
"clicked" -> DigiaExperienceEvent.Clicked(elementId)
|
|
160
|
+
"dismissed" -> DigiaExperienceEvent.Dismissed
|
|
161
|
+
else -> {
|
|
162
|
+
android.util.Log.w("DigiaAnalytics", "[trackEvent] unknown eventType='$eventType' — dropped")
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
val payload = InAppPayload(
|
|
167
|
+
id = campaignKey,
|
|
168
|
+
content = mapOf(
|
|
169
|
+
"campaign_id" to campaignId,
|
|
170
|
+
"campaign_key" to campaignKey,
|
|
171
|
+
"campaign_type" to campaignType,
|
|
172
|
+
),
|
|
173
|
+
)
|
|
174
|
+
android.util.Log.d("DigiaAnalytics", "[trackEvent] forwarding to Digia.captureAnalyticsEvent: event=${event::class.simpleName}")
|
|
175
|
+
Digia.captureAnalyticsEvent(event, payload)
|
|
176
|
+
}
|
|
177
|
+
|
|
129
178
|
// ─── triggerCampaign ──────────────────────────────────────────────────────
|
|
130
179
|
|
|
131
180
|
/**
|
|
@@ -138,11 +187,20 @@ internal class DigiaModule(
|
|
|
138
187
|
@ReactMethod
|
|
139
188
|
fun triggerCampaign(id: String, content: ReadableMap, cepContext: ReadableMap) {
|
|
140
189
|
val delegate = rnPlugin.delegate ?: return
|
|
190
|
+
val contentMap = content.toHashMap().toMap()
|
|
191
|
+
val campaignKey = (contentMap["digia_campaign_key"] as? String)
|
|
192
|
+
?: (contentMap["campaign_key"] as? String)
|
|
193
|
+
?: id
|
|
194
|
+
@Suppress("UNCHECKED_CAST")
|
|
195
|
+
val variables = (contentMap["variables"] as? Map<*, *>)
|
|
196
|
+
?.entries
|
|
197
|
+
?.associate { it.key.toString() to it.value?.toString().orEmpty() }
|
|
141
198
|
delegate.onCampaignTriggered(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
199
|
+
CEPTriggerPayload(
|
|
200
|
+
cepCampaignId = id,
|
|
201
|
+
campaignKey = campaignKey,
|
|
202
|
+
cepMetadata = cepContext.toHashMap().toMap(),
|
|
203
|
+
variables = variables,
|
|
146
204
|
)
|
|
147
205
|
)
|
|
148
206
|
}
|
|
@@ -277,10 +335,10 @@ internal class RNEventBridgePlugin(
|
|
|
277
335
|
/* forwarded by Digia.setCurrentScreen() on the native side */
|
|
278
336
|
}
|
|
279
337
|
|
|
280
|
-
override fun notifyEvent(event: DigiaExperienceEvent, payload:
|
|
338
|
+
override fun notifyEvent(event: DigiaExperienceEvent, payload: CEPTriggerPayload) {
|
|
281
339
|
val params =
|
|
282
340
|
Arguments.createMap().apply {
|
|
283
|
-
putString("campaignId", payload.
|
|
341
|
+
putString("campaignId", payload.cepCampaignId)
|
|
284
342
|
when (event) {
|
|
285
343
|
is DigiaExperienceEvent.Impressed -> putString("type", "impressed")
|
|
286
344
|
is DigiaExperienceEvent.Clicked -> {
|
package/ios/DigiaEngageModule.m
CHANGED
|
@@ -34,6 +34,14 @@ RCT_EXTERN_METHOD(registerBridge)
|
|
|
34
34
|
|
|
35
35
|
RCT_EXTERN_METHOD(setCurrentScreen : (NSString *)name)
|
|
36
36
|
|
|
37
|
+
RCT_EXTERN_METHOD(setUserId : (NSString *)userId)
|
|
38
|
+
|
|
39
|
+
RCT_EXTERN_METHOD(clearUserId)
|
|
40
|
+
|
|
41
|
+
RCT_EXTERN_METHOD(trackEvent : (NSString *)eventType campaignId : (NSString *)
|
|
42
|
+
campaignId campaignKey : (NSString *)campaignKey campaignType
|
|
43
|
+
: (NSString *)campaignType elementId : (NSString *)elementId)
|
|
44
|
+
|
|
37
45
|
RCT_EXTERN_METHOD(triggerCampaign : (NSString *)id content : (NSDictionary *)
|
|
38
46
|
content cepContext : (NSDictionary *)cepContext)
|
|
39
47
|
|
package/ios/DigiaModule.swift
CHANGED
|
@@ -78,13 +78,18 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
78
78
|
default: logLevelValue = .error
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
let cleanBaseUrl = baseUrl.flatMap { url -> String? in
|
|
82
|
+
var s = url.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
83
|
+
.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
|
84
|
+
if s.hasSuffix("/api/v1") { s = String(s.dropLast(7)) }
|
|
85
|
+
return s.isEmpty ? nil : s
|
|
86
|
+
}
|
|
87
|
+
|
|
81
88
|
let config = DigiaConfig(
|
|
82
89
|
apiKey: projectId,
|
|
83
90
|
logLevel: logLevelValue,
|
|
84
91
|
environment: envValue,
|
|
85
|
-
developerConfig:
|
|
86
|
-
$0.isEmpty ? nil : DigiaDeveloperConfig(baseURL: $0)
|
|
87
|
-
},
|
|
92
|
+
developerConfig: cleanBaseUrl.map { DigiaDeveloperConfig(baseURL: $0) },
|
|
88
93
|
fontFamily: fontFamily.flatMap { $0.isEmpty ? nil : $0 }
|
|
89
94
|
)
|
|
90
95
|
|
|
@@ -109,10 +114,27 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
109
114
|
@objc
|
|
110
115
|
func registerBridge() {
|
|
111
116
|
Task { @MainActor in
|
|
117
|
+
// Dismiss any stale overlay left over from the previous JS session.
|
|
118
|
+
Digia.dismissActiveNudge()
|
|
119
|
+
|
|
120
|
+
// After a JS reload, re-bring the overlay host to the front.
|
|
121
|
+
// Expo/RN may have added views during the reload cycle that sit on
|
|
122
|
+
// top of the host, causing the SwiftUI layer to be unreachable by
|
|
123
|
+
// touch even when hasActiveOverlay = true.
|
|
124
|
+
if let rootVC = UIApplication.shared.connectedScenes
|
|
125
|
+
.compactMap({ ($0 as? UIWindowScene)?.keyWindow?.rootViewController })
|
|
126
|
+
.first,
|
|
127
|
+
let hostView = rootVC.view.viewWithTag(Self.overlayMountTag) {
|
|
128
|
+
rootVC.view.bringSubviewToFront(hostView)
|
|
129
|
+
}
|
|
130
|
+
|
|
112
131
|
Digia.register(self.rnPlugin)
|
|
132
|
+
print("[DigiaRN] registerBridge: rnPlugin registered, delegate=\(self.rnPlugin.delegate != nil ? "set" : "nil")")
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
|
|
136
|
+
private static let overlayMountTag = 0xD19140
|
|
137
|
+
|
|
116
138
|
// ────────────────────────────────────────────────────────────────────────
|
|
117
139
|
// MARK: - setCurrentScreen
|
|
118
140
|
|
|
@@ -123,6 +145,53 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
123
145
|
// Digia.setCurrentScreen(name)
|
|
124
146
|
}
|
|
125
147
|
|
|
148
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
149
|
+
// MARK: - Analytics identity
|
|
150
|
+
|
|
151
|
+
/// Sets the authenticated user ID for analytics identity stitching.
|
|
152
|
+
///
|
|
153
|
+
/// Mirrors Android's DigiaModule.setUserId(). The public iOS SDK does not
|
|
154
|
+
/// expose Digia.setUserId yet, so this is a no-op placeholder (like
|
|
155
|
+
/// setCurrentScreen) that exists to satisfy the JS NativeDigiaEngage spec —
|
|
156
|
+
/// without it, `getModule()?.setUserId(...)` throws on iOS. Activate the body
|
|
157
|
+
/// once the iOS SDK adds the public API.
|
|
158
|
+
@objc
|
|
159
|
+
func setUserId(_ userId: String) {
|
|
160
|
+
// Digia.setUserId(userId)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// Clears the user ID (e.g. on logout). No-op placeholder — see setUserId.
|
|
164
|
+
@objc
|
|
165
|
+
func clearUserId() {
|
|
166
|
+
// Digia.clearUserId()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
170
|
+
// MARK: - trackEvent (guide / JS-rendered campaigns)
|
|
171
|
+
|
|
172
|
+
/// Records an analytics event originating from JS-rendered campaigns
|
|
173
|
+
/// (guides / tooltips / spotlights). Native campaigns (nudge, inline,
|
|
174
|
+
/// survey) are tracked internally by the SDK.
|
|
175
|
+
///
|
|
176
|
+
/// Mirrors Android's DigiaModule.trackEvent(), which forwards to
|
|
177
|
+
/// Digia.captureAnalyticsEvent(event, payload). The public iOS SDK does not
|
|
178
|
+
/// expose an equivalent capture API yet, so iOS analytics for JS-rendered
|
|
179
|
+
/// campaigns are not forwarded — this method logs the event and otherwise
|
|
180
|
+
/// no-ops. It MUST exist regardless: without it,
|
|
181
|
+
/// `getModule()?.trackEvent(...)` throws "trackEvent is not a function" and
|
|
182
|
+
/// crashes the JS render tree (DigiaProvider). Wire up the body once the iOS
|
|
183
|
+
/// SDK adds a public capture API.
|
|
184
|
+
@objc
|
|
185
|
+
func trackEvent(
|
|
186
|
+
_ eventType: String,
|
|
187
|
+
campaignId: String,
|
|
188
|
+
campaignKey: String,
|
|
189
|
+
campaignType: String,
|
|
190
|
+
elementId: String?
|
|
191
|
+
) {
|
|
192
|
+
print("[DigiaRN] trackEvent type=\(eventType) campaignId=\(campaignId) campaignKey=\(campaignKey) campaignType=\(campaignType) elementId=\(elementId ?? "nil") — iOS capture API not available, dropping")
|
|
193
|
+
}
|
|
194
|
+
|
|
126
195
|
// ────────────────────────────────────────────────────────────────────────
|
|
127
196
|
// MARK: - triggerCampaign
|
|
128
197
|
|
|
@@ -140,10 +209,17 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
140
209
|
let content = buildInAppPayloadContent(from: contentMap)
|
|
141
210
|
let cepContext = (cepContextMap as? [String: String]) ?? [:]
|
|
142
211
|
let payload = InAppPayload(id: id, content: content, cepContext: cepContext)
|
|
212
|
+
print("[DigiaRN] triggerCampaign id=\(id) campaignKey=\(content.campaignKey ?? "nil")")
|
|
143
213
|
|
|
144
214
|
Task { @MainActor in
|
|
145
|
-
guard let delegate = self.rnPlugin.delegate else {
|
|
215
|
+
guard let delegate = self.rnPlugin.delegate else {
|
|
216
|
+
print("[DigiaRN] triggerCampaign: delegate is nil — registerBridge() may not have run yet")
|
|
217
|
+
return
|
|
218
|
+
}
|
|
146
219
|
delegate.onCampaignTriggered(payload)
|
|
220
|
+
Task { @MainActor in
|
|
221
|
+
print("[DigiaRN] triggerCampaign post-call: hasActiveOverlay=\(Digia.hasActiveOverlay)")
|
|
222
|
+
}
|
|
147
223
|
}
|
|
148
224
|
}
|
|
149
225
|
|
|
@@ -213,12 +289,11 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
213
289
|
else { return }
|
|
214
290
|
|
|
215
291
|
// Guard against double-mounting (e.g. fast-refresh).
|
|
216
|
-
|
|
217
|
-
if rootVC.view.viewWithTag(mountTag) != nil { return }
|
|
292
|
+
if rootVC.view.viewWithTag(Self.overlayMountTag) != nil { return }
|
|
218
293
|
|
|
219
294
|
let hc = UIHostingController(rootView: DigiaHostWrapperView())
|
|
220
295
|
let hostView = DigiaRootOverlayView(hostingController: hc)
|
|
221
|
-
hostView.tag =
|
|
296
|
+
hostView.tag = Self.overlayMountTag
|
|
222
297
|
hostView.translatesAutoresizingMaskIntoConstraints = false
|
|
223
298
|
hostView.backgroundColor = .clear
|
|
224
299
|
|
|
@@ -254,6 +329,7 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
254
329
|
let screenId = map["screenId"] as? String
|
|
255
330
|
let campaignKey =
|
|
256
331
|
(map["campaignKey"] as? String) ?? (map["campaign_key"] as? String)
|
|
332
|
+
?? (map["digia_campaign_key"] as? String)
|
|
257
333
|
?? (map["digiaKey"] as? String)
|
|
258
334
|
var type = (map["type"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
259
335
|
if type.isEmpty {
|
|
@@ -266,6 +342,13 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
266
342
|
return raw.compactMapValues { JSONValue(rawValue: $0) }
|
|
267
343
|
}()
|
|
268
344
|
|
|
345
|
+
// CEP trigger variables for `{{ }}` interpolation. CleverTap's nudge
|
|
346
|
+
// mapper puts them at `content.variables` (top-level); the command/inline
|
|
347
|
+
// mappers may nest them under `args.variables`. Mirror the JS bridge's
|
|
348
|
+
// `_extractVariables` (content.variables first, then args.variables).
|
|
349
|
+
let variables = Self.variableMap(map["variables"])
|
|
350
|
+
?? Self.variableMap((map["args"] as? [String: Any])?["variables"])
|
|
351
|
+
|
|
269
352
|
return InAppPayloadContent(
|
|
270
353
|
type: type,
|
|
271
354
|
placementKey: pk,
|
|
@@ -275,9 +358,35 @@ final class DigiaModule: RCTEventEmitter {
|
|
|
275
358
|
command: command,
|
|
276
359
|
args: args,
|
|
277
360
|
screenId: screenId,
|
|
278
|
-
campaignKey: campaignKey
|
|
361
|
+
campaignKey: campaignKey,
|
|
362
|
+
variables: variables
|
|
279
363
|
)
|
|
280
364
|
}
|
|
365
|
+
|
|
366
|
+
/// Coerces a raw `variables` value into a `[String: String]` map, stringifying
|
|
367
|
+
/// scalar values (string / number / bool) and dropping anything else. Returns
|
|
368
|
+
/// nil for a missing or empty map. Mirrors the JS `parseVariableMap`.
|
|
369
|
+
private static func variableMap(_ raw: Any?) -> [String: String]? {
|
|
370
|
+
guard let dict = raw as? [String: Any] else { return nil }
|
|
371
|
+
var result: [String: String] = [:]
|
|
372
|
+
for (key, value) in dict {
|
|
373
|
+
switch value {
|
|
374
|
+
case let string as String:
|
|
375
|
+
result[key] = string
|
|
376
|
+
case let number as NSNumber:
|
|
377
|
+
// Distinguish a boxed bool from a numeric NSNumber so `true`
|
|
378
|
+
// stays "true" rather than "1".
|
|
379
|
+
if CFGetTypeID(number) == CFBooleanGetTypeID() {
|
|
380
|
+
result[key] = number.boolValue ? "true" : "false"
|
|
381
|
+
} else {
|
|
382
|
+
result[key] = number.stringValue
|
|
383
|
+
}
|
|
384
|
+
default:
|
|
385
|
+
continue
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return result.isEmpty ? nil : result
|
|
389
|
+
}
|
|
281
390
|
}
|
|
282
391
|
|
|
283
392
|
// MARK: - DigiaRootOverlayView
|
|
@@ -54,6 +54,8 @@ internal final class RNEventBridgePlugin: NSObject, DigiaCEPPlugin {
|
|
|
54
54
|
case .dismissed:
|
|
55
55
|
body["type"] = "dismissed"
|
|
56
56
|
}
|
|
57
|
+
let hasEmitter = eventEmitter != nil
|
|
58
|
+
print("[DigiaRN] RNEventBridgePlugin.notifyEvent type=\(body["type"] ?? "?") campaignId=\(payload.id) hasEmitter=\(hasEmitter)")
|
|
57
59
|
eventEmitter?.sendEvent(withName: "digiaEngageEvent", body: body)
|
|
58
60
|
}
|
|
59
61
|
|