cloudx-react-native 3.4.6 → 3.6.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 (114) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +16 -0
  3. package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +14 -0
  4. package/android/src/main/java/com/cloudxreactnative/CloudXAdView.kt +238 -0
  5. package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +28 -0
  6. package/android/src/main/java/com/cloudxreactnative/CloudXAdViewManagerImpl.kt +54 -0
  7. package/android/src/main/java/com/cloudxreactnative/CloudXExtraParameters.kt +101 -0
  8. package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +171 -57
  9. package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +1 -1
  10. package/android/src/newarch/com/cloudxreactnative/CloudXAdViewManager.kt +52 -0
  11. package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +7 -0
  12. package/android/src/oldarch/com/cloudxreactnative/CloudXAdViewManager.kt +46 -0
  13. package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +7 -0
  14. package/cloudx-react-native.podspec +3 -3
  15. package/ios/CloudX.h +2 -2
  16. package/ios/CloudX.mm +268 -62
  17. package/ios/CloudXAdView.h +33 -0
  18. package/ios/CloudXAdView.mm +500 -0
  19. package/ios/CloudXAdViewManager.h +12 -0
  20. package/ios/CloudXAdViewManager.mm +38 -0
  21. package/ios/CloudXExtraParameters.h +27 -0
  22. package/ios/CloudXExtraParameters.mm +117 -0
  23. package/lib/commonjs/CloudX.js +5 -1
  24. package/lib/commonjs/CloudX.js.map +1 -1
  25. package/lib/commonjs/CloudXAdViewBase.js +250 -0
  26. package/lib/commonjs/CloudXAdViewBase.js.map +1 -0
  27. package/lib/commonjs/CloudXAppOpenAd.js +98 -0
  28. package/lib/commonjs/CloudXAppOpenAd.js.map +1 -0
  29. package/lib/commonjs/CloudXBannerView.js +27 -0
  30. package/lib/commonjs/CloudXBannerView.js.map +1 -0
  31. package/lib/commonjs/CloudXMRECView.js +27 -0
  32. package/lib/commonjs/CloudXMRECView.js.map +1 -0
  33. package/lib/commonjs/hooks.js +81 -0
  34. package/lib/commonjs/hooks.js.map +1 -1
  35. package/lib/commonjs/index.js +53 -0
  36. package/lib/commonjs/index.js.map +1 -1
  37. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +30 -0
  38. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -0
  39. package/lib/commonjs/specs/NativeCloudX.js.map +1 -1
  40. package/lib/commonjs/types/AppOpenAd.js +6 -0
  41. package/lib/commonjs/types/AppOpenAd.js.map +1 -0
  42. package/lib/commonjs/types/RevenueData.js +21 -0
  43. package/lib/commonjs/types/RevenueData.js.map +1 -0
  44. package/lib/commonjs/types/index.js +17 -0
  45. package/lib/commonjs/types/index.js.map +1 -1
  46. package/lib/commonjs/version.js +1 -1
  47. package/lib/module/CloudX.js +5 -1
  48. package/lib/module/CloudX.js.map +1 -1
  49. package/lib/module/CloudXAdViewBase.js +242 -0
  50. package/lib/module/CloudXAdViewBase.js.map +1 -0
  51. package/lib/module/CloudXAppOpenAd.js +91 -0
  52. package/lib/module/CloudXAppOpenAd.js.map +1 -0
  53. package/lib/module/CloudXBannerView.js +19 -0
  54. package/lib/module/CloudXBannerView.js.map +1 -0
  55. package/lib/module/CloudXMRECView.js +19 -0
  56. package/lib/module/CloudXMRECView.js.map +1 -0
  57. package/lib/module/hooks.js +80 -0
  58. package/lib/module/hooks.js.map +1 -1
  59. package/lib/module/index.js +10 -1
  60. package/lib/module/index.js.map +1 -1
  61. package/lib/module/specs/CloudXAdViewNativeComponent.js +27 -0
  62. package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -0
  63. package/lib/module/specs/NativeCloudX.js.map +1 -1
  64. package/lib/module/types/AppOpenAd.js +2 -0
  65. package/lib/module/types/AppOpenAd.js.map +1 -0
  66. package/lib/module/types/RevenueData.js +15 -0
  67. package/lib/module/types/RevenueData.js.map +1 -0
  68. package/lib/module/types/index.js +1 -1
  69. package/lib/module/types/index.js.map +1 -1
  70. package/lib/module/version.js +1 -1
  71. package/lib/typescript/src/CloudX.d.ts.map +1 -1
  72. package/lib/typescript/src/CloudXAdViewBase.d.ts +28 -0
  73. package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -0
  74. package/lib/typescript/src/CloudXAppOpenAd.d.ts +4 -0
  75. package/lib/typescript/src/CloudXAppOpenAd.d.ts.map +1 -0
  76. package/lib/typescript/src/CloudXBannerView.d.ts +16 -0
  77. package/lib/typescript/src/CloudXBannerView.d.ts.map +1 -0
  78. package/lib/typescript/src/CloudXMRECView.d.ts +16 -0
  79. package/lib/typescript/src/CloudXMRECView.d.ts.map +1 -0
  80. package/lib/typescript/src/hooks.d.ts +14 -0
  81. package/lib/typescript/src/hooks.d.ts.map +1 -1
  82. package/lib/typescript/src/index.d.ts +9 -3
  83. package/lib/typescript/src/index.d.ts.map +1 -1
  84. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +62 -0
  85. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -0
  86. package/lib/typescript/src/specs/NativeCloudX.d.ts +13 -0
  87. package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -1
  88. package/lib/typescript/src/types/AdProps.d.ts +3 -0
  89. package/lib/typescript/src/types/AdProps.d.ts.map +1 -1
  90. package/lib/typescript/src/types/AppOpenAd.d.ts +8 -0
  91. package/lib/typescript/src/types/AppOpenAd.d.ts.map +1 -0
  92. package/lib/typescript/src/types/CloudX.d.ts +6 -0
  93. package/lib/typescript/src/types/CloudX.d.ts.map +1 -1
  94. package/lib/typescript/src/types/RevenueData.d.ts +32 -0
  95. package/lib/typescript/src/types/RevenueData.d.ts.map +1 -0
  96. package/lib/typescript/src/types/index.d.ts +3 -0
  97. package/lib/typescript/src/types/index.d.ts.map +1 -1
  98. package/lib/typescript/src/version.d.ts +1 -1
  99. package/package.json +6 -2
  100. package/src/CloudX.ts +6 -0
  101. package/src/CloudXAdViewBase.tsx +294 -0
  102. package/src/CloudXAppOpenAd.ts +109 -0
  103. package/src/CloudXBannerView.tsx +20 -0
  104. package/src/CloudXMRECView.tsx +20 -0
  105. package/src/hooks.ts +103 -0
  106. package/src/index.ts +22 -2
  107. package/src/specs/CloudXAdViewNativeComponent.ts +84 -0
  108. package/src/specs/NativeCloudX.ts +22 -0
  109. package/src/types/AdProps.ts +4 -0
  110. package/src/types/AppOpenAd.ts +8 -0
  111. package/src/types/CloudX.ts +7 -0
  112. package/src/types/RevenueData.ts +39 -0
  113. package/src/types/index.ts +3 -0
  114. package/src/version.ts +1 -1
