@amplytools/react-native-amply-sdk 0.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.
Files changed (88) hide show
  1. package/LICENSE +178 -0
  2. package/README.md +714 -0
  3. package/android/build.gradle +90 -0
  4. package/android/consumer-rules.pro +1 -0
  5. package/android/gradle.properties +3 -0
  6. package/android/settings.gradle +9 -0
  7. package/android/src/main/AndroidManifest.xml +3 -0
  8. package/android/src/main/java/tools/amply/sdk/reactnative/AmplyModule.kt +384 -0
  9. package/android/src/main/java/tools/amply/sdk/reactnative/AmplyPackage.kt +39 -0
  10. package/android/src/main/java/tools/amply/sdk/reactnative/core/AmplyClient.kt +30 -0
  11. package/android/src/main/java/tools/amply/sdk/reactnative/core/DefaultAmplyClient.kt +296 -0
  12. package/android/src/main/java/tools/amply/sdk/reactnative/model/AmplyInitializationOptions.kt +10 -0
  13. package/android/src/main/java/tools/amply/sdk/reactnative/model/DataSetType.kt +42 -0
  14. package/android/src/main/java/tools/amply/sdk/reactnative/model/DataSetTypeMapper.kt +38 -0
  15. package/android/src/main/java/tools/amply/sdk/reactnative/model/DeepLinkPayload.kt +8 -0
  16. package/android/src/main/java/tools/amply/sdk/reactnative/model/EventEnvelope.kt +9 -0
  17. package/android/src/main/jni/AmplyTurboModule.cpp +29 -0
  18. package/android/src/main/jni/CMakeLists.txt +76 -0
  19. package/android/src/newarch/java/tools/amply/sdk/reactnative/NativeAmplyModuleSpec.java +75 -0
  20. package/android/src/newarch/jni/AmplyReactNative-generated.cpp +77 -0
  21. package/android/src/newarch/jni/AmplyReactNative.h +31 -0
  22. package/android/src/newarch/jni/CMakeLists.txt +40 -0
  23. package/app.plugin.js +1 -0
  24. package/dist/index.js +272 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/index.mjs +234 -0
  27. package/dist/index.mjs.map +1 -0
  28. package/dist/plugin/index.d.ts +6 -0
  29. package/dist/plugin/index.d.ts.map +1 -0
  30. package/dist/plugin/index.js +186 -0
  31. package/dist/plugin/index.js.map +1 -0
  32. package/dist/plugin/index.mjs +169 -0
  33. package/dist/plugin/index.mjs.map +1 -0
  34. package/dist/plugin/src/index.d.ts +6 -0
  35. package/dist/plugin/src/index.d.ts.map +1 -0
  36. package/dist/plugin/src/index.js +3 -0
  37. package/dist/plugin/src/withAmply.d.ts +30 -0
  38. package/dist/plugin/src/withAmply.d.ts.map +1 -0
  39. package/dist/plugin/src/withAmply.js +51 -0
  40. package/dist/plugin/withAmply.d.ts +12 -0
  41. package/dist/plugin/withAmply.d.ts.map +1 -0
  42. package/dist/src/__tests__/index.test.d.ts +2 -0
  43. package/dist/src/__tests__/index.test.d.ts.map +1 -0
  44. package/dist/src/__tests__/index.test.js +70 -0
  45. package/dist/src/hooks/useAmplySystemEvents.d.ts +12 -0
  46. package/dist/src/hooks/useAmplySystemEvents.d.ts.map +1 -0
  47. package/dist/src/hooks/useAmplySystemEvents.js +56 -0
  48. package/dist/src/index.d.ts +32 -0
  49. package/dist/src/index.d.ts.map +1 -0
  50. package/dist/src/index.js +80 -0
  51. package/dist/src/nativeModule.d.ts +5 -0
  52. package/dist/src/nativeModule.d.ts.map +1 -0
  53. package/dist/src/nativeModule.js +48 -0
  54. package/dist/src/nativeSpecs/NativeAmplyModule.d.ts +75 -0
  55. package/dist/src/nativeSpecs/NativeAmplyModule.d.ts.map +1 -0
  56. package/dist/src/nativeSpecs/NativeAmplyModule.js +2 -0
  57. package/dist/src/systemEventUtils.d.ts +3 -0
  58. package/dist/src/systemEventUtils.d.ts.map +1 -0
  59. package/dist/src/systemEventUtils.js +30 -0
  60. package/dist/src/systemEvents.d.ts +6 -0
  61. package/dist/src/systemEvents.d.ts.map +1 -0
  62. package/dist/src/systemEvents.js +8 -0
  63. package/dist/tsconfig.tsbuildinfo +1 -0
  64. package/docs/ARCHITECTURE.md +1115 -0
  65. package/expo-module.config.json +11 -0
  66. package/ios/AmplyReactNative.podspec +32 -0
  67. package/ios/README.md +11 -0
  68. package/ios/Sources/AmplyReactNative/AmplyModule.mm +332 -0
  69. package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative-generated.mm +111 -0
  70. package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative.h +152 -0
  71. package/package.json +71 -0
  72. package/plugin/build/index.d.ts +5 -0
  73. package/plugin/build/index.js +8 -0
  74. package/plugin/build/withAmply.d.ts +29 -0
  75. package/plugin/build/withAmply.js +53 -0
  76. package/plugin/src/index.ts +7 -0
  77. package/plugin/src/withAmply.ts +68 -0
  78. package/plugin/tsconfig.json +8 -0
  79. package/plugin/tsconfig.tsbuildinfo +1 -0
  80. package/react-native.config.js +34 -0
  81. package/scripts/codegen.js +212 -0
  82. package/src/__tests__/index.test.ts +92 -0
  83. package/src/hooks/useAmplySystemEvents.ts +75 -0
  84. package/src/index.ts +115 -0
  85. package/src/nativeModule.ts +65 -0
  86. package/src/nativeSpecs/NativeAmplyModule.ts +80 -0
  87. package/src/systemEventUtils.ts +35 -0
  88. package/src/systemEvents.ts +13 -0
