react-native-mparticle 2.9.2 → 3.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 (34) hide show
  1. package/README.md +51 -4
  2. package/android/build.gradle +2 -2
  3. package/android/gradle.properties +1 -1
  4. package/android/src/main/java/com/mparticle/react/rokt/MPRoktModuleImpl.kt +27 -0
  5. package/android/src/newarch/java/com/mparticle/react/rokt/MPRoktModule.kt +30 -4
  6. package/android/src/oldarch/java/com/mparticle/react/NativeMPRoktSpec.kt +16 -0
  7. package/android/src/oldarch/java/com/mparticle/react/rokt/MPRoktModule.kt +28 -0
  8. package/ios/RNMParticle/RNMPRokt.mm +138 -91
  9. package/ios/RNMParticle/RNMParticle.mm +18 -24
  10. package/ios/RNMParticle/RoktEventManager.h +3 -2
  11. package/ios/RNMParticle/RoktEventManager.m +71 -33
  12. package/ios/RNMParticle/RoktLayoutManager.m +7 -2
  13. package/ios/RNMParticle/RoktNativeLayoutComponentView.h +11 -2
  14. package/ios/RNMParticle/RoktNativeLayoutComponentView.mm +2 -2
  15. package/js/codegenSpecs/NativeMParticle.ts +1 -4
  16. package/js/codegenSpecs/rokt/NativeMPRokt.ts +12 -0
  17. package/js/rokt/rokt.ts +20 -0
  18. package/lib/codegenSpecs/NativeMParticle.js.map +1 -1
  19. package/lib/codegenSpecs/rokt/NativeMPRokt.d.ts +6 -0
  20. package/lib/codegenSpecs/rokt/NativeMPRokt.js.map +1 -1
  21. package/lib/rokt/rokt.d.ts +4 -0
  22. package/lib/rokt/rokt.js +12 -0
  23. package/lib/rokt/rokt.js.map +1 -1
  24. package/package.json +5 -3
  25. package/plugin/build/customBaseUrl.d.ts +4 -0
  26. package/plugin/build/customBaseUrl.js +22 -0
  27. package/plugin/build/withMParticle.d.ts +6 -0
  28. package/plugin/build/withMParticleAndroid.js +39 -10
  29. package/plugin/build/withMParticleIOS.js +34 -3
  30. package/plugin/src/customBaseUrl.ts +31 -0
  31. package/plugin/src/withMParticle.ts +7 -0
  32. package/plugin/src/withMParticleAndroid.ts +49 -10
  33. package/plugin/src/withMParticleIOS.ts +48 -3
  34. package/react-native-mparticle.podspec +4 -3
package/README.md CHANGED
@@ -82,6 +82,7 @@ npx expo run:android
82
82
  | `dataPlanId` | string | No | Data plan ID for validation |
83
83
  | `dataPlanVersion` | number | No | Data plan version |
84
84
  | `iosKits` | string[] | No | iOS kit pod names (e.g., `['mParticle-Rokt']`) |
85
+ | `customBaseUrl` | string | No | Custom base URL for global CNAME setup on iOS and Android |
85
86
  | `androidKits` | string[] | No | Android kit artifact names (e.g., `['android-rokt-kit']`) |
86
87
  | `useEmptyIdentifyRequest` | boolean | No | Use empty user identify request at init (default: `true`) |
87
88
 
@@ -109,17 +110,27 @@ npx expo run:android
109
110
  }