package/ios/CloudX.mm CHANGED
@@ -4,7 +4,9 @@
4
4
  //
5
5
 
6
6
  #import "CloudX.h"
7
+ #import "CloudXExtraParameters.h"
7
8
  #import <React/RCTUtils.h>
9
+ #import <math.h>
8
10
 
9
11
 
10
12
  @interface UIColor (CLXUtils)
@@ -57,6 +59,7 @@
57
59
 
58
60
  // Fullscreen ad storage — lazily created on first load/show, keyed by ad unit ID.
59
61
  @property (nonatomic, strong) NSMutableDictionary<NSString *, CLXInterstitial *> *interstitials;
62
+ @property (nonatomic, strong) NSMutableDictionary<NSString *, CLXAppOpen *> *appOpenAds;
60
63
  @property (nonatomic, strong) NSMutableDictionary<NSString *, CLXRewarded *> *rewardedAds;
61
64
 
62
65
  // Overlay banner/MREC state — each ad unit ID owns exactly one CLXBannerAdView,
@@ -107,6 +110,14 @@ static NSString *const ON_INTERSTITIAL_DISPLAY_FAILED_EVENT = @"OnInterstitialD
107
110
  static NSString *const ON_INTERSTITIAL_HIDDEN_EVENT = @"OnInterstitialHiddenEvent";
108
111
  static NSString *const ON_INTERSTITIAL_AD_REVENUE_PAID = @"OnInterstitialAdRevenuePaid";
109
112
 
113
+ static NSString *const ON_APPOPEN_LOADED_EVENT = @"OnAppOpenLoadedEvent";
114
+ static NSString *const ON_APPOPEN_LOAD_FAILED_EVENT = @"OnAppOpenLoadFailedEvent";
115
+ static NSString *const ON_APPOPEN_CLICKED_EVENT = @"OnAppOpenClickedEvent";
116
+ static NSString *const ON_APPOPEN_DISPLAYED_EVENT = @"OnAppOpenDisplayedEvent";
117
+ static NSString *const ON_APPOPEN_DISPLAY_FAILED_EVENT = @"OnAppOpenDisplayFailedEvent";
118
+ static NSString *const ON_APPOPEN_HIDDEN_EVENT = @"OnAppOpenHiddenEvent";
119
+ static NSString *const ON_APPOPEN_AD_REVENUE_PAID = @"OnAppOpenAdRevenuePaid";
120
+
110
121
  static NSString *const ON_REWARDED_AD_LOADED_EVENT = @"OnRewardedAdLoadedEvent";
