@digia-engage/core 1.0.0-beta.1
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 +21 -0
- package/README.md +277 -0
- package/android/build.gradle +82 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradlew +185 -0
- package/android/gradlew.bat +89 -0
- package/android/settings.gradle +33 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaModule.kt +234 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaPackage.kt +69 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaSlotViewManager.kt +64 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaViewManager.kt +63 -0
- package/ios/DigiaEngageModule.m +71 -0
- package/lib/commonjs/Digia.js +106 -0
- package/lib/commonjs/Digia.js.map +1 -0
- package/lib/commonjs/DigiaHostView.js +73 -0
- package/lib/commonjs/DigiaHostView.js.map +1 -0
- package/lib/commonjs/DigiaSlotView.js +73 -0
- package/lib/commonjs/DigiaSlotView.js.map +1 -0
- package/lib/commonjs/NativeDigiaModule.js +56 -0
- package/lib/commonjs/NativeDigiaModule.js.map +1 -0
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/Digia.js +100 -0
- package/lib/module/Digia.js.map +1 -0
- package/lib/module/DigiaHostView.js +67 -0
- package/lib/module/DigiaHostView.js.map +1 -0
- package/lib/module/DigiaSlotView.js +66 -0
- package/lib/module/DigiaSlotView.js.map +1 -0
- package/lib/module/NativeDigiaModule.js +51 -0
- package/lib/module/NativeDigiaModule.js.map +1 -0
- package/lib/module/index.js +15 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/Digia.d.ts +62 -0
- package/lib/typescript/Digia.d.ts.map +1 -0
- package/lib/typescript/DigiaHostView.d.ts +40 -0
- package/lib/typescript/DigiaHostView.d.ts.map +1 -0
- package/lib/typescript/DigiaSlotView.d.ts +52 -0
- package/lib/typescript/DigiaSlotView.d.ts.map +1 -0
- package/lib/typescript/NativeDigiaModule.d.ts +45 -0
- package/lib/typescript/NativeDigiaModule.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +15 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +58 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/package.json +89 -0
- package/src/Digia.ts +104 -0
- package/src/DigiaHostView.tsx +83 -0
- package/src/DigiaSlotView.tsx +79 -0
- package/src/NativeDigiaModule.ts +86 -0
- package/src/index.ts +15 -0
- package/src/types.ts +61 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaModule
|
|
3
|
+
*
|
|
4
|
+
* React Native NativeModule that bridges the Digia Engage Android SDK.
|
|
5
|
+
*
|
|
6
|
+
* Exposed methods (callable from JS via NativeModules.DigiaEngageModule):
|
|
7
|
+
*
|
|
8
|
+
* initialize(apiKey, environment, logLevel): Promise<void> register(): void setCurrentScreen(name):
|
|
9
|
+
* void triggerCampaign(id, content, cepContext): void invalidateCampaign(campaignId): void
|
|
10
|
+
*
|
|
11
|
+
* Architecture ──────────── The RN bridge mirrors the native Digia.initialize / Digia.register /
|
|
12
|
+
* Digia.setCurrentScreen flow exactly. An internal [RNEventBridgePlugin] is the single native
|
|
13
|
+
* DigiaCEPPlugin registered via Digia.register().
|
|
14
|
+
*
|
|
15
|
+
* When the SDK calls plugin.setup(delegate), the bridge stores that delegate reference. JS plugins
|
|
16
|
+
* that need to push campaigns into the Compose overlay call triggerCampaign / invalidateCampaign
|
|
17
|
+
* which forward to delegate.onCampaignTriggered / delegate.onCampaignInvalidated.
|
|
18
|
+
*
|
|
19
|
+
* Overlay lifecycle events (impressed / clicked / dismissed) are forwarded from the native
|
|
20
|
+
* plugin.notifyEvent() to JS via DeviceEventEmitter so that pure-JS CEP plugins (e.g.
|
|
21
|
+
* DigiaMoEngagePlugin) can report analytics.
|
|
22
|
+
*/
|
|
23
|
+
package com.digia.engage.rn
|
|
24
|
+
|
|
25
|
+
import android.widget.FrameLayout
|
|
26
|
+
import androidx.lifecycle.LifecycleOwner
|
|
27
|
+
import androidx.lifecycle.ViewModelStoreOwner
|
|
28
|
+
import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
29
|
+
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
|
30
|
+
import androidx.savedstate.SavedStateRegistryOwner
|
|
31
|
+
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
32
|
+
import com.digia.engage.DiagnosticReport
|
|
33
|
+
import com.digia.engage.Digia
|
|
34
|
+
import com.digia.engage.DigiaCEPDelegate
|
|
35
|
+
import com.digia.engage.DigiaCEPPlugin
|
|
36
|
+
import com.digia.engage.DigiaConfig
|
|
37
|
+
import com.digia.engage.DigiaEnvironment
|
|
38
|
+
import com.digia.engage.DigiaExperienceEvent
|
|
39
|
+
import com.digia.engage.DigiaHostView
|
|
40
|
+
import com.digia.engage.DigiaLogLevel
|
|
41
|
+
import com.digia.engage.InAppPayload
|
|
42
|
+
import com.facebook.react.bridge.Arguments
|
|
43
|
+
import com.facebook.react.bridge.Promise
|
|
44
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
45
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
46
|
+
import com.facebook.react.bridge.ReactMethod
|
|
47
|
+
import com.facebook.react.bridge.ReadableMap
|
|
48
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
49
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
50
|
+
|
|
51
|
+
internal class DigiaModule(
|
|
52
|
+
private val reactContext: ReactApplicationContext,
|
|
53
|
+
) : ReactContextBaseJavaModule(reactContext) {
|
|
54
|
+
|
|
55
|
+
private val rnPlugin = RNEventBridgePlugin(reactContext)
|
|
56
|
+
|
|
57
|
+
override fun getName(): String = MODULE_NAME
|
|
58
|
+
|
|
59
|
+
// ─── initialize ───────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
@ReactMethod
|
|
62
|
+
fun initialize(apiKey: String, environment: String, logLevel: String, promise: Promise) {
|
|
63
|
+
try {
|
|
64
|
+
val config =
|
|
65
|
+
DigiaConfig(
|
|
66
|
+
apiKey = apiKey,
|
|
67
|
+
environment =
|
|
68
|
+
when (environment.lowercase()) {
|
|
69
|
+
"sandbox" -> DigiaEnvironment.SANDBOX
|
|
70
|
+
else -> DigiaEnvironment.PRODUCTION
|
|
71
|
+
},
|
|
72
|
+
logLevel =
|
|
73
|
+
when (logLevel.lowercase()) {
|
|
74
|
+
"verbose" -> DigiaLogLevel.VERBOSE
|
|
75
|
+
"none" -> DigiaLogLevel.NONE
|
|
76
|
+
else -> DigiaLogLevel.ERROR
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
Digia.initialize(reactContext.applicationContext, config)
|
|
80
|
+
|
|
81
|
+
UiThreadUtil.runOnUiThread {
|
|
82
|
+
mountDigiaHost()
|
|
83
|
+
promise.resolve(null)
|
|
84
|
+
}
|
|
85
|
+
} catch (e: Exception) {
|
|
86
|
+
promise.reject("DIGIA_INIT_ERROR", e.message ?: "Initialisation failed", e)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── register ─────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Registers [RNEventBridgePlugin] with the native Digia SDK.
|
|
94
|
+
*
|
|
95
|
+
* This is bridge infrastructure — not a user-facing CEP plugin. Called once by the JS
|
|
96
|
+
* `Digia.register()` wrapper on the first plugin registration so that
|
|
97
|
+
* [RNEventBridgePlugin.delegate] is populated before any triggerCampaign / invalidateCampaign
|
|
98
|
+
* calls arrive from JS.
|
|
99
|
+
*/
|
|
100
|
+
@ReactMethod
|
|
101
|
+
fun registerBridge() {
|
|
102
|
+
Digia.register(rnPlugin)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ─── setCurrentScreen ─────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
@ReactMethod
|
|
108
|
+
fun setCurrentScreen(name: String) {
|
|
109
|
+
Digia.setCurrentScreen(name)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── triggerCampaign ──────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Forwards a campaign payload to the native DigiaCEPDelegate.
|
|
116
|
+
*
|
|
117
|
+
* This is called by the JS DigiaDelegate.onCampaignTriggered() implementation when a JS CEP
|
|
118
|
+
* plugin (e.g. DigiaMoEngagePlugin) delivers a campaign. The delegate routes it into the
|
|
119
|
+
* Compose overlay for rendering.
|
|
120
|
+
*/
|
|
121
|
+
@ReactMethod
|
|
122
|
+
fun triggerCampaign(id: String, content: ReadableMap, cepContext: ReadableMap) {
|
|
123
|
+
val delegate = rnPlugin.delegate ?: return
|
|
124
|
+
delegate.onCampaignTriggered(
|
|
125
|
+
InAppPayload(
|
|
126
|
+
id = id,
|
|
127
|
+
content = content.toHashMap().toMap(),
|
|
128
|
+
cepContext = cepContext.toHashMap().toMap(),
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─── invalidateCampaign ───────────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
/** Forwards a campaign invalidation to the native DigiaCEPDelegate. */
|
|
136
|
+
@ReactMethod
|
|
137
|
+
fun invalidateCampaign(campaignId: String) {
|
|
138
|
+
rnPlugin.delegate?.onCampaignInvalidated(campaignId)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Internal: mount the Compose overlay host ─────────────────────────────
|
|
142
|
+
|
|
143
|
+
private fun mountDigiaHost() {
|
|
144
|
+
val activity = reactContext.currentActivity ?: return
|
|
145
|
+
|
|
146
|
+
val contentRoot = activity.window.decorView.findViewWithTag<DigiaHostView>(DIGIA_HOST_TAG)
|
|
147
|
+
if (contentRoot != null) return
|
|
148
|
+
|
|
149
|
+
val composeView =
|
|
150
|
+
DigiaHostView(activity).apply {
|
|
151
|
+
tag = DIGIA_HOST_TAG
|
|
152
|
+
if (activity is LifecycleOwner) setViewTreeLifecycleOwner(activity)
|
|
153
|
+
if (activity is ViewModelStoreOwner) setViewTreeViewModelStoreOwner(activity)
|
|
154
|
+
if (activity is SavedStateRegistryOwner)
|
|
155
|
+
setViewTreeSavedStateRegistryOwner(activity)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
activity.addContentView(
|
|
159
|
+
composeView,
|
|
160
|
+
FrameLayout.LayoutParams(
|
|
161
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
162
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
companion object {
|
|
168
|
+
const val MODULE_NAME = "DigiaEngageModule"
|
|
169
|
+
private const val DIGIA_HOST_TAG = "digia_host_compose_view"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* RNEventBridgePlugin
|
|
175
|
+
*
|
|
176
|
+
* The single native DigiaCEPPlugin used in React Native.
|
|
177
|
+
*
|
|
178
|
+
* When Digia.register(rnPlugin) is called, the SDK calls setup(delegate) which gives us the
|
|
179
|
+
* DigiaCEPDelegate reference. This delegate is used by triggerCampaign / invalidateCampaign bridge
|
|
180
|
+
* methods to push campaigns into the native rendering engine.
|
|
181
|
+
*
|
|
182
|
+
* Overlay lifecycle events (impressed / clicked / dismissed) received via notifyEvent() are emitted
|
|
183
|
+
* to JS as DeviceEventEmitter events so that JS CEP plugins can report analytics back to their
|
|
184
|
+
* platform.
|
|
185
|
+
*/
|
|
186
|
+
internal class RNEventBridgePlugin(
|
|
187
|
+
private val reactContext: ReactApplicationContext,
|
|
188
|
+
) : DigiaCEPPlugin {
|
|
189
|
+
|
|
190
|
+
override val identifier: String = "rn-event-bridge"
|
|
191
|
+
|
|
192
|
+
/** Delegate received from the SDK via setup(). Used by DigiaModule bridge methods. */
|
|
193
|
+
var delegate: DigiaCEPDelegate? = null
|
|
194
|
+
private set
|
|
195
|
+
|
|
196
|
+
private fun emit(event: String, params: com.facebook.react.bridge.WritableMap) {
|
|
197
|
+
if (reactContext.hasActiveReactInstance()) {
|
|
198
|
+
reactContext
|
|
199
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
200
|
+
.emit(event, params)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
override fun setup(delegate: DigiaCEPDelegate) {
|
|
205
|
+
this.delegate = delegate
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
override fun forwardScreen(name: String) {
|
|
209
|
+
/* forwarded by Digia.setCurrentScreen() on the native side */
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
override fun notifyEvent(event: DigiaExperienceEvent, payload: InAppPayload) {
|
|
213
|
+
val params =
|
|
214
|
+
Arguments.createMap().apply {
|
|
215
|
+
putString("campaignId", payload.id)
|
|
216
|
+
when (event) {
|
|
217
|
+
is DigiaExperienceEvent.Impressed -> putString("type", "impressed")
|
|
218
|
+
is DigiaExperienceEvent.Clicked -> {
|
|
219
|
+
putString("type", "clicked")
|
|
220
|
+
event.elementId?.let { putString("elementId", it) }
|
|
221
|
+
}
|
|
222
|
+
is DigiaExperienceEvent.Dismissed -> putString("type", "dismissed")
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
emit("digiaOverlayEvent", params)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
override fun teardown() {
|
|
229
|
+
delegate = null
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
override fun healthCheck(): DiagnosticReport =
|
|
233
|
+
DiagnosticReport(isHealthy = true, metadata = mapOf("identifier" to identifier))
|
|
234
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaPackage
|
|
3
|
+
*
|
|
4
|
+
* Registers the Digia Engage native module and view managers with React Native.
|
|
5
|
+
*
|
|
6
|
+
* Extends TurboReactPackage so the package works transparently on both Old Architecture (bridge)
|
|
7
|
+
* and New Architecture (TurboModules / JSI).
|
|
8
|
+
*
|
|
9
|
+
* Why is this needed? ──────────────────── React Native's auto-linker reads react-native.config.js,
|
|
10
|
+
* which declares `packageInstance: 'new DigiaPackage()'`. At host-app compile time, RN injects this
|
|
11
|
+
* into the generated `PackageList`, making our native module and view managers available to JS
|
|
12
|
+
* without any manual MainApplication edits.
|
|
13
|
+
*
|
|
14
|
+
* JS: NativeModules.DigiaEngageModule ──► DigiaModule.kt JS:
|
|
15
|
+
* requireNativeComponent('DigiaHostView') ──► DigiaViewManager.kt JS:
|
|
16
|
+
* requireNativeComponent('DigiaSlotView') ──► DigiaSlotViewManager.kt
|
|
17
|
+
*/
|
|
18
|
+
package com.digia.engage.rn
|
|
19
|
+
|
|
20
|
+
import com.facebook.react.BaseReactPackage
|
|
21
|
+
import com.facebook.react.bridge.NativeModule
|
|
22
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
23
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
24
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
25
|
+
import com.facebook.react.uimanager.ViewManager
|
|
26
|
+
|
|
27
|
+
class DigiaPackage : BaseReactPackage() {
|
|
28
|
+
|
|
29
|
+
// ─── Native Modules ───────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Called by New Architecture (TurboModules) to instantiate the module by name. Old Architecture
|
|
33
|
+
* continues to use createNativeModules() which TurboReactPackage implements internally by
|
|
34
|
+
* delegating to this method via getReactModuleInfoProvider.
|
|
35
|
+
*/
|
|
36
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
|
|
37
|
+
when (name) {
|
|
38
|
+
DigiaModule.MODULE_NAME -> DigiaModule(reactContext)
|
|
39
|
+
else -> null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Metadata table: tells the RN runtime which modules this package provides and whether they
|
|
44
|
+
* should be treated as TurboModules (New Architecture).
|
|
45
|
+
*/
|
|
46
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider {
|
|
47
|
+
mapOf(
|
|
48
|
+
DigiaModule.MODULE_NAME to
|
|
49
|
+
ReactModuleInfo(
|
|
50
|
+
/* name */ DigiaModule.MODULE_NAME,
|
|
51
|
+
/* className */ DigiaModule.MODULE_NAME,
|
|
52
|
+
/* canOverrideExistingModule */ false,
|
|
53
|
+
/* needsEagerInit */ false,
|
|
54
|
+
/* isCxxModule */ false,
|
|
55
|
+
/* isTurboModule */ false,
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── View Managers ────────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
override fun createViewManagers(
|
|
63
|
+
reactContext: ReactApplicationContext,
|
|
64
|
+
): List<ViewManager<*, *>> =
|
|
65
|
+
listOf(
|
|
66
|
+
DigiaViewManager(),
|
|
67
|
+
DigiaSlotViewManager(),
|
|
68
|
+
)
|
|
69
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaSlotViewManager
|
|
3
|
+
*
|
|
4
|
+
* React Native ViewManager that exposes [DigiaSlotView] (from the Digia Android SDK) as the native
|
|
5
|
+
* view behind the JS `<DigiaSlotView>` component.
|
|
6
|
+
*
|
|
7
|
+
* Supported JS props:
|
|
8
|
+
* - `placementKey` (String) — matches the placement key set in the Digia dashboard.
|
|
9
|
+
*/
|
|
10
|
+
package com.digia.engage.rn
|
|
11
|
+
|
|
12
|
+
import android.content.Context
|
|
13
|
+
import android.widget.FrameLayout
|
|
14
|
+
import androidx.lifecycle.LifecycleOwner
|
|
15
|
+
import androidx.lifecycle.ViewModelStoreOwner
|
|
16
|
+
import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
17
|
+
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
|
18
|
+
import androidx.savedstate.SavedStateRegistryOwner
|
|
19
|
+
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
20
|
+
import com.digia.engage.DigiaSlotView
|
|
21
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
22
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
23
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
24
|
+
|
|
25
|
+
internal class DigiaSlotViewManager : SimpleViewManager<DigiaSlotView>() {
|
|
26
|
+
|
|
27
|
+
override fun getName(): String = VIEW_NAME
|
|
28
|
+
|
|
29
|
+
override fun createViewInstance(context: ThemedReactContext): DigiaSlotView {
|
|
30
|
+
val activityContext: Context = context.currentActivity ?: context
|
|
31
|
+
|
|
32
|
+
val view = DigiaSlotView(activityContext)
|
|
33
|
+
|
|
34
|
+
// Wire Architecture Component owners so the Compose runtime works correctly.
|
|
35
|
+
val activity = context.currentActivity
|
|
36
|
+
if (activity is LifecycleOwner) {
|
|
37
|
+
view.setViewTreeLifecycleOwner(activity)
|
|
38
|
+
}
|
|
39
|
+
if (activity is ViewModelStoreOwner) {
|
|
40
|
+
view.setViewTreeViewModelStoreOwner(activity)
|
|
41
|
+
}
|
|
42
|
+
if (activity is SavedStateRegistryOwner) {
|
|
43
|
+
view.setViewTreeSavedStateRegistryOwner(activity)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// React Native controls sizing; fill whatever space the JS stylesheet allocates.
|
|
47
|
+
view.layoutParams =
|
|
48
|
+
FrameLayout.LayoutParams(
|
|
49
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
50
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return view
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@ReactProp(name = "placementKey")
|
|
57
|
+
fun setPlacementKey(view: DigiaSlotView, placementKey: String?) {
|
|
58
|
+
view.placementKey = placementKey.orEmpty()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
companion object {
|
|
62
|
+
const val VIEW_NAME = "DigiaSlotView"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaViewManager
|
|
3
|
+
*
|
|
4
|
+
* React Native ViewManager that exposes `DigiaHostView` (from the Digia Android SDK) as the native
|
|
5
|
+
* view behind the JS `<DigiaHostView>` component.
|
|
6
|
+
*
|
|
7
|
+
* The view hosts the `DigiaHost` composable which manages dialog and bottom-sheet overlays driven
|
|
8
|
+
* by Digia CEP plugins.
|
|
9
|
+
*/
|
|
10
|
+
package com.digia.engage.rn
|
|
11
|
+
|
|
12
|
+
import android.content.Context
|
|
13
|
+
import android.widget.FrameLayout
|
|
14
|
+
import androidx.lifecycle.LifecycleOwner
|
|
15
|
+
import androidx.lifecycle.ViewModelStoreOwner
|
|
16
|
+
import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
17
|
+
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
|
18
|
+
import androidx.savedstate.SavedStateRegistryOwner
|
|
19
|
+
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
20
|
+
import com.digia.engage.DigiaHostView
|
|
21
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
22
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
23
|
+
|
|
24
|
+
internal class DigiaViewManager : SimpleViewManager<DigiaHostView>() {
|
|
25
|
+
|
|
26
|
+
override fun getName(): String = VIEW_NAME
|
|
27
|
+
|
|
28
|
+
override fun createViewInstance(context: ThemedReactContext): DigiaHostView {
|
|
29
|
+
// Prefer the current Activity as the context provider so that the Compose
|
|
30
|
+
// runtime can access a proper LifecycleOwner / ViewModelStoreOwner.
|
|
31
|
+
val activityContext: Context = context.currentActivity ?: context
|
|
32
|
+
|
|
33
|
+
val view = DigiaHostView(activityContext)
|
|
34
|
+
|
|
35
|
+
// Explicitly wire the Android Architecture Component owners so that the
|
|
36
|
+
// Compose runtime (which uses ViewTree* APIs) works correctly regardless
|
|
37
|
+
// of React Native's internal view hierarchy wiring.
|
|
38
|
+
val activity = context.currentActivity
|
|
39
|
+
if (activity is LifecycleOwner) {
|
|
40
|
+
view.setViewTreeLifecycleOwner(activity)
|
|
41
|
+
}
|
|
42
|
+
if (activity is ViewModelStoreOwner) {
|
|
43
|
+
view.setViewTreeViewModelStoreOwner(activity)
|
|
44
|
+
}
|
|
45
|
+
if (activity is SavedStateRegistryOwner) {
|
|
46
|
+
view.setViewTreeSavedStateRegistryOwner(activity)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// React Native controls sizing via its layout system; fill whatever space
|
|
50
|
+
// the JS stylesheet allocates (typically StyleSheet.absoluteFill).
|
|
51
|
+
view.layoutParams =
|
|
52
|
+
FrameLayout.LayoutParams(
|
|
53
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
54
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return view
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
companion object {
|
|
61
|
+
const val VIEW_NAME = "DigiaHostView"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DigiaEngageModule (iOS stub)
|
|
3
|
+
*
|
|
4
|
+
* iOS support is not yet implemented. This stub registers the module so that
|
|
5
|
+
* the JS layer does not crash when imported on iOS. All methods are no-ops.
|
|
6
|
+
*/
|
|
7
|
+
#import <React/RCTBridgeModule.h>
|
|
8
|
+
#import <React/RCTViewManager.h>
|
|
9
|
+
|
|
10
|
+
// ── NativeModule stub ─────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
@interface DigiaEngageModule : NSObject <RCTBridgeModule>
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
@implementation DigiaEngageModule
|
|
16
|
+
|
|
17
|
+
RCT_EXPORT_MODULE(DigiaEngageModule)
|
|
18
|
+
|
|
19
|
+
RCT_EXPORT_METHOD(initialize:(NSString *)apiKey
|
|
20
|
+
environment:(NSString *)environment
|
|
21
|
+
logLevel:(NSString *)logLevel
|
|
22
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
23
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
24
|
+
{
|
|
25
|
+
// iOS not yet implemented – resolve immediately so JS doesn't hang.
|
|
26
|
+
resolve(nil);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
RCT_EXPORT_METHOD(setCurrentScreen:(NSString *)name)
|
|
30
|
+
{
|
|
31
|
+
// no-op
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
RCT_EXPORT_METHOD(openNavigation:(nullable NSString *)startPageId
|
|
35
|
+
pageArgs:(NSDictionary *)pageArgs)
|
|
36
|
+
{
|
|
37
|
+
// no-op
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
RCT_EXPORT_METHOD(triggerCampaign:(NSString *)campaignId
|
|
41
|
+
content:(NSDictionary *)content
|
|
42
|
+
cepContext:(NSDictionary *)cepContext)
|
|
43
|
+
{
|
|
44
|
+
// no-op — iOS Digia SDK not yet available
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
RCT_EXPORT_METHOD(invalidateCampaign:(NSString *)campaignId)
|
|
48
|
+
{
|
|
49
|
+
// no-op
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// ── ViewManager stub ──────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
@interface DigiaHostViewManager : RCTViewManager
|
|
58
|
+
@end
|
|
59
|
+
|
|
60
|
+
@implementation DigiaHostViewManager
|
|
61
|
+
|
|
62
|
+
RCT_EXPORT_MODULE(DigiaHostView)
|
|
63
|
+
|
|
64
|
+
- (UIView *)view {
|
|
65
|
+
// Return a transparent placeholder view
|
|
66
|
+
UIView *v = [[UIView alloc] init];
|
|
67
|
+
v.userInteractionEnabled = NO;
|
|
68
|
+
return v;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Digia = void 0;
|
|
7
|
+
var _NativeDigiaModule = require("./NativeDigiaModule");
|
|
8
|
+
/**
|
|
9
|
+
* High-level Digia Engage SDK wrapper.
|
|
10
|
+
*
|
|
11
|
+
* Usage
|
|
12
|
+
* ──────
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { Digia } from '@digia/engage-react-native';
|
|
15
|
+
*
|
|
16
|
+
* // In your App entry point (e.g. App.tsx):
|
|
17
|
+
* await Digia.initialize({ apiKey: 'YOUR_API_KEY' });
|
|
18
|
+
*
|
|
19
|
+
* // Whenever your navigation screen changes:
|
|
20
|
+
* Digia.setCurrentScreen('Home');
|
|
21
|
+
*
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class DigiaClass {
|
|
26
|
+
_plugins = new Map();
|
|
27
|
+
// Tracks whether the native bridge plugin (RNEventBridgePlugin) has been
|
|
28
|
+
// wired to the native SDK. Done once on the first Digia.register() call.
|
|
29
|
+
_nativeBridgeWired = false;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialise the Digia Engage SDK.
|
|
33
|
+
*
|
|
34
|
+
* Must be called once before anything else – ideally as early as possible
|
|
35
|
+
* in your application lifecycle (start of `App.tsx`).
|
|
36
|
+
*/
|
|
37
|
+
async initialize(config) {
|
|
38
|
+
const environment = config.environment ?? 'production';
|
|
39
|
+
const logLevel = config.logLevel ?? 'error';
|
|
40
|
+
await _NativeDigiaModule.nativeDigiaModule.initialize(config.apiKey, environment, logLevel);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Register a CEP plugin with the Digia SDK.
|
|
45
|
+
*
|
|
46
|
+
* On the first call this also wires the internal RNEventBridgePlugin with
|
|
47
|
+
* the native Android SDK so it holds the DigiaCEPDelegate reference needed
|
|
48
|
+
* to show overlays and emit lifecycle events back to JS. This is transparent
|
|
49
|
+
* bridge plumbing — you never interact with RNEventBridgePlugin directly.
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { DigiaMoEngagePlugin } from '@digia/moengage-plugin';
|
|
53
|
+
*
|
|
54
|
+
* await Digia.initialize({ apiKey: 'YOUR_KEY' });
|
|
55
|
+
* Digia.register(new DigiaMoEngagePlugin({ moEngage: MoEngage }));
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
register(plugin) {
|
|
59
|
+
if (this._plugins.has(plugin.identifier)) {
|
|
60
|
+
this._plugins.get(plugin.identifier).teardown();
|
|
61
|
+
}
|
|
62
|
+
// Wire the native bridge plugin once, before the first plugin's setup()
|
|
63
|
+
// so the delegate is ready when JS campaigns start flowing.
|
|
64
|
+
if (!this._nativeBridgeWired) {
|
|
65
|
+
_NativeDigiaModule.nativeDigiaModule.registerBridge();
|
|
66
|
+
this._nativeBridgeWired = true;
|
|
67
|
+
}
|
|
68
|
+
plugin.setup(this);
|
|
69
|
+
this._plugins.set(plugin.identifier, plugin);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Unregister a previously registered plugin.
|
|
74
|
+
* Calls plugin.teardown() internally.
|
|
75
|
+
*/
|
|
76
|
+
unregister(pluginOrId) {
|
|
77
|
+
const id = typeof pluginOrId === 'string' ? pluginOrId : pluginOrId.identifier;
|
|
78
|
+
this._plugins.get(id)?.teardown();
|
|
79
|
+
this._plugins.delete(id);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Notify the SDK of the currently active screen name.
|
|
84
|
+
*
|
|
85
|
+
* Wire this up to your navigation library's screen-change listener
|
|
86
|
+
* (e.g. React Navigation focus events or `useNavigationContainerRef`).
|
|
87
|
+
* All registered plugins will have forwardScreen() called automatically.
|
|
88
|
+
*/
|
|
89
|
+
setCurrentScreen(name) {
|
|
90
|
+
_NativeDigiaModule.nativeDigiaModule.setCurrentScreen(name);
|
|
91
|
+
this._plugins.forEach(plugin => plugin.forwardScreen(name));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── DigiaDelegate ────────────────────────────────────────────────────────
|
|
95
|
+
// Mirrors DigiaCEPDelegate on Android.
|
|
96
|
+
// Forwards to the native DigiaCEPDelegate via the bridge.
|
|
97
|
+
|
|
98
|
+
onCampaignTriggered(payload) {
|
|
99
|
+
_NativeDigiaModule.nativeDigiaModule.triggerCampaign(payload.id, payload.content, payload.cepContext);
|
|
100
|
+
}
|
|
101
|
+
onCampaignInvalidated(campaignId) {
|
|
102
|
+
_NativeDigiaModule.nativeDigiaModule.invalidateCampaign(campaignId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const Digia = exports.Digia = new DigiaClass();
|
|
106
|
+
//# sourceMappingURL=Digia.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_NativeDigiaModule","require","DigiaClass","_plugins","Map","_nativeBridgeWired","initialize","config","environment","logLevel","nativeDigiaModule","apiKey","register","plugin","has","identifier","get","teardown","registerBridge","setup","set","unregister","pluginOrId","id","delete","setCurrentScreen","name","forEach","forwardScreen","onCampaignTriggered","payload","triggerCampaign","content","cepContext","onCampaignInvalidated","campaignId","invalidateCampaign","Digia","exports"],"sourceRoot":"../../src","sources":["Digia.ts"],"mappings":";;;;;;AAiBA,IAAAA,kBAAA,GAAAC,OAAA;AAjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA,MAAMC,UAAU,CAA0B;EACrBC,QAAQ,GAAG,IAAIC,GAAG,CAAsB,CAAC;EAC1D;EACA;EACQC,kBAAkB,GAAG,KAAK;;EAElC;AACJ;AACA;AACA;AACA;AACA;EACI,MAAMC,UAAUA,CAACC,MAAmB,EAAiB;IACjD,MAAMC,WAAW,GAAGD,MAAM,CAACC,WAAW,IAAI,YAAY;IACtD,MAAMC,QAAQ,GAAGF,MAAM,CAACE,QAAQ,IAAI,OAAO;IAC3C,MAAMC,oCAAiB,CAACJ,UAAU,CAACC,MAAM,CAACI,MAAM,EAAEH,WAAW,EAAEC,QAAQ,CAAC;EAC5E;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACIG,QAAQA,CAACC,MAAmB,EAAQ;IAChC,IAAI,IAAI,CAACV,QAAQ,CAACW,GAAG,CAACD,MAAM,CAACE,UAAU,CAAC,EAAE;MACtC,IAAI,CAACZ,QAAQ,CAACa,GAAG,CAACH,MAAM,CAACE,UAAU,CAAC,CAAEE,QAAQ,CAAC,CAAC;IACpD;IACA;IACA;IACA,IAAI,CAAC,IAAI,CAACZ,kBAAkB,EAAE;MAC1BK,oCAAiB,CAACQ,cAAc,CAAC,CAAC;MAClC,IAAI,CAACb,kBAAkB,GAAG,IAAI;IAClC;IACAQ,MAAM,CAACM,KAAK,CAAC,IAAI,CAAC;IAClB,IAAI,CAAChB,QAAQ,CAACiB,GAAG,CAACP,MAAM,CAACE,UAAU,EAAEF,MAAM,CAAC;EAChD;;EAEA;AACJ;AACA;AACA;EACIQ,UAAUA,CAACC,UAAgC,EAAQ;IAC/C,MAAMC,EAAE,GAAG,OAAOD,UAAU,KAAK,QAAQ,GAAGA,UAAU,GAAGA,UAAU,CAACP,UAAU;IAC9E,IAAI,CAACZ,QAAQ,CAACa,GAAG,CAACO,EAAE,CAAC,EAAEN,QAAQ,CAAC,CAAC;IACjC,IAAI,CAACd,QAAQ,CAACqB,MAAM,CAACD,EAAE,CAAC;EAC5B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;EACIE,gBAAgBA,CAACC,IAAY,EAAQ;IACjChB,oCAAiB,CAACe,gBAAgB,CAACC,IAAI,CAAC;IACxC,IAAI,CAACvB,QAAQ,CAACwB,OAAO,CAAEd,MAAM,IAAKA,MAAM,CAACe,aAAa,CAACF,IAAI,CAAC,CAAC;EACjE;;EAEA;EACA;EACA;;EAEAG,mBAAmBA,CAACC,OAAqB,EAAQ;IAC7CpB,oCAAiB,CAACqB,eAAe,CAACD,OAAO,CAACP,EAAE,EAAEO,OAAO,CAACE,OAAO,EAAEF,OAAO,CAACG,UAAU,CAAC;EACtF;EAEAC,qBAAqBA,CAACC,UAAkB,EAAQ;IAC5CzB,oCAAiB,CAAC0B,kBAAkB,CAACD,UAAU,CAAC;EACpD;AAEJ;AAEO,MAAME,KAAK,GAAAC,OAAA,CAAAD,KAAA,GAAG,IAAInC,UAAU,CAAC,CAAC","ignoreList":[]}
|