110
111
  ```
111
112
 
113
+ For global CNAME setup, add the optional shared `customBaseUrl` setting:
114
+
115
+ ```json
116
+ {
117
+ "customBaseUrl": "https://cname.example.com"
118
+ }
119
+ ```
120
+
112
121
  ### What the Plugin Does
113
122
 
114
123
  **iOS:**
115
124
 
116
125
  - Adds mParticle SDK initialization to `AppDelegate` (supports both Swift and Objective-C)
126
+ - Sets `MPNetworkOptions.customBaseURL` before startup when `customBaseUrl` is configured
117
127
  - Configures `pre_install` hook in Podfile for dynamic framework linking
118
128
  - Adds specified kit pod dependencies
119
129
 
120
130
  **Android:**
121
131
 
122
132
  - Adds mParticle SDK initialization to `MainApplication` (supports both Kotlin and Java)
133
+ - Sets `NetworkOptions.setCustomBaseURL` before startup when `customBaseUrl` is configured
123
134
  - Adds specified kit Maven dependencies to `build.gradle`
124
135
 
125
136
  ### Version Support
@@ -219,6 +230,12 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau
219
230
  mParticleOptions.onAttributionComplete = { (attributionResult, error) in
220
231
  NSLog(@"Attribution Complete. attributionResults = %@", attributionResult.linkInfo)
221
232
  }
233
+
234
+ // Optional global CNAME setup. Configure before start.
235
+ let networkOptions = MPNetworkOptions()
236
+ networkOptions.customBaseURL = URL(string: "https://cname.example.com")
237
+ mParticleOptions.networkOptions = networkOptions
238
+
222
239
  MParticle.sharedInstance().start(with: mParticleOptions)
223
240
  return true
224
241
  }
@@ -260,12 +277,34 @@ Next, you'll need to start the SDK:
260
277
  NSLog(@"Attribution Complete. attributionResults = %@", attributionResult.linkInfo)
261
278
  }
262
279
 
280
+ // Optional global CNAME setup. Configure before start.
281
+ MPNetworkOptions *networkOptions = [[MPNetworkOptions alloc] init];
282
+ networkOptions.customBaseURL = [NSURL URLWithString:@"https://cname.example.com"];
283
+ mParticleOptions.networkOptions = networkOptions;
284
+
263
285
  [[MParticle sharedInstance] startWithOptions:mParticleOptions];
264
286
 
265
287
  return YES;
266
288
  }
267
289
  ```
268
290
 