111
122
  static NSString *const ON_REWARDED_AD_LOAD_FAILED_EVENT = @"OnRewardedAdLoadFailedEvent";
112
123
  static NSString *const ON_REWARDED_AD_CLICKED_EVENT = @"OnRewardedAdClickedEvent";
@@ -157,6 +168,7 @@ RCT_EXPORT_MODULE(CloudX)
157
168
  CloudXShared = self;
158
169
 
159
170
  self.interstitials = [NSMutableDictionary dictionaryWithCapacity: 2];
171
+ self.appOpenAds = [NSMutableDictionary dictionaryWithCapacity: 2];
160
172
  self.rewardedAds = [NSMutableDictionary dictionaryWithCapacity: 2];
161
173
 
162
174
  self.adViews = [NSMutableDictionary dictionaryWithCapacity: 2];
@@ -283,6 +295,20 @@ RCT_EXPORT_METHOD(arbiter:(NSDictionary<NSString *, id> *)configuration resolve:
283
295
  }];
284
296
  }
285
297
 
298
+ #pragma mark - Publisher-reported Revenue
299
+
300
+ RCT_EXPORT_METHOD(reportRevenueData:(NSDictionary<NSString *, id> *)data resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
301
+ {
302
+ CLXRevenueData *revenueData = [self revenueDataFromDictionary: data];
303
+ if ( !revenueData )
304
+ {
305
+ resolve(@(NO));
306
+ return;
307
+ }
308
+
309
+ resolve(@([[CloudXCore shared] reportRevenueData: revenueData]));
310
+ }
311
+
286
312
  #pragma mark - Banners
287
313
 
288
314
  RCT_EXPORT_METHOD(createBanner:(NSString *)adUnitIdentifier position:(NSString *)bannerPosition)
@@ -431,7 +457,9 @@ RCT_EXPORT_METHOD(loadInterstitial:(NSString *)adUnitIdentifier)
431
457
  RCT_EXPORT_METHOD(setInterstitialExtraParameters:(NSString *)adUnitIdentifier extraParameters:(NSDictionary<NSString *, id> *)extraParameters)
432
458
  {
433
459
  CLXInterstitial *interstitial = [self retrieveInterstitialForAdUnitIdentifier: adUnitIdentifier];
434
- [self applyExtraParameters: extraParameters toFullscreenAd: interstitial];
460
+ [CloudXExtraParameters applyExtraParameters: extraParameters toFullscreenAd: interstitial logBlock:^(NSString *message) {
461
+ [self log: @"%@", message];
462
+ }];
435
463
  }
436
464
 
437
465
  RCT_EXPORT_METHOD(isInterstitialReady:(NSString *)adUnitIdentifier resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
@@ -471,6 +499,60 @@ RCT_EXPORT_METHOD(destroyInterstitial:(NSString *)adUnitIdentifier)
471
499
  }
472
500
  }
473
501
 