@@ -0,0 +1,296 @@
1
+ package tools.amply.sdk.reactnative.core
2
+
3
+ import android.app.Activity
4
+ import android.app.Application
5
+ import android.os.Handler
6
+ import android.os.Looper
7
+ import tools.amply.sdk.reactnative.model.AmplyInitializationOptions
8
+ import tools.amply.sdk.reactnative.model.DataSetType
9
+ import tools.amply.sdk.reactnative.model.DeepLinkPayload
10
+ import tools.amply.sdk.reactnative.model.EventEnvelope
11
+ import tools.amply.sdk.reactnative.model.toNativeDataSetType
12
+ import java.util.concurrent.atomic.AtomicBoolean
13
+ import java.util.concurrent.atomic.AtomicLong
14
+ import java.util.concurrent.atomic.AtomicReference
15
+ import java.lang.ref.WeakReference
16
+ import kotlinx.coroutines.Dispatchers
17
+ import kotlinx.coroutines.flow.MutableSharedFlow
18
+ import kotlinx.coroutines.flow.SharedFlow
19
+ import kotlinx.coroutines.flow.asSharedFlow
20
+ import kotlinx.coroutines.runBlocking
21
+ import kotlinx.coroutines.sync.Mutex
22
+ import kotlinx.coroutines.sync.withLock
23
+ import kotlinx.coroutines.withContext
24
+ import tools.amply.sdk.Amply
25
+ import tools.amply.sdk.actions.DeepLinkListener
26
+ import tools.amply.sdk.config.AmplyConfig
27
+ import tools.amply.sdk.config.amplyConfig
28
+ import tools.amply.sdk.core.AmplySDKInterface
29
+ import tools.amply.sdk.events.EventInterface
30
+ import tools.amply.sdk.events.SystemEventsListener
31
+
32
+ class DefaultAmplyClient(
33
+ private val application: Application,
34
+ ) : AmplyClient {
35
+
36
+ private val mutex = Mutex()
37
+ private var amplyInstance: Amply? = null
38
+ private val deepLinkRegistered = AtomicBoolean(false)
39
+ private val systemEventsRegistered = AtomicBoolean(false)
40
+ private val deepLinkSequence = AtomicLong(0L)
41
+ private val lastResumedActivity = AtomicReference<WeakReference<Activity>?>(null)
42
+ private val sessionPrimed = AtomicBoolean(false)
43
+ private val mainHandler = Handler(Looper.getMainLooper())
44
+
45
+ private val _deepLinkEvents = MutableSharedFlow<DeepLinkPayload>(
46
+ replay = 1,
47
+ extraBufferCapacity = 16,
48
+ )
49
+ override val deepLinkEvents: SharedFlow<DeepLinkPayload> = _deepLinkEvents.asSharedFlow()
50
+ private val _systemEvents = MutableSharedFlow<EventEnvelope>(
51
+ replay = 32,
52
+ extraBufferCapacity = 128,
53
+ )
54
+ override val systemEvents: SharedFlow<EventEnvelope> = _systemEvents.asSharedFlow()
55
+
56
+ override suspend fun initialize(options: AmplyInitializationOptions) {
57
+ var createdInstance = false
58
+ mutex.withLock {
59
+ if (amplyInstance == null) {
60
+ val config = buildConfig(options)
61
+ android.util.Log.i(
62
+ "AmplyReactNative",
63
+ "Initializing Amply with appId=${options.appId} apiKeyPublic=${options.apiKeyPublic.takeIf { it.isNotEmpty() } ?: "<empty>"}"
64
+ )
65
+ val instance = withContext(Dispatchers.Default) {
66
+ Amply(config, application)
67
+ }
68
+ ensureSystemEventsListener(instance)
69
+ amplyInstance = instance
70
+ createdInstance = true
71
+ }
72
+ }
73
+ if (createdInstance) {
74
+ maybePrimeSessionTracker()
75
+ }
76
+ }
77
+
78
+ override fun isInitialized(): Boolean = amplyInstance != null
79
+
80
+ override suspend fun track(name: String, properties: Map<String, Any?>?) {
81
+ val instance = requireInstance()
82
+ withContext(Dispatchers.IO) {
83
+ android.util.Log.i(
84
+ "AmplyReactNative",
85
+ "Tracking event '$name' with properties=${properties?.filterValues { it != null }}"
86
+ )
87
+ instance.track(name, properties?.toNonNullMap() ?: emptyMap())
88
+ }
89
+ }
90
+
91
+ override suspend fun getRecentEvents(limit: Int): List<EventEnvelope> {
92
+ val instance = requireInstance()
93
+ return withContext(Dispatchers.IO) {
94
+ val events = instance.getRecentEvents(limit)
95
+ android.util.Log.i(
96
+ "AmplyReactNative",
97
+ "Fetched ${events.size} recent events (limit=$limit)"
98
+ )
99
+ events.map { it.toEventEnvelope() }
100
+ }
101
+ }
102
+
103
+ override suspend fun getDataSetSnapshot(type: DataSetType): Map<String, Any?> {
104
+ val instance = requireInstance()
105
+ val nativeType = type.toNativeDataSetType()
106
+ return withContext(Dispatchers.IO) {
107
+ val snapshot = instance.getDataSetSnapshot(nativeType)
108
+ android.util.Log.i(
109
+ "AmplyReactNative",
110
+ "DataSetSnapshot(${type.javaClass.simpleName}) keys=${snapshot.keys}"
111
+ )
112
+ snapshot.toNullableValues()
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Registers a listener for deep links triggered by Amply SDK campaigns.
118
+ *
119
+ * This listener allows app developers to:
120
+ * 1. Know that a deep link originated from Amply SDK (vs. external sources like
121
+ * push notifications, browser links, or other SDKs)
122
+ * 2. Access campaign metadata via the `info` map (campaign ID, variant, etc.)
123
+ * that is not available in the URL itself
124
+ * 3. Track/log Amply-specific deep link events for analytics
125
+ *
126
+ * Example use case:
127
+ * // In JS:
128
+ * Amply.addDeepLinkListener(event => {
129
+ * // We know this deep link came from an Amply campaign, not from elsewhere
130
+ * analytics.track('Amply campaign triggered', { url: event.url, info: event.info });
131
+ * });
132
+ *
133
+ * The deep link flow:
134
+ * Campaign triggers → KMP SDK → onDeepLink callback → JS event emitted
135
+ * ↓ (then)
136
+ * startActivity(Intent.ACTION_VIEW) → Linking API
137
+ *
138
+ * Note: The listener is an observer, not a controller. The SDK will still open
139
+ * the URL via system after emitting the event.
140
+ */
141
+ override fun registerDeepLinkListener() {
142
+ val instance = requireInstance()
143
+ if (!deepLinkRegistered.compareAndSet(false, true)) {
144
+ return
145
+ }
146
+ android.util.Log.i("AmplyReactNative", "Registering deep link listener")
147
+
148
+ instance.registerDeepLinkListener(object : DeepLinkListener {
149
+ override fun onDeepLink(url: String, info: Map<String, Any>): Boolean {
150
+ android.util.Log.i(
151
+ "AmplyReactNative",
152
+ "Received deep link from Amply url=$url infoKeys=${info.keys}"
153
+ )
154
+ val payload = DeepLinkPayload(
155
+ sequenceId = deepLinkSequence.incrementAndGet(),
156
+ url = url,
157
+ info = info.mapValues { it.value },
158
+ consumed = false
159
+ )
160
+ if (!_deepLinkEvents.tryEmit(payload)) {
161
+ android.util.Log.w(
162
+ "AmplyReactNative",
163
+ "Dropping deep link event due to backpressure sequenceId=${payload.sequenceId}"
164
+ )
165
+ }
166
+ return false
167
+ }
168
+ })
169
+ }
170
+
171
+ override fun registerSystemEventListener() {
172
+ val instance = requireInstance()
173
+ android.util.Log.i(
174
+ "AmplyReactNative",
175
+ "registerSystemEventListener() called; alreadyRegistered=${systemEventsRegistered.get()}"
176
+ )
177
+ ensureSystemEventsListener(instance)
178
+ }
179
+
180
+ override fun onHostResume(activity: Activity?) {
181
+ if (activity != null) {
182
+ lastResumedActivity.set(WeakReference(activity))
183
+ }
184
+ maybePrimeSessionTracker()
185
+ }
186
+
187
+ override fun shutdown() {
188
+ runBlocking {
189
+ mutex.withLock {
190
+ amplyInstance = null
191
+ }
192
+ }
193
+ deepLinkRegistered.set(false)
194
+ systemEventsRegistered.set(false)
195
+ android.util.Log.i("AmplyReactNative", "Amply client shutdown; deep link listener cleared")
196
+ deepLinkSequence.set(0L)
197
+ sessionPrimed.set(false)
198
+ lastResumedActivity.set(null)
199
+ _deepLinkEvents.resetReplayCache()
200
+ _systemEvents.resetReplayCache()
201
+ }
202
+
203
+ private fun requireInstance(): Amply {
204
+ return amplyInstance ?: throw IllegalStateException("Amply has not been initialized yet")
205
+ }
206
+
207
+ private fun buildConfig(options: AmplyInitializationOptions): AmplyConfig {
208
+ return amplyConfig {
209
+ api {
210
+ appId = options.appId
211
+ apiKeyPublic = options.apiKeyPublic
212
+ options.apiKeySecret?.let { apiKeySecret = it }
213
+ }
214
+ options.defaultConfig?.let { defaultConfig = it }
215
+ }
216
+ }
217
+
218
+ private fun Map<String, Any?>.toNonNullMap(): Map<String, Any> =
219
+ entries.mapNotNull { (key, value) -> value?.let { key to it } }.toMap()
220
+
221
+ private fun Map<String, Any>.toNullableValues(): Map<String, Any?> =
222
+ mapValues { it.value }
223
+
224
+ private fun EventInterface.toEventEnvelope(): EventEnvelope =
225
+ EventEnvelope(
226
+ id = null,
227
+ name = name,
228
+ type = type.name.lowercase(),
229
+ timestamp = timestamp,
230
+ properties = properties.mapValues { it.value }
231
+ )
232
+
233
+ private fun ensureSystemEventsListener(instance: Amply) {
234
+ if (!systemEventsRegistered.compareAndSet(false, true)) {
235
+ android.util.Log.i(
236
+ "AmplyReactNative",
237
+ "System events listener already registered; skipping setSystemEventsListener"
238
+ )
239
+ return
240
+ }
241
+ instance.setSystemEventsListener(object : SystemEventsListener {
242
+ override fun onEvent(event: EventInterface) {
243
+ android.util.Log.i(
244
+ "AmplyReactNative",
245
+ "System event ${event.name} ts=${event.timestamp} props=${event.properties.keys}"
246
+ )
247
+ val envelope = event.toEventEnvelope()
248
+ if (!_systemEvents.tryEmit(envelope)) {
249
+ android.util.Log.w(
250
+ "AmplyReactNative",
251
+ "Dropping system event due to backpressure name=${event.name}"
252
+ )
253
+ }
254
+ }
255
+ })
256
+ }
257
+
258
+ private fun maybePrimeSessionTracker() {
259
+ if (sessionPrimed.get()) {
260
+ return
261
+ }
262
+ val instance = amplyInstance ?: return
263
+ val activity = lastResumedActivity.get()?.get() ?: return
264
+ if (Looper.myLooper() != Looper.getMainLooper()) {
265
+ mainHandler.post { maybePrimeSessionTracker() }
266
+ return
267
+ }
268
+
269
+ try {
270
+ val coreField = Amply::class.java.getDeclaredField("amplyCore").apply {
271
+ isAccessible = true
272
+ }
273
+ val core = coreField.get(instance) as? AmplySDKInterface ?: return
274
+ val sessionManager = core.getSessionManager()
275
+ val trackerField = sessionManager.javaClass.getDeclaredField("sessionTracker").apply {
276
+ isAccessible = true
277
+ }
278
+ val sessionTracker = trackerField.get(sessionManager)
279
+ if (sessionTracker is Application.ActivityLifecycleCallbacks) {
280
+ sessionTracker.onActivityCreated(activity, null)
281
+ sessionTracker.onActivityStarted(activity)
282
+ sessionTracker.onActivityResumed(activity)
283
+ sessionPrimed.set(true)
284
+ android.util.Log.i(
285
+ "AmplyReactNative",
286
+ "Primed Amply session tracker with activity=${activity::class.java.simpleName}"
287
+ )
288
+ }
289
+ } catch (error: Throwable) {
290
+ android.util.Log.w(
291
+ "AmplyReactNative",
292
+ "Unable to prime Amply session tracker: ${error.message}"
293
+ )
294
+ }
295
+ }
296
+ }
@@ -0,0 +1,10 @@
1
+ package tools.amply.sdk.reactnative.model
2
+
3
+ data class AmplyInitializationOptions(
4
+ val appId: String,
5
+ val apiKeyPublic: String,
6
+ val apiKeySecret: String?,
7
+ val endpoint: String?,
8
+ val datasetPrefetch: List<DataSetType>?,
9
+ val defaultConfig: String?,
10
+ )
@@ -0,0 +1,42 @@
1
+ package tools.amply.sdk.reactnative.model
2
+
3
+ sealed interface DataSetType {
4
+ data object Device : DataSetType
5
+ data object User : DataSetType
6
+ data object Session : DataSetType
7
+
8
+ data class TriggeredEvent(
9
+ val countStrategy: CountStrategy,
10
+ val params: List<EventParam>,
11
+ val eventName: String?
12
+ ) : DataSetType {
13
+ enum class CountStrategy(val wireName: String) {
14
+ TOTAL("total"),
15
+ SESSION("session"),
16
+ USER("user");
17
+
18
+ companion object {
19
+ fun fromWireName(name: String?): CountStrategy? = entries.firstOrNull { it.wireName == name }
20
+ }
21
+ }
22
+ }
23
+
24
+ data class Events(val events: List<Event>) : DataSetType {
25
+ data class Event(
26
+ val name: String,
27
+ val type: EventType,
28
+ val params: List<EventParam>
29
+ )
30
+
31
+ enum class EventType(val wireName: String) {
32
+ CUSTOM("custom"),
33
+ SYSTEM("system");
34
+
35
+ companion object {
36
+ fun fromWireName(name: String?): EventType? = entries.firstOrNull { it.wireName == name }
37
+ }
38
+ }
39
+ }
40
+
41
+ data class EventParam(val name: String, val value: Any?)
42
+ }
@@ -0,0 +1,38 @@
1
+ package tools.amply.sdk.reactnative.model
2
+
3
+ import tools.amply.sdk.datasets.DataSetType as NativeDataSetType
4
+ import tools.amply.sdk.events.EventType as NativeEventType
5
+
6
+ fun DataSetType.toNativeDataSetType(): NativeDataSetType = when (this) {
7
+ DataSetType.Device -> NativeDataSetType.Device
8
+ DataSetType.User -> NativeDataSetType.User
9
+ DataSetType.Session -> NativeDataSetType.Session
10
+ is DataSetType.TriggeredEvent ->
11
+ NativeDataSetType.TriggeredEvent(
12
+ countStrategy = this.countStrategy.toNativeCountStrategy(),
13
+ params = params.mapNotNull { it.toNativeParamOrNull() },
14
+ eventName = eventName
15
+ )
16
+ is DataSetType.Events -> NativeDataSetType.Events(events.map { it.toNativeEventOrNull() }.filterNotNull())
17
+ }
18
+
19
+ private fun DataSetType.TriggeredEvent.CountStrategy.toNativeCountStrategy(): NativeDataSetType.TriggeredEvent.CountStrategy {
20
+ return NativeDataSetType.TriggeredEvent.CountStrategy.values().firstOrNull {
21
+ it.name.equals(name, ignoreCase = true)
22
+ } ?: throw IllegalArgumentException("Unsupported TriggeredEvent count strategy: $name")
23
+ }
24
+
25
+ private fun DataSetType.EventParam.toNativeParamOrNull(): NativeDataSetType.EventParam? =
26
+ value?.let { NativeDataSetType.EventParam(name, it) }
27
+
28
+ private fun DataSetType.Events.Event.toNativeEventOrNull(): NativeDataSetType.Events.Event? {
29
+ val transformedParams = params.mapNotNull { it.toNativeParamOrNull() }
30
+ if (transformedParams.size != params.size) {
31
+ return null
32
+ }
33
+ return NativeDataSetType.Events.Event(
34
+ name = name,
35
+ type = NativeEventType.valueOf(type.name.uppercase()),
36
+ params = transformedParams
37
+ )
38
+ }
@@ -0,0 +1,8 @@
1
+ package tools.amply.sdk.reactnative.model
2
+
3
+ data class DeepLinkPayload(
4
+ val sequenceId: Long,
5
+ val url: String,
6
+ val info: Map<String, Any?>,
7
+ val consumed: Boolean,
8
+ )
@@ -0,0 +1,9 @@
1
+ package tools.amply.sdk.reactnative.model
2
+
3
+ data class EventEnvelope(
4
+ val id: String?,
5
+ val name: String,
6
+ val type: String,
7
+ val timestamp: Long,
8
+ val properties: Map<String, Any?>,
9
+ )
@@ -0,0 +1,29 @@
1
+ #include <fbjni/fbjni.h>
2
+ #include <react/newarchdefaults/DefaultTurboModuleManagerDelegate.h>
3
+ #include <memory>
4
+ #include <string>
5
+
6
+ #include "AmplyReactNative.h"
7
+
8
+ using namespace facebook;
9
+
10
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
11
+ return jni::initialize(vm, [] {
12
+ const auto previousProvider =
13
+ react::DefaultTurboModuleManagerDelegate::javaModuleProvider;
14
+
15
+ react::DefaultTurboModuleManagerDelegate::javaModuleProvider =
16
+ [previousProvider](
17
+ const std::string &name,
18
+ const react::JavaTurboModule::InitParams &params)
19
+ -> std::shared_ptr<react::TurboModule> {
20
+ if (auto module = react::AmplyReactNative_ModuleProvider(name, params)) {
21
+ return module;
22
+ }
23
+ if (previousProvider) {
24
+ return previousProvider(name, params);
25
+ }
26
+ return nullptr;
27
+ };
28
+ });
29
+ }
@@ -0,0 +1,76 @@
1
+ cmake_minimum_required(VERSION 3.13)
2
+
3
+ project(AmplyReactNative LANGUAGES CXX)
4
+
5
+ set(CMAKE_VERBOSE_MAKEFILE on)
6
+
7
+ # React Native dir передаётся Gradle
8
+ set(REACT_SRC_ROOT "${REACT_NATIVE_DIR}")
9
+ set(REACT_COMMON_DIR "${REACT_SRC_ROOT}/ReactCommon")
10
+ set(REACT_ANDROID_SRC_DIR "${REACT_SRC_ROOT}/ReactAndroid/src/main/jni")
11
+ set(REACT_JAVA_TURBO_DIR "${REACT_COMMON_DIR}/react/nativemodule/core/platform/android")
12
+ set(REACT_CALL_INVOKER_DIR "${REACT_COMMON_DIR}/callinvoker")
13
+ set(REACT_TURBO_CORE_DIR "${REACT_COMMON_DIR}/react/nativemodule/core")
14
+ include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
15
+ find_package(ReactAndroid REQUIRED CONFIG)
16
+ find_package(fbjni REQUIRED CONFIG)
17
+
18
+ # Add codegen subdirectory (this will define react_codegen_AmplyReactNative target)
19
+ add_subdirectory(
20
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../newarch/jni
21
+ ${CMAKE_CURRENT_BINARY_DIR}/codegen
22
+ )
23
+
24
+ # Now that targets are defined, propagate includes to the codegen target
25
+ # This ensures OBJECT libraries can access all necessary headers (including folly)
26
+ get_target_property(FBJNI_IFACE_INCLUDES fbjni::fbjni INTERFACE_INCLUDE_DIRECTORIES)
27
+ if(FBJNI_IFACE_INCLUDES)
28
+ target_include_directories(react_codegen_AmplyReactNative PUBLIC ${FBJNI_IFACE_INCLUDES})
29
+ endif()
30
+
31
+ # Get includes from ReactAndroid::reactnative target (includes JSI, folly, etc.)
32
+ # These includes contain folly/dynamic.h and other necessary React Native headers
33
+ get_target_property(REACTNATIVE_IFACE_INCLUDES ReactAndroid::reactnative INTERFACE_INCLUDE_DIRECTORIES)
34
+ if(REACTNATIVE_IFACE_INCLUDES)
35
+ target_include_directories(react_codegen_AmplyReactNative PUBLIC ${REACTNATIVE_IFACE_INCLUDES})
36
+ endif()
37
+
38
+ target_include_directories(
39
+ react_codegen_AmplyReactNative
40
+ PUBLIC
41
+ ${REACT_SRC_ROOT}
42
+ ${REACT_ANDROID_SRC_DIR}
43
+ ${REACT_COMMON_DIR}
44
+ ${REACT_CALL_INVOKER_DIR}
45
+ ${REACT_TURBO_CORE_DIR}
46
+ ${REACT_JAVA_TURBO_DIR}
47
+ )
48
+
49
+ add_library(
50
+ AmplyReactNative
51
+ SHARED
52
+ AmplyTurboModule.cpp
53
+ )
54
+
55
+ target_include_directories(
56
+ AmplyReactNative
57
+ PUBLIC
58
+ ${CMAKE_CURRENT_SOURCE_DIR}
59
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../newarch/jni
60
+ ${REACT_ANDROID_SRC_DIR}
61
+ ${REACT_SRC_ROOT}
62
+ ${REACT_COMMON_DIR}
63
+ ${REACT_CALL_INVOKER_DIR}
64
+ ${REACT_TURBO_CORE_DIR}
65
+ ${REACT_JAVA_TURBO_DIR}
66
+ )
67
+
68
+ target_link_libraries(
69
+ AmplyReactNative
70
+ react_codegen_AmplyReactNative # важно
71
+ ReactAndroid::reactnative
72
+ ReactAndroid::jsi
73
+ fbjni::fbjni
74
+ )
75
+
76
+ target_compile_reactnative_options(AmplyReactNative PRIVATE)
@@ -0,0 +1,75 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateModuleJavaSpec.js
9
+ *
10
+ * @nolint
11
+ */
12
+
13
+ package tools.amply.sdk.reactnative;
14
+
15
+ import com.facebook.proguard.annotations.DoNotStrip;
16
+ import com.facebook.react.bridge.Promise;
17
+ import com.facebook.react.bridge.ReactApplicationContext;
18
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
19
+ import com.facebook.react.bridge.ReactMethod;
20
+ import com.facebook.react.bridge.ReadableMap;
21
+ import com.facebook.react.turbomodule.core.interfaces.TurboModule;
22
+ import javax.annotation.Nonnull;
23
+
24
+ public abstract class NativeAmplyModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
25
+ public static final String NAME = "Amply";
26
+
27
+ public NativeAmplyModuleSpec(ReactApplicationContext reactContext) {
28
+ super(reactContext);
29
+ }
30
+
31
+ @Override
32
+ public @Nonnull String getName() {
33
+ return NAME;
34
+ }
35
+
36
+ protected final void emitOnSystemEvent(ReadableMap value) {
37
+ mEventEmitterCallback.invoke("onSystemEvent", value);
38
+ }
39
+
40
+ protected final void emitOnDeepLink(ReadableMap value) {
41
+ mEventEmitterCallback.invoke("onDeepLink", value);
42
+ }
43
+
44
+ @ReactMethod
45
+ @DoNotStrip
46
+ public abstract void initialize(ReadableMap config, Promise promise);
47
+
48
+ @ReactMethod(isBlockingSynchronousMethod = true)
49
+ @DoNotStrip
50
+ public abstract boolean isInitialized();
51
+
52
+ @ReactMethod
53
+ @DoNotStrip
54
+ public abstract void track(ReadableMap payload, Promise promise);
55
+
56
+ @ReactMethod
57
+ @DoNotStrip
58
+ public abstract void getRecentEvents(double limit, Promise promise);
59
+
60
+ @ReactMethod
61
+ @DoNotStrip
62
+ public abstract void getDataSetSnapshot(ReadableMap type, Promise promise);
63
+
64
+ @ReactMethod
65
+ @DoNotStrip
66
+ public abstract void registerDeepLinkListener();
67
+
68
+ @ReactMethod
69
+ @DoNotStrip
70
+ public abstract void addListener(String eventName);
71
+
72
+ @ReactMethod
73
+ @DoNotStrip
74
+ public abstract void removeListeners(double count);
75
+ }
@@ -0,0 +1,77 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateModuleJniCpp.js
9
+ */
10
+
11
+ #include "AmplyReactNative.h"
12
+
13
+ namespace facebook::react {
14
+
15
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_initialize(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
16
+ static jmethodID cachedMethodId = nullptr;
17
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "initialize", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
18
+ }
19
+
20
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_isInitialized(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
21
+ static jmethodID cachedMethodId = nullptr;
22
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, BooleanKind, "isInitialized", "()Z", args, count, cachedMethodId);
23
+ }
24
+
25
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_track(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
26
+ static jmethodID cachedMethodId = nullptr;
27
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "track", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
28
+ }
29
+
30
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_getRecentEvents(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
31
+ static jmethodID cachedMethodId = nullptr;
32
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getRecentEvents", "(DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
33
+ }
34
+
35
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_getDataSetSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
36
+ static jmethodID cachedMethodId = nullptr;
37
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getDataSetSnapshot", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
38
+ }
39
+
40
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_registerDeepLinkListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
41
+ static jmethodID cachedMethodId = nullptr;
42
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "registerDeepLinkListener", "()V", args, count, cachedMethodId);
43
+ }
44
+
45
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_addListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
46
+ static jmethodID cachedMethodId = nullptr;
47
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "addListener", "(Ljava/lang/String;)V", args, count, cachedMethodId);
48
+ }
49
+
50
+ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_removeListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
51
+ static jmethodID cachedMethodId = nullptr;
52
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "removeListeners", "(D)V", args, count, cachedMethodId);
53
+ }
54
+
55
+ NativeAmplyModuleSpecJSI::NativeAmplyModuleSpecJSI(const JavaTurboModule::InitParams &params)
56
+ : JavaTurboModule(params) {
57
+ methodMap_["initialize"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_initialize};
58
+ methodMap_["isInitialized"] = MethodMetadata {0, __hostFunction_NativeAmplyModuleSpecJSI_isInitialized};
59
+ methodMap_["track"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_track};
60
+ methodMap_["getRecentEvents"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_getRecentEvents};
61
+ methodMap_["getDataSetSnapshot"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_getDataSetSnapshot};
62
+ methodMap_["registerDeepLinkListener"] = MethodMetadata {0, __hostFunction_NativeAmplyModuleSpecJSI_registerDeepLinkListener};
63
+ methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_addListener};
64
+ methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_removeListeners};
65
+ eventEmitterMap_["onSystemEvent"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
66
+ eventEmitterMap_["onDeepLink"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
67
+ configureEventEmitterCallback();
68
+ }
69
+
70
+ std::shared_ptr<TurboModule> AmplyReactNative_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
71
+ if (moduleName == "Amply") {
72
+ return std::make_shared<NativeAmplyModuleSpecJSI>(params);
73
+ }
74
+ return nullptr;
75
+ }
76
+
77
+ } // namespace facebook::react