291
+ ### Rokt iOS Setup
292
+
293
+ For standard Rokt placements, add the mParticle Rokt kit:
294
+
295
+ ```ruby
296
+ pod 'mParticle-Rokt', '~> 9.2'
297
+ ```
298
+
299
+ In Expo apps, use `iosKits: ["mParticle-Rokt"]` for standard Rokt placements. The Expo plugin does not add payment-extension pods or URL callback forwarding in this release.
300
+
301
+ See [MIGRATING.md](./MIGRATING.md) for release-specific migration guidance.
302
+
303
+ For Android integrations that use `MParticle.Rokt.setSessionId()` or
304
+ `MParticle.Rokt.getSessionId()`, `android-core` and `android-rokt-kit`
305
+ `5.79.0` or newer are required. Android CNAME setup through
306
+ `customBaseUrl` also requires `android-core` `5.79.0` or newer.
307
+
269
308
  See [Identity](http://docs.mparticle.com/developers/sdk/ios/identity/) for more information on supplying an `MPIdentityApiRequest` object during SDK initialization.
270
309
 
271
310
  4. Remember to start Metro with:
@@ -285,13 +324,15 @@ and build your workspace from xCode.
285
324
  For more help, see [the Android set up docs](https://docs.mparticle.com/developers/sdk/android/getting-started/#create-an-input).
286
325
 
287
326
  ```kotlin
288
- package com.example.myapp;
327
+ package com.example.myapp
289
328
 
290
- import android.app.Application;
291
- import com.mparticle.MParticle;
329
+ import android.app.Application
330
+ import com.mparticle.MParticle
331
+ import com.mparticle.MParticleOptions
332
+ import com.mparticle.networking.NetworkOptions
292
333
 
293
334
  class MyApplication : Application() {
294
- fun onCreate() {
335
+ override fun onCreate() {
295
336
  super.onCreate()
296
337
  val options: MParticleOptions = MParticleOptions.builder(this)
297
338
  .credentials("REPLACE ME WITH KEY", "REPLACE ME WITH SECRET")
@@ -299,6 +340,12 @@ class MyApplication : Application() {
299
340
  .logLevel(MParticle.LogLevel.VERBOSE)
300
341
  //optional
301
342
  .identify(identifyRequest)
343
+ //optional global CNAME setup
344
+ .networkOptions(
345
+ NetworkOptions.builder()
346
+ .setCustomBaseURL("https://cname.example.com")
347
+ .build()
348
+ )
302
349
  //optional
303
350
  .identifyTask(
304
351
  BaseIdentityTask()
@@ -118,7 +118,7 @@ dependencies {
118
118
  //
119
119
  // (See https://github.com/mparticle/mparticle-android-sdk for the latest version)
120
120
  //
121
- api 'com.mparticle:android-core:[5.9.3, )'
121
+ api 'com.mparticle:android-core:[5.79.0, )'
122
122
 
123
123
  //
124
124
  // And, if you want to include kits, you can do so as follows:
@@ -134,6 +134,6 @@ dependencies {
134
134
  testImplementation 'junit:junit:4.13.2'
135
135
  testImplementation files('libs/java-json.jar')
136
136
 
137
- testImplementation 'com.mparticle:android-core:5+'
137
+ testImplementation 'com.mparticle:android-core:5.79.0'
138
138
  testImplementation("com.facebook.react:react-android:+")
139
139
  }
@@ -10,7 +10,7 @@
10
10
  # Specifies the JVM arguments used for the daemon process.
11
11
  # The setting is particularly useful for tweaking memory settings.
12
12
  # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13
- org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
13
+ org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m
14
14
 
15
15
  # When configured, Gradle will run in incubating parallel mode.
16
16
  # This option should only be used with decoupled projects. More details, visit
@@ -6,6 +6,7 @@ import androidx.lifecycle.LifecycleOwner
6
6
  import androidx.lifecycle.lifecycleScope
7
7
  import androidx.lifecycle.repeatOnLifecycle
8
8
  import com.facebook.react.bridge.Arguments
9
+ import com.facebook.react.bridge.Promise
9
10
  import com.facebook.react.bridge.ReactApplicationContext
10
11
  import com.facebook.react.bridge.ReactContext
11
12
  import com.facebook.react.bridge.ReadableMap
@@ -16,6 +17,7 @@ import com.mparticle.MpRoktEventCallback
16
17
  import com.mparticle.RoktEvent
17
18
  import com.mparticle.UnloadReasons
18
19
  import com.mparticle.WrapperSdk
20
+ import com.mparticle.internal.Logger
19
21
  import com.mparticle.rokt.CacheConfig
20
22
  import com.mparticle.rokt.RoktConfig
21
23
  import kotlinx.coroutines.Job
@@ -39,6 +41,14 @@ class MPRoktModuleImpl(
39
41
 
40
42
  fun getName(): String = MODULE_NAME
41
43
 
44
+ fun selectShoppableAds(
45
+ identifier: String,
46
+ attributes: ReadableMap?,
47
+ roktConfig: ReadableMap?,
48
+ ) {
49
+ Logger.warning("selectShoppableAds is not yet supported on Android")
50
+ }
51
+
42
52
  fun purchaseFinalized(
43
53
  placementId: String,
44
54
  catalogItemId: String,
@@ -47,6 +57,23 @@ class MPRoktModuleImpl(
47
57
  MParticle.getInstance()?.Rokt()?.purchaseFinalized(placementId, catalogItemId, success)
48
58
  }
49
59
 
60
+ fun close(promise: Promise) {
61
+ MParticle.getInstance()?.Rokt()?.close()
62
+ promise.resolve(null)
63
+ }
64
+
65
+ fun setSessionId(
66
+ sessionId: String,
67
+ promise: Promise,
68
+ ) {
69
+ MParticle.getInstance()?.Rokt()?.setSessionId(sessionId)
70
+ promise.resolve(null)
71
+ }
72
+
73
+ fun getSessionId(promise: Promise) {
74
+ promise.resolve(MParticle.getInstance()?.Rokt()?.getSessionId())
75
+ }
76
+
50
77
  fun setRoktEventHandler(roktEventHandler: MpRoktEventCallback) {
51
78
  this.roktEventHandler = roktEventHandler
52
79
  }
@@ -1,5 +1,6 @@
1
1
  package com.mparticle.react.rokt
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
4
5
  import com.facebook.react.bridge.ReactMethod
5
6
  import com.facebook.react.bridge.ReadableMap
@@ -7,17 +8,15 @@ import com.facebook.react.bridge.ReadableType
7
8
  import com.facebook.react.bridge.UiThreadUtil
8
9
  import com.facebook.react.uimanager.UIManagerHelper
9
10
  import com.mparticle.MParticle
10
- import com.mparticle.WrapperSdk
11
+ import com.mparticle.internal.Logger
11
12
  import com.mparticle.react.NativeMPRoktSpec
12
13
  import com.mparticle.rokt.RoktEmbeddedView
13
- import com.mparticle.internal.Logger
14
14
  import java.lang.ref.WeakReference
15
15
  import java.util.concurrent.CountDownLatch
16
16
 
17
17
  class MPRoktModule(
18
18
  private val reactContext: ReactApplicationContext,
19
19
  ) : NativeMPRoktSpec(reactContext) {
20
-
21
20
  private val impl = MPRoktModuleImpl(reactContext)
22
21
 
23
22
  override fun getName(): String = impl.getName()
@@ -52,6 +51,15 @@ class MPRoktModule(
52
51
  )
53
52
  }
54
53
 
54
+ @ReactMethod
55
+ override fun selectShoppableAds(
56
+ identifier: String,
57
+ attributes: ReadableMap?,
58
+ roktConfig: ReadableMap?,
59
+ ) {
60
+ impl.selectShoppableAds(identifier, attributes, roktConfig)
61
+ }
62
+
55
63
  @ReactMethod
56
64
  override fun purchaseFinalized(
57
65
  placementId: String,
@@ -61,6 +69,23 @@ class MPRoktModule(
61
69
  impl.purchaseFinalized(placementId, catalogItemId, success)
62
70
  }
63
71
 
72
+ @ReactMethod
73
+ override fun close(promise: Promise) {
74
+ impl.close(promise)
75
+ }
76
+
77
+ @ReactMethod
78
+ override fun setSessionId(
79
+ sessionId: String,
80
+ promise: Promise,
81
+ ) {
82
+ impl.setSessionId(sessionId, promise)
83
+ }
84
+
85
+ @ReactMethod
86
+ override fun getSessionId(promise: Promise) {
87
+ impl.getSessionId(promise)
88
+ }
64
89
 
65
90
  /**
66
91
  * Process placeholders from ReadableMap to a map of Widgets for use with Rokt.
@@ -83,8 +108,9 @@ class MPRoktModule(
83
108
  // Get the tag value as an integer
84
109
  val reactTag =
85
110
  when {
86
- placeholders.getType(key) == ReadableType.Number ->
111
+ placeholders.getType(key) == ReadableType.Number -> {
87
112
  placeholders.getDouble(key).toInt()
113
+ }
88
114
 
89
115
  else -> {
90
116
  Logger.warning("Invalid view tag for key: $key")
@@ -1,5 +1,6 @@
1
1
  package com.mparticle.react
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
4
5
  import com.facebook.react.bridge.ReactContextBaseJavaModule
5
6
  import com.facebook.react.bridge.ReadableMap
@@ -21,9 +22,24 @@ abstract class NativeMPRoktSpec(
21
22
  fontFilesMap: ReadableMap?,
22
23
  )
23
24
 
25
+ abstract fun selectShoppableAds(
26
+ identifier: String,
27
+ attributes: ReadableMap?,
28
+ roktConfig: ReadableMap?,
29
+ )
30
+
24
31
  abstract fun purchaseFinalized(
25
32
  placementId: String,
26
33
  catalogItemId: String,
27
34
  success: Boolean,
28
35
  )
36
+
37
+ abstract fun close(promise: Promise)
38
+
39
+ abstract fun setSessionId(
40
+ sessionId: String,
41
+ promise: Promise,
42
+ )
43
+
44
+ abstract fun getSessionId(promise: Promise)
29
45
  }
@@ -1,5 +1,6 @@
1
1
  package com.mparticle.react.rokt
2
2
 
3
+ import com.facebook.react.bridge.Promise
3
4
  import com.facebook.react.bridge.ReactApplicationContext
4
5
  import com.facebook.react.bridge.ReactMethod
5
6
  import com.facebook.react.bridge.ReadableMap
@@ -48,6 +49,15 @@ class MPRoktModule(
48
49
  }
49
50
  }
50
51
 
52
+ @ReactMethod
53
+ override fun selectShoppableAds(
54
+ identifier: String,
55
+ attributes: ReadableMap?,
56
+ roktConfig: ReadableMap?,
57
+ ) {
58
+ impl.selectShoppableAds(identifier, attributes, roktConfig)
59
+ }
60
+
51
61
  @ReactMethod
52
62
  override fun purchaseFinalized(
53
63
  placementId: String,
@@ -57,6 +67,24 @@ class MPRoktModule(
57
67
  impl.purchaseFinalized(placementId, catalogItemId, success)
58
68
  }
59
69
 
70
+ @ReactMethod
71
+ override fun close(promise: Promise) {
72
+ impl.close(promise)
73
+ }
74
+
75
+ @ReactMethod
76
+ override fun setSessionId(
77
+ sessionId: String,
78
+ promise: Promise,
79
+ ) {
80
+ impl.setSessionId(sessionId, promise)
81
+ }
82
+
83
+ @ReactMethod
84
+ override fun getSessionId(promise: Promise) {
85
+ impl.getSessionId(promise)
86
+ }
87
+
60
88
  private fun safeUnwrapPlaceholders(
61
89
  placeholders: ReadableMap?,
62
90
  nativeViewHierarchyManager: NativeViewHierarchyManager,
@@ -1,20 +1,22 @@
1
1
  #import "RNMPRokt.h"
2
- #if defined(__has_include) && __has_include(<mParticle_Apple_SDK/mParticle.h>)
2
+ // SDK 9.0: ObjC headers moved to mParticle_Apple_SDK_ObjC module
3
+ #if defined(__has_include) && __has_include(<mParticle_Apple_SDK_ObjC/mParticle.h>)
4
+ #import <mParticle_Apple_SDK_ObjC/mParticle.h>
5
+ #import <mParticle_Apple_SDK_ObjC/MPRokt.h>
6
+ #elif defined(__has_include) && __has_include(<mParticle_Apple_SDK/mParticle.h>)
3
7
  #import <mParticle_Apple_SDK/mParticle.h>
4
8
  #import <mParticle_Apple_SDK/MPRokt.h>
5
- #elif defined(__has_include) && __has_include(<mParticle_Apple_SDK_NoLocation/mParticle.h>)
6
- #import <mParticle_Apple_SDK_NoLocation/mParticle.h>
7
9
  #else
8
- #import <mParticle_Apple_SDK/Include/mParticle.h>
10
+ #import <mParticle_Apple_SDK_ObjC/mParticle.h>
11
+ #import <mParticle_Apple_SDK_ObjC/MPRokt.h>
9
12
  #endif
10
- #if defined(__has_include) && __has_include(<mParticle_Apple_SDK/mParticle_Apple_SDK-Swift.h>)
11
- #import <mParticle_Apple_SDK/mParticle_Apple_SDK-Swift.h>
12
- #elif defined(__has_include) && __has_include(<mParticle_Apple_SDK_NoLocation/mParticle_Apple_SDK-Swift.h>)
13
- #import <mParticle_Apple_SDK_NoLocation/mParticle_Apple_SDK-Swift.h>
14
- #else
15
- #import "mParticle_Apple_SDK-Swift.h"
13
+ #if __has_include(<RoktContracts/RoktContracts-Swift.h>)
14
+ #import <RoktContracts/RoktContracts-Swift.h>
15
+ #elif __has_include(<RoktContracts/RoktContracts.h>)
16
+ #import <RoktContracts/RoktContracts.h>
16
17
  #endif
17
18
  #import <React/RCTConvert.h>
19
+ #import <React/RCTBridgeModule.h>
18
20
  #import <React/RCTEventEmitter.h>
19
21
  #import <React/RCTViewManager.h>
20
22
  #import <React/RCTUIManager.h>
@@ -81,6 +83,12 @@ RCT_EXTERN void RCTRegisterModule(Class);
81
83
  // We always return the UI manager's method queue
82
84
  }
83
85
 
86
+ - (void)ensureEventManager {
87
+ if (self.eventManager == nil) {
88
+ self.eventManager = [RoktEventManager allocWithZone: nil];
89
+ }
90
+ }
91
+
84
92
  #ifdef RCT_NEW_ARCH_ENABLED
85
93
  // Extracts roktConfig fields into an NSDictionary, returning nil when the
86
94
  // TurboModule bridge passes a null C++ reference for an omitted optional param.
@@ -112,7 +120,7 @@ static NSDictionary * __attribute__((optnone)) safeExtractRoktConfigDict(
112
120
  return roktConfigDict;
113
121
  }
114
122
 
115
- // New Architecture Implementation
123
+ // New Architecture Implementation — selectPlacements
116
124
  - (void)selectPlacements:(NSString *)identifer
117
125
  attributes:(NSDictionary *)attributes
118
126
  placeholders:(NSDictionary *)placeholders
@@ -123,48 +131,22 @@ static NSDictionary * __attribute__((optnone)) safeExtractRoktConfigDict(
123
131
  NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes];
124
132
 
125
133
  NSDictionary *roktConfigDict = safeExtractRoktConfigDict(roktConfig);
126
- MPRoktConfig *config = [self buildRoktConfigFromDict:roktConfigDict];
134
+ RoktConfig *config = [self buildRoktConfigFromDict:roktConfigDict];
127
135
  #else
128
- // Old Architecture Implementation
136
+ // Old Architecture Implementation — selectPlacements
129
137
  RCT_EXPORT_METHOD(selectPlacements:(NSString *) identifer attributes:(NSDictionary *)attributes placeholders:(NSDictionary * _Nullable)placeholders roktConfig:(NSDictionary * _Nullable)roktConfig fontFilesMap:(NSDictionary * _Nullable)fontFilesMap)
130
138
  {
131
139
  _rokt_log(@"[mParticle-Rokt] Old Architecture Implementation");
132
140
  NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes];
133
- MPRoktConfig *config = [self buildRoktConfigFromDict:roktConfig];
141
+ RoktConfig *config = [self buildRoktConfigFromDict:roktConfig];
134
142
  #endif
135
143
 
136
144
  _rokt_log(@"[mParticle-Rokt] selectPlacements called with identifier: %@, attributes count: %lu", identifer, (unsigned long)finalAttributes.count);
137
145
 
138
146
  [MParticle _setWrapperSdk_internal:MPWrapperSdkReactNative version:@""];
139
- // Create callback implementation
140
- MPRoktEventCallback *callbacks = [[MPRoktEventCallback alloc] init];
147
+ [self ensureEventManager];
141
148
  __weak __typeof__(self) weakSelf = self;
142
149
 
143
- callbacks.onLoad = ^{
144
- _rokt_log(@"[mParticle-Rokt] onLoad");
145
- [weakSelf.eventManager onRoktCallbackReceived:@"onLoad"];
146
- };
147
-
148
- callbacks.onUnLoad = ^{
149
- _rokt_log(@"[mParticle-Rokt] onUnLoad");
150
- [weakSelf.eventManager onRoktCallbackReceived:@"onUnLoad"];
151
- };
152
-
153
- callbacks.onShouldShowLoadingIndicator = ^{
154
- _rokt_log(@"[mParticle-Rokt] onShouldShowLoadingIndicator");
155
- [weakSelf.eventManager onRoktCallbackReceived:@"onShouldShowLoadingIndicator"];
156
- };
157
-
158
- callbacks.onShouldHideLoadingIndicator = ^{
159
- _rokt_log(@"[mParticle-Rokt] onShouldHideLoadingIndicator");
160
- [weakSelf.eventManager onRoktCallbackReceived:@"onShouldHideLoadingIndicator"];
161
- };
162
-
163
- callbacks.onEmbeddedSizeChange = ^(NSString *placementId, CGFloat height) {
164
- _rokt_log(@"[mParticle-Rokt] onEmbeddedSizeChange");
165
- [weakSelf.eventManager onWidgetHeightChanges:height placement:placementId];
166
- };
167
-
168
150
  BOOL bridgeNil = (self.bridge == nil);
169
151
  BOOL uiManagerNil = (self.bridge.uiManager == nil);
170
152
  _rokt_log(@"[mParticle-Rokt] bridge %@, uiManager %@", bridgeNil ? @"nil" : @"non-nil", uiManagerNil ? @"nil" : @"non-nil");
@@ -180,10 +162,6 @@ RCT_EXPORT_METHOD(selectPlacements:(NSString *) identifer attributes:(NSDictiona
180
162
 
181
163
  NSMutableDictionary *nativePlaceholders = strongSelf ? [strongSelf getNativePlaceholders:placeholders viewRegistry:viewRegistry] : [NSMutableDictionary dictionary];
182
164
 
183
- if (strongSelf) {
184
- [strongSelf subscribeViewEvents:identifer];
185
- }
186
-
187
165
  id mpInstance = [MParticle sharedInstance];
188
166
  id roktKit = mpInstance ? [mpInstance rokt] : nil;
189
167
  _rokt_log(@"[mParticle-Rokt] MParticle sharedInstance %@, rokt kit %@", mpInstance ? @"non-nil" : @"nil", roktKit ? @"non-nil" : @"nil");
@@ -192,11 +170,103 @@ RCT_EXPORT_METHOD(selectPlacements:(NSString *) identifer attributes:(NSDictiona
192
170
  attributes:finalAttributes
193
171
  embeddedViews:nativePlaceholders
194
172
  config:config
195
- callbacks:callbacks];
173
+ onEvent:^(RoktEvent * _Nonnull event) {
174
+ [weakSelf.eventManager onRoktEvents:event viewName:identifer];
175
+ }];
196
176
  }];
197
177
  _rokt_log(@"[mParticle-Rokt] addUIBlock enqueued for identifier: %@", identifer);
198
178
  }
199
179
 
180
+ #ifdef RCT_NEW_ARCH_ENABLED
181
+ // New Architecture Implementation — selectShoppableAds
182
+ - (void)selectShoppableAds:(NSString *)identifier
183
+ attributes:(NSDictionary *)attributes
184
+ roktConfig:(JS::NativeMPRokt::RoktConfigType &)roktConfig
185
+ {
186
+ _rokt_log(@"[mParticle-Rokt] selectShoppableAds New Architecture");
187
+ NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes];
188
+ NSDictionary *roktConfigDict = safeExtractRoktConfigDict(roktConfig);
189
+ RoktConfig *config = [self buildRoktConfigFromDict:roktConfigDict];
190
+ #else
191
+ // Old Architecture Implementation — selectShoppableAds
192
+ RCT_EXPORT_METHOD(selectShoppableAds:(NSString *)identifier attributes:(NSDictionary *)attributes roktConfig:(NSDictionary * _Nullable)roktConfig)
193
+ {
194
+ _rokt_log(@"[mParticle-Rokt] selectShoppableAds Old Architecture");
195
+ NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes];
196
+ RoktConfig *config = [self buildRoktConfigFromDict:roktConfig];
197
+ #endif
198
+
199
+ _rokt_log(@"[mParticle-Rokt] selectShoppableAds called with identifier: %@, attributes count: %lu", identifier, (unsigned long)finalAttributes.count);
200
+
201
+ [MParticle _setWrapperSdk_internal:MPWrapperSdkReactNative version:@""];
202
+ [self ensureEventManager];
203
+ __weak __typeof__(self) weakSelf = self;
204
+
205
+ [[[MParticle sharedInstance] rokt] selectShoppableAds:identifier
206
+ attributes:finalAttributes
207
+ config:config
208
+ onEvent:^(RoktEvent * _Nonnull event) {
209
+ [weakSelf.eventManager onRoktEvents:event viewName:identifier];
210
+ }];
211
+ }
212
+
213
+ #ifdef RCT_NEW_ARCH_ENABLED
214
+ - (void)close:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
215
+ {
216
+ (void)reject;
217
+ [self closeWithResolve:resolve];
218
+ }
219
+
220
+ - (void)setSessionId:(NSString *)sessionId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
221
+ {
222
+ (void)reject;
223
+ [self setSessionIdWithString:sessionId resolve:resolve];
224
+ }
225
+
226
+ - (void)getSessionId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
227
+ {
228
+ (void)reject;
229
+ [self getSessionIdWithResolve:resolve];
230
+ }
231
+ #else
232
+ RCT_EXPORT_METHOD(close:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
233
+ {
234
+ (void)reject;
235
+ [self closeWithResolve:resolve];
236
+ }
237
+
238
+ RCT_EXPORT_METHOD(setSessionId:(NSString *)sessionId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
239
+ {
240
+ (void)reject;
241
+ [self setSessionIdWithString:sessionId resolve:resolve];
242
+ }
243
+
244
+ RCT_EXPORT_METHOD(getSessionId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
245
+ {
246
+ (void)reject;
247
+ [self getSessionIdWithResolve:resolve];
248
+ }
249
+ #endif
250
+
251
+ - (void)closeWithResolve:(RCTPromiseResolveBlock)resolve
252
+ {
253
+ [[[MParticle sharedInstance] rokt] close];
254
+ resolve(nil);
255
+ }
256
+
257
+ - (void)setSessionIdWithString:(NSString *)sessionId
258
+ resolve:(RCTPromiseResolveBlock)resolve
259
+ {
260
+ [[[MParticle sharedInstance] rokt] setSessionId:sessionId ?: @""];
261
+ resolve(nil);
262
+ }
263
+
264
+ - (void)getSessionIdWithResolve:(RCTPromiseResolveBlock)resolve
265
+ {
266
+ NSString *sessionId = [[[MParticle sharedInstance] rokt] getSessionId];
267
+ resolve(sessionId ?: [NSNull null]);
268
+ }
269
+
200
270
  RCT_EXPORT_METHOD(purchaseFinalized : (NSString *)placementId catalogItemId : (
201
271
  NSString *)catalogItemId success : (BOOL)success) {
202
272
  [[[MParticle sharedInstance] rokt] purchaseFinalized:placementId
@@ -209,48 +279,35 @@ RCT_EXPORT_METHOD(purchaseFinalized : (NSString *)placementId catalogItemId : (
209
279
  NSMutableDictionary *finalAttributes = [attributes mutableCopy];
210
280
  NSArray *keysForNullValues = [finalAttributes allKeysForObject:[NSNull null]];
211
281
  [finalAttributes removeObjectsForKeys:keysForNullValues];
212
-
282
+
213
283
  NSSet *keys = [finalAttributes keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
214
284
  return ![obj isKindOfClass:[NSString class]];
215
285
  }];
216
-
286
+
217
287
  [finalAttributes removeObjectsForKeys:[keys allObjects]];
218
288
  return finalAttributes;
219
-
220
- }
221
289
 
222
- - (MPColorMode)stringToColorMode:(NSString*)colorString
223
- {
224
- if ([colorString isEqualToString:@"light"]) {
225
- return MPColorModeLight;
226
- }
227
- else if ([colorString isEqualToString:@"dark"]) {
228
- return MPColorModeDark;
229
- }
230
- else {
231
- return MPColorModeSystem;
232
- }
233
290
  }
234
291
 
235
- - (MPRoktConfig *)buildRoktConfigFromDict:(NSDictionary<NSString *, id> *)configMap {
292
+ - (RoktConfig *)buildRoktConfigFromDict:(NSDictionary<NSString *, id> *)configMap {
236
293
  _rokt_log(@"[mParticle-Rokt] buildRoktConfigFromDict: configMap %@", configMap == nil ? @"nil" : [NSString stringWithFormat:@"non-nil (%lu keys)", (unsigned long)configMap.count]);
237
- MPRoktConfig *config = [[MPRoktConfig alloc] init];
294
+ if (configMap == nil || configMap.count == 0) {
295
+ _rokt_log(@"[mParticle-Rokt] buildRoktConfigFromDict: returning nil");
296
+ return nil;
297
+ }
298
+
299
+ RoktConfigBuilder *builder = [[RoktConfigBuilder alloc] init];
238
300
  BOOL isConfigEmpty = YES;
239
301
 
240
302
  NSString *colorModeString = configMap[@"colorMode"];
241
303
  if (colorModeString && [colorModeString isKindOfClass:[NSString class]]) {
242
- if (@available(iOS 12.0, *)) {
243
- isConfigEmpty = NO;
244
- if ([colorModeString isEqualToString:@"dark"]) {
245
- if (@available(iOS 13.0, *)) {
246
- config.colorMode = MPColorModeDark;
247
- }
248
- } else if ([colorModeString isEqualToString:@"light"]) {
249
- config.colorMode = MPColorModeLight;
250
- } else {
251
- // default: "system"
252
- config.colorMode = MPColorModeSystem;
253
- }
304
+ isConfigEmpty = NO;
305
+ if ([colorModeString isEqualToString:@"dark"]) {
306
+ [builder colorMode:RoktColorModeDark];
307
+ } else if ([colorModeString isEqualToString:@"light"]) {
308
+ [builder colorMode:RoktColorModeLight];
309
+ } else {
310
+ [builder colorMode:RoktColorModeSystem];
254
311
  }
255
312
  }
256
313
 
@@ -262,23 +319,13 @@ RCT_EXPORT_METHOD(purchaseFinalized : (NSString *)placementId catalogItemId : (
262
319
  cacheDuration = @0;
263
320
  }
264
321
  NSDictionary<NSString *, NSString *> *cacheAttributes = cacheConfigMap[@"cacheAttributes"];
265
- config.cacheAttributes = cacheAttributes;
266
- config.cacheDuration = cacheDuration;
322
+ RoktCacheConfig *cacheConfig = [[RoktCacheConfig alloc] initWithCacheDuration:[cacheDuration longLongValue]
323
+ cacheAttributes:cacheAttributes ?: @{}];
324
+ [builder cacheConfig:cacheConfig];
267
325
  }
268
326
 
269
327
  _rokt_log(@"[mParticle-Rokt] buildRoktConfigFromDict: returning %@", isConfigEmpty ? @"nil" : @"config");
270
- return isConfigEmpty ? nil : config;
271
- }
272
-
273
- - (void)subscribeViewEvents:(NSString* _Nonnull) viewName
274
- {
275
- _rokt_log(@"[mParticle-Rokt] subscribeViewEvents for viewName: %@", viewName);
276
- if (self.eventManager == nil) {
277
- self.eventManager = [RoktEventManager allocWithZone: nil];
278
- }
279
- [[[MParticle sharedInstance] rokt] events:viewName onEvent:^(MPRoktEvent * _Nonnull roktEvent) {
280
- [self.eventManager onRoktEvents:roktEvent viewName:viewName];
281
- }];
328
+ return isConfigEmpty ? nil : [builder build];
282
329
  }
283
330
 
284
331
  - (NSMutableDictionary *)getNativePlaceholders:(NSDictionary *)placeholders viewRegistry:(NSDictionary<NSNumber *, UIView *> *)viewRegistry
@@ -295,8 +342,8 @@ RCT_EXPORT_METHOD(purchaseFinalized : (NSString *)placementId catalogItemId : (
295
342
  }
296
343
  nativePlaceholders[key] = wrapperView.roktEmbeddedView;
297
344
  #else
298
- MPRoktEmbeddedView *view = viewRegistry[[placeholders objectForKey:key]];
299
- if (!view || ![view isKindOfClass:[MPRoktEmbeddedView class]]) {
345
+ RoktEmbeddedView *view = viewRegistry[[placeholders objectForKey:key]];
346
+ if (!view || ![view isKindOfClass:[RoktEmbeddedView class]]) {
300
347
  RCTLogError(@"Cannot find RoktEmbeddedView with tag #%@", key);
301
348
  continue;
302
349
  }