502
+ #pragma mark - App Open
503
+
504
+ RCT_EXPORT_METHOD(loadAppOpen:(NSString *)adUnitIdentifier)
505
+ {
506
+ [self log: @"loadAppOpen called from JS — adUnitId: %@", adUnitIdentifier];
507
+ CLXAppOpen *appOpen = [self retrieveAppOpenForAdUnitIdentifier: adUnitIdentifier];
508
+ [appOpen load];
509
+ }
510
+
511
+ RCT_EXPORT_METHOD(setAppOpenExtraParameters:(NSString *)adUnitIdentifier extraParameters:(NSDictionary<NSString *, id> *)extraParameters)
512
+ {
513
+ CLXAppOpen *appOpen = [self retrieveAppOpenForAdUnitIdentifier: adUnitIdentifier];
514
+ [CloudXExtraParameters applyExtraParameters: extraParameters toFullscreenAd: appOpen logBlock:^(NSString *message) {
515
+ [self log: @"%@", message];
516
+ }];
517
+ }
518
+
519
+ RCT_EXPORT_METHOD(isAppOpenReady:(NSString *)adUnitIdentifier resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
520
+ {
521
+ CLXAppOpen *appOpen = [self retrieveAppOpenForAdUnitIdentifier: adUnitIdentifier];
522
+ resolve(@([appOpen isReady]));
523
+ }
524
+
525
+ RCT_EXPORT_METHOD(showAppOpen:(NSString *)adUnitIdentifier placement:(nullable NSString *)placement customData:(nullable NSString *)customData)
526
+ {
527
+ UIViewController *vc = [self topViewController];
528
+ if ( !vc )
529
+ {
530
+ [self log: @"showAppOpen: no visible view controller — emitting display failure"];
531
+ NSDictionary *body = @{@"adUnitId": adUnitIdentifier ?: @"",
532
+ @"code": @(-1),
533
+ @"message": @"No visible view controller to present app open ad from"};
534
+ [self sendReactNativeEventWithName: ON_APPOPEN_DISPLAY_FAILED_EVENT body: body];
535
+ return;
536
+ }
537
+
538
+ CLXAppOpen *appOpen = [self retrieveAppOpenForAdUnitIdentifier: adUnitIdentifier];
539
+ [appOpen showFromViewController: vc placement: placement customData: customData];
540
+ }
541
+
542
+ RCT_EXPORT_METHOD(destroyAppOpen:(NSString *)adUnitIdentifier)
543
+ {
544
+ [self log: @"Destroying app open ad with ad unit identifier \"%@\"", adUnitIdentifier];
545
+
546
+ CLXAppOpen *appOpen = self.appOpenAds[adUnitIdentifier];
547
+ if ( appOpen )
548
+ {
549
+ appOpen.delegate = nil;
550
+ appOpen.revenueDelegate = nil;
551
+ [appOpen destroy];
552
+ [self.appOpenAds removeObjectForKey: adUnitIdentifier];
553
+ }
554
+ }
555
+
474
556
  #pragma mark - Rewarded
475
557
 
476
558
  RCT_EXPORT_METHOD(loadRewarded:(NSString *)adUnitIdentifier)
@@ -483,7 +565,9 @@ RCT_EXPORT_METHOD(loadRewarded:(NSString *)adUnitIdentifier)
483
565
  RCT_EXPORT_METHOD(setRewardedExtraParameters:(NSString *)adUnitIdentifier extraParameters:(NSDictionary<NSString *, id> *)extraParameters)
484
566
  {
485
567
  CLXRewarded *rewardedAd = [self retrieveRewardedAdForAdUnitIdentifier: adUnitIdentifier];
486
- [self applyExtraParameters: extraParameters toFullscreenAd: rewardedAd];
568
+ [CloudXExtraParameters applyExtraParameters: extraParameters toFullscreenAd: rewardedAd logBlock:^(NSString *message) {
569
+ [self log: @"%@", message];
570
+ }];
487
571
  }
488
572
 
489
573
  RCT_EXPORT_METHOD(isRewardedReady:(NSString *)adUnitIdentifier resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
@@ -548,6 +632,10 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
548
632
  {
549
633
  name = ON_INTERSTITIAL_LOADED_EVENT;
550
634
  }
635
+ else if ( adFormat == CLXAdFormatAppOpen )
636
+ {
637
+ name = ON_APPOPEN_LOADED_EVENT;
638
+ }
551
639
  else if ( adFormat == CLXAdFormatRewarded )
552
640
  {
553
641
  name = ON_REWARDED_AD_LOADED_EVENT;
@@ -575,6 +663,11 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
575
663
  [self sendReactNativeEventWithName: ON_INTERSTITIAL_LOAD_FAILED_EVENT
576
664
  body: [self adLoadFailedInfoForAd: key withError: error]];
577
665
  }
666
+ for ( NSString *key in self.appOpenAds )
667
+ {
668
+ [self sendReactNativeEventWithName: ON_APPOPEN_LOAD_FAILED_EVENT
669
+ body: [self adLoadFailedInfoForAd: key withError: error]];
670
+ }
578
671
  for ( NSString *key in self.rewardedAds )
579
672
  {
580
673
  [self sendReactNativeEventWithName: ON_REWARDED_AD_LOAD_FAILED_EVENT
@@ -593,14 +686,18 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
593
686
  {
594
687
  name = ON_INTERSTITIAL_LOAD_FAILED_EVENT;
595
688
  }
689
+ else if ( self.appOpenAds[adUnitId] )
690
+ {
691
+ name = ON_APPOPEN_LOAD_FAILED_EVENT;
692
+ }
596
693
  else if ( self.rewardedAds[adUnitId] )
597
694
  {
598
695
  name = ON_REWARDED_AD_LOAD_FAILED_EVENT;
599
696
  }
600
697
  else
601
698
  {
602
- [self log: @"didFailToLoadAd — adUnitId '%@' not found in any dictionary (keys: adViews=%@, interstitials=%@, rewardedAds=%@)",
603
- adUnitId, self.adViews.allKeys, self.interstitials.allKeys, self.rewardedAds.allKeys];
699
+ [self log: @"didFailToLoadAd — adUnitId '%@' not found in any dictionary (keys: adViews=%@, interstitials=%@, appOpenAds=%@, rewardedAds=%@)",
700
+ adUnitId, self.adViews.allKeys, self.interstitials.allKeys, self.appOpenAds.allKeys, self.rewardedAds.allKeys];
604
701
  return;
605
702
  }
606
703
 
@@ -625,6 +722,10 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
625
722
  {
626
723
  name = ON_INTERSTITIAL_CLICKED_EVENT;
627
724
  }
725
+ else if ( adFormat == CLXAdFormatAppOpen )
726
+ {
727
+ name = ON_APPOPEN_CLICKED_EVENT;
728
+ }
628
729
  else if ( adFormat == CLXAdFormatRewarded )
629
730
  {
630
731
  name = ON_REWARDED_AD_CLICKED_EVENT;
@@ -643,13 +744,17 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
643
744
  {
644
745
  dispatch_async(dispatch_get_main_queue(), ^{
645
746
  CLXAdFormat adFormat = ad.adFormat;
646
- if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatRewarded ) return;
747
+ if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatAppOpen && adFormat != CLXAdFormatRewarded ) return;
647
748
 
648
749
  NSString *name;
649
750
  if ( adFormat == CLXAdFormatInterstitial )
650
751
  {
651
752
  name = ON_INTERSTITIAL_DISPLAYED_EVENT;
652
753
  }
754
+ else if ( adFormat == CLXAdFormatAppOpen )
755
+ {
756
+ name = ON_APPOPEN_DISPLAYED_EVENT;
757
+ }
653
758
  else
654
759
  {
655
760
  name = ON_REWARDED_AD_DISPLAYED_EVENT;
@@ -663,13 +768,17 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
663
768
  {
664
769
  dispatch_async(dispatch_get_main_queue(), ^{
665
770
  CLXAdFormat adFormat = ad.adFormat;
666
- if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatRewarded ) return;
771
+ if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatAppOpen && adFormat != CLXAdFormatRewarded ) return;
667
772
 
668
773
  NSString *name;
669
774
  if ( adFormat == CLXAdFormatInterstitial )
670
775
  {
671
776
  name = ON_INTERSTITIAL_DISPLAY_FAILED_EVENT;
672
777
  }
778
+ else if ( adFormat == CLXAdFormatAppOpen )
779
+ {
780
+ name = ON_APPOPEN_DISPLAY_FAILED_EVENT;
781
+ }
673
782
  else
674
783
  {
675
784
  name = ON_REWARDED_AD_DISPLAY_FAILED_EVENT;
@@ -683,13 +792,17 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
683
792
  {
684
793
  dispatch_async(dispatch_get_main_queue(), ^{
685
794
  CLXAdFormat adFormat = ad.adFormat;
686
- if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatRewarded ) return;
795
+ if ( adFormat != CLXAdFormatInterstitial && adFormat != CLXAdFormatAppOpen && adFormat != CLXAdFormatRewarded ) return;
687
796
 
688
797
  NSString *name;
689
798
  if ( adFormat == CLXAdFormatInterstitial )
690
799
  {
691
800
  name = ON_INTERSTITIAL_HIDDEN_EVENT;
692
801
  }
802
+ else if ( adFormat == CLXAdFormatAppOpen )
803
+ {
804
+ name = ON_APPOPEN_HIDDEN_EVENT;
805
+ }
693
806
  else
694
807
  {
695
808
  name = ON_REWARDED_AD_HIDDEN_EVENT;
@@ -746,6 +859,10 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
746
859
  {
747
860
  name = ON_INTERSTITIAL_AD_REVENUE_PAID;
748
861
  }
862
+ else if ( adFormat == CLXAdFormatAppOpen )
863
+ {
864
+ name = ON_APPOPEN_AD_REVENUE_PAID;
865
+ }
749
866
  else if ( adFormat == CLXAdFormatRewarded )
750
867
  {
751
868
  name = ON_REWARDED_AD_REVENUE_PAID;
@@ -876,7 +993,9 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
876
993
  CLXBannerAdView *adView = [self retrieveAdViewForAdUnitIdentifier: adUnitIdentifier adFormat: adFormat];
877
994
  if ( adView )
878
995
  {
879
- [self applyExtraParameters: extraParameters toAdView: adView];
996
+ [CloudXExtraParameters applyExtraParameters: extraParameters toAdView: adView logBlock:^(NSString *message) {
997
+ [self log: @"%@", message];
998
+ }];
880
999
  return;
881
1000
  }
882
1001
 
@@ -887,17 +1006,7 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
887
1006
  self.adViewExtraParameters[adUnitIdentifier] = pending;
888
1007
  }
889
1008
 
890
- [extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
891
- if ( !key || key.length == 0 ) return;
892
- if ( !value || [value isKindOfClass: [NSNull class]] )
893
- {
894
- [pending removeObjectForKey: key];
895
- }
896
- else
897
- {
898
- pending[key] = value;
899
- }
900
- }];
1009
+ [CloudXExtraParameters mergeExtraParameters: extraParameters intoPendingDictionary: pending];
901
1010
  }];
902
1011
  }
903
1012
 
@@ -905,49 +1014,8 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
905
1014
  {
906
1015
  NSDictionary<NSString *, id> *pending = [self.adViewExtraParameters[adUnitIdentifier] copy];
907
1016
  if ( pending.count == 0 ) return;
908
- [self applyExtraParameters: pending toAdView: adView];
909
- }
910
-
911
- - (void)applyExtraParameterValue:(id)value forKey:(NSString *)key toTarget:(id)target
912
- {
913
- if ( !target || !key || key.length == 0 ) return;
914
-
915
- SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
916
- if ( ![target respondsToSelector: selector] )
917
- {
918
- selector = NSSelectorFromString(@"setExtraParameterForKey:value:");
919
- }
920
-
921
- if ( ![target respondsToSelector: selector] )
922
- {
923
- [self log: @"Skipping extra parameter \"%@\" because %@ does not respond to setExtraParameter:value: or setExtraParameterForKey:value:", key, NSStringFromClass([target class])];
924
- return;
925
- }
926
-
927
- using SetExtraParameterMethod = void (*)(id, SEL, NSString *, id);
928
- SetExtraParameterMethod method = (SetExtraParameterMethod)[target methodForSelector: selector];
929
- method(target, selector, key, value);
930
-
931
- [self log: @"Applied extra parameter \"%@\" with value \"%@\" to %@", key, value ?: @"(cleared)", NSStringFromClass([target class])];
932
- }
933
-
934
- - (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters toAdView:(CLXBannerAdView *)adView
935
- {
936
- [extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
937
- if ( !key || key.length == 0 ) return;
938
- id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
939
- SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
940
- id target = [adView respondsToSelector: selector] ? adView : adView.ad;
941
- [self applyExtraParameterValue: normalizedValue forKey: key toTarget: target];
942
- }];
943
- }
944
-
945
- - (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters toFullscreenAd:(id<CLXFullscreenAd>)ad
946
- {
947
- [extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
948
- if ( !key || key.length == 0 ) return;
949
- id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
950
- [self applyExtraParameterValue: normalizedValue forKey: key toTarget: ad];
1017
+ [CloudXExtraParameters applyExtraParameters: pending toAdView: adView logBlock:^(NSString *message) {
1018
+ [self log: @"%@", message];
951
1019
  }];
952
1020
  }
953
1021
 
@@ -1152,6 +1220,21 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1152
1220
  return result;
1153
1221
  }
1154
1222
 
1223
+ - (CLXAppOpen *)retrieveAppOpenForAdUnitIdentifier:(NSString *)adUnitIdentifier
1224
+ {
1225
+ CLXAppOpen *result = self.appOpenAds[adUnitIdentifier];
1226
+ if ( !result )
1227
+ {
1228
+ result = [[CloudXCore shared] createAppOpenWithAdUnitId: adUnitIdentifier];
1229
+ result.delegate = self;
1230
+ result.revenueDelegate = self;
1231
+
1232
+ self.appOpenAds[adUnitIdentifier] = result;
1233
+ }
1234
+
1235
+ return result;
1236
+ }
1237
+
1155
1238
  - (CLXRewarded *)retrieveRewardedAdForAdUnitIdentifier:(NSString *)adUnitIdentifier
1156
1239
  {
1157
1240
  CLXRewarded *result = self.rewardedAds[adUnitIdentifier];
@@ -1501,6 +1584,107 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1501
1584
  return vc;
1502
1585
  }
1503
1586
 
1587
+ - (nullable CLXRevenueData *)revenueDataFromDictionary:(NSDictionary<NSString *, id> *)dictionary
1588
+ {
1589
+ if ( ![dictionary isKindOfClass: [NSDictionary class]] )
1590
+ {
1591
+ [self log: @"reportRevenueData: ignoring data with missing or invalid required fields"];
1592
+ return nil;
1593
+ }
1594
+
1595
+ NSString *platform = [self stringValueFromDictionary: dictionary key: @"platform"];
1596
+ NSNumber *revenueNumber = [self revenueNumberValueFromDictionary: dictionary key: @"revenue"];
1597
+ NSString *adFormat = [self stringValueFromDictionary: dictionary key: @"adFormat"];
1598
+ CLXRevenuePlatform revenuePlatform = [self revenuePlatformFromString: platform];
1599
+ if ( !revenuePlatform || !revenueNumber || [self isBlankString: adFormat] )
1600
+ {
1601
+ [self log: @"reportRevenueData: ignoring data with missing or invalid required fields"];
1602
+ return nil;
1603
+ }
1604
+
1605
+ double revenue = revenueNumber.doubleValue;
1606
+ if ( !isfinite(revenue) )
1607
+ {
1608
+ [self log: @"reportRevenueData: ignoring data with non-finite revenue=%@", revenueNumber];
1609
+ return nil;
1610
+ }
1611
+
1612
+ return [CLXRevenueData revenueDataWithPlatform: revenuePlatform
1613
+ revenue: revenue
1614
+ adFormat: adFormat
1615
+ builderBlock:^(CLXRevenueDataBuilder *builder) {
1616
+ builder.currencyCode = [self nonBlankStringValueFromDictionary: dictionary key: @"currencyCode"];
1617
+ builder.precision = [self revenuePrecisionFromString: [self stringValueFromDictionary: dictionary key: @"precision"]];
1618
+ builder.networkName = [self nonBlankStringValueFromDictionary: dictionary key: @"networkName"];
1619
+ builder.adUnitId = [self nonBlankStringValueFromDictionary: dictionary key: @"adUnitId"];
1620
+ builder.thirdPartyAdPlacementId = [self nonBlankStringValueFromDictionary: dictionary key: @"thirdPartyAdPlacementId"];
1621
+ builder.creativeId = [self nonBlankStringValueFromDictionary: dictionary key: @"creativeId"];
1622
+ builder.networkPlacement = [self nonBlankStringValueFromDictionary: dictionary key: @"networkPlacement"];
1623
+ builder.countryCode = [self nonBlankStringValueFromDictionary: dictionary key: @"countryCode"];
1624
+ builder.userSegment = [self nonBlankStringValueFromDictionary: dictionary key: @"userSegment"];
1625
+ }];
1626
+ }
1627
+
1628
+ - (nullable CLXRevenuePlatform)revenuePlatformFromString:(nullable NSString *)platform
1629
+ {
1630
+ if ( !platform )
1631
+ {
1632
+ return nil;
1633
+ }
1634
+
1635
+ NSString *trimmedPlatform = [platform stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
1636
+ if ( trimmedPlatform.length == 0 )
1637
+ {
1638
+ return nil;
1639
+ }
1640
+
1641
+ if ( [trimmedPlatform caseInsensitiveCompare: CLXRevenuePlatformAdMob] == NSOrderedSame )
1642
+ {
1643
+ return CLXRevenuePlatformAdMob;
1644
+ }
1645
+
1646
+ if ( [trimmedPlatform caseInsensitiveCompare: CLXRevenuePlatformInMobi] == NSOrderedSame )
1647
+ {
1648
+ return CLXRevenuePlatformInMobi;
1649
+ }
1650
+
1651
+ return CLXRevenuePlatformCustom(trimmedPlatform);
1652
+ }
1653
+
1654
+ - (nullable NSString *)nonBlankStringValueFromDictionary:(NSDictionary<NSString *, id> *)dictionary key:(NSString *)key
1655
+ {
1656
+ NSString *value = [self stringValueFromDictionary: dictionary key: key];
1657
+ return [self isBlankString: value] ? nil : value;
1658
+ }
1659
+
1660
+ - (nullable NSNumber *)revenueNumberValueFromDictionary:(NSDictionary<NSString *, id> *)dictionary key:(NSString *)key
1661
+ {
1662
+ id value = dictionary[key];
1663
+ if ( ![value isKindOfClass: [NSNumber class]] ) return nil;
1664
+ if ( CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID() ) return nil;
1665
+ return value;
1666
+ }
1667
+
1668
+ - (BOOL)isBlankString:(nullable NSString *)value
1669
+ {
1670
+ if ( ![value isKindOfClass: [NSString class]] ) return YES;
1671
+ return [value stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0;
1672
+ }
1673
+
1674
+ - (nullable CLXRevenuePrecision *)revenuePrecisionFromString:(nullable NSString *)value
1675
+ {
1676
+ if ( !value ) return nil;
1677
+
1678
+ NSString *lower = [value lowercaseString];
1679
+ if ( [lower isEqualToString: @"exact"] ) return CLXRevenuePrecision.exact;
1680
+ if ( [lower isEqualToString: @"estimated"] ) return CLXRevenuePrecision.estimated;
1681
+ if ( [lower isEqualToString: @"publisher_defined"] ) return CLXRevenuePrecision.publisherDefined;
1682
+ if ( [lower isEqualToString: @"undefined"] ) return CLXRevenuePrecision.undefined;
1683
+
1684
+ [self log: @"reportRevenueData: ignoring unknown precision=%@", value];
1685
+ return nil;
1686
+ }
1687
+
1504
1688
  - (CLXLogLevel)logLevelFromString:(NSString *)level
1505
1689
  {
1506
1690
  NSString *lower = [level lowercaseString];
@@ -1735,6 +1919,11 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1735
1919
  *result = CLXAdFormatInterstitial;
1736
1920
  return YES;
1737
1921
  }
1922
+ if ( [upper isEqualToString: @"APP_OPEN"] )
1923
+ {
1924
+ *result = CLXAdFormatAppOpen;
1925
+ return YES;
1926
+ }
1738
1927
  if ( [upper isEqualToString: @"REWARDED"] )
1739
1928
  {
1740
1929
  *result = CLXAdFormatRewarded;
@@ -1755,6 +1944,7 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1755
1944
  case CLXAdFormatBanner: return @"BANNER";
1756
1945
  case CLXAdFormatMREC: return @"MREC";
1757
1946
  case CLXAdFormatInterstitial: return @"INTERSTITIAL";
1947
+ case CLXAdFormatAppOpen: return @"APP_OPEN";
1758
1948
  case CLXAdFormatRewarded: return @"REWARDED";
1759
1949
  default: return @"";
1760
1950
  }
@@ -1791,6 +1981,14 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1791
1981
  ON_INTERSTITIAL_HIDDEN_EVENT,
1792
1982
  ON_INTERSTITIAL_AD_REVENUE_PAID,
1793
1983
 
1984
+ ON_APPOPEN_LOADED_EVENT,
1985
+ ON_APPOPEN_LOAD_FAILED_EVENT,
1986
+ ON_APPOPEN_CLICKED_EVENT,
1987
+ ON_APPOPEN_DISPLAYED_EVENT,
1988
+ ON_APPOPEN_DISPLAY_FAILED_EVENT,
1989
+ ON_APPOPEN_HIDDEN_EVENT,
1990
+ ON_APPOPEN_AD_REVENUE_PAID,
1991
+
1794
1992
  ON_REWARDED_AD_LOADED_EVENT,
1795
1993
  ON_REWARDED_AD_LOAD_FAILED_EVENT,
1796
1994
  ON_REWARDED_AD_CLICKED_EVENT,
@@ -1825,6 +2023,14 @@ RCT_EXPORT_METHOD(destroyRewarded:(NSString *)adUnitIdentifier)
1825
2023
  @"ON_INTERSTITIAL_HIDDEN_EVENT": ON_INTERSTITIAL_HIDDEN_EVENT,
1826
2024
  @"ON_INTERSTITIAL_AD_REVENUE_PAID": ON_INTERSTITIAL_AD_REVENUE_PAID,
1827
2025
 
2026
+ @"ON_APPOPEN_LOADED_EVENT": ON_APPOPEN_LOADED_EVENT,
2027
+ @"ON_APPOPEN_LOAD_FAILED_EVENT": ON_APPOPEN_LOAD_FAILED_EVENT,
2028
+ @"ON_APPOPEN_CLICKED_EVENT": ON_APPOPEN_CLICKED_EVENT,
2029
+ @"ON_APPOPEN_DISPLAYED_EVENT": ON_APPOPEN_DISPLAYED_EVENT,
2030
+ @"ON_APPOPEN_DISPLAY_FAILED_EVENT": ON_APPOPEN_DISPLAY_FAILED_EVENT,
2031
+ @"ON_APPOPEN_HIDDEN_EVENT": ON_APPOPEN_HIDDEN_EVENT,
2032
+ @"ON_APPOPEN_AD_REVENUE_PAID": ON_APPOPEN_AD_REVENUE_PAID,
2033
+
1828
2034
  @"ON_REWARDED_AD_LOADED_EVENT": ON_REWARDED_AD_LOADED_EVENT,
1829
2035
  @"ON_REWARDED_AD_LOAD_FAILED_EVENT": ON_REWARDED_AD_LOAD_FAILED_EVENT,
1830
2036
  @"ON_REWARDED_AD_CLICKED_EVENT": ON_REWARDED_AD_CLICKED_EVENT,
@@ -0,0 +1,33 @@
1
+ //
2
+ // CloudXAdView.h
3
+ // cloudx-react-native
4
+ //
5
+ // In-tree banner/MREC view component. Unlike the imperative overlay banner in
6
+ // CloudX.mm (attached above the whole RN view tree), this hosts a
7
+ // CLXBannerAdView as an ordinary RN view so app overlays layer above it.
8
+ //
9
+
10
+ #import <React/RCTUIManager.h>
11
+ #import <CloudXCore/CloudXCore.h>
12
+
13
+ #ifdef RCT_NEW_ARCH_ENABLED
14
+ #import <React/RCTViewComponentView.h>
15
+ @interface CloudXAdView : RCTViewComponentView <CLXBannerDelegate, CLXAdRevenueDelegate>
16
+ #else
17
+ @interface CloudXAdView : UIView <CLXBannerDelegate, CLXAdRevenueDelegate>
18
+ #endif
19
+
20
+ NS_ASSUME_NONNULL_BEGIN
21
+
22
+ // Nil by default on the Old Architecture (only set when the publisher passes
23
+ // the corresponding callback); delegate call sites guard with `if (self.onX)`.
24
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadedEvent;
25
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadFailedEvent;
26
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClickedEvent;
27
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdRevenuePaidEvent;
28
+
29
+ - (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters;
30
+
31
+ @end
32
+
33
+ NS_ASSUME_NONNULL_END