cloudx-react-native 3.11.0 → 3.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +9 -0
  3. package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +76 -0
  4. package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +110 -0
  5. package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdHolder.kt +184 -0
  6. package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdView.kt +209 -70
  7. package/android/src/main/java/com/cloudxreactnative/CloudXNativeAdViewManagerImpl.kt +6 -0
  8. package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +9 -0
  9. package/android/src/newarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +2 -0
  10. package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +14 -0
  11. package/android/src/oldarch/com/cloudxreactnative/CloudXNativeAdViewManager.kt +3 -0
  12. package/android/src/test/java/com/cloudxreactnative/CloudXNativeAdPreloadTest.kt +351 -0
  13. package/android/src/test/java/com/cloudxreactnative/FakeReadable.kt +2 -2
  14. package/ios/CloudX.h +12 -0
  15. package/ios/CloudX.mm +94 -1
  16. package/ios/CloudXNativeAdHolder.h +66 -0
  17. package/ios/CloudXNativeAdHolder.mm +247 -0
  18. package/ios/CloudXNativeAdView.h +9 -0
  19. package/ios/CloudXNativeAdView.mm +308 -64
  20. package/ios/CloudXNativeAdViewManager.mm +7 -0
  21. package/lib/commonjs/CloudXNativeAd.js +178 -0
  22. package/lib/commonjs/CloudXNativeAd.js.map +1 -0
  23. package/lib/commonjs/CloudXNativeAdView.js +58 -11
  24. package/lib/commonjs/CloudXNativeAdView.js.map +1 -1
  25. package/lib/commonjs/hooks.js +203 -0
  26. package/lib/commonjs/hooks.js.map +1 -1
  27. package/lib/commonjs/index.js +13 -0
  28. package/lib/commonjs/index.js.map +1 -1
  29. package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js +2 -0
  30. package/lib/commonjs/specs/CloudXNativeAdViewNativeComponent.js.map +1 -1
  31. package/lib/commonjs/specs/NativeCloudX.js.map +1 -1
  32. package/lib/commonjs/types/NativeAd.js +21 -1
  33. package/lib/commonjs/types/NativeAd.js.map +1 -1
  34. package/lib/commonjs/types/index.js.map +1 -1
  35. package/lib/commonjs/version.js +1 -1
  36. package/lib/module/CloudXNativeAd.js +170 -0
  37. package/lib/module/CloudXNativeAd.js.map +1 -0
  38. package/lib/module/CloudXNativeAdView.js +58 -11
  39. package/lib/module/CloudXNativeAdView.js.map +1 -1
  40. package/lib/module/hooks.js +202 -0
  41. package/lib/module/hooks.js.map +1 -1
  42. package/lib/module/index.js +2 -1
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/specs/CloudXNativeAdViewNativeComponent.js +2 -0
  45. package/lib/module/specs/CloudXNativeAdViewNativeComponent.js.map +1 -1
  46. package/lib/module/specs/NativeCloudX.js.map +1 -1
  47. package/lib/module/types/NativeAd.js +26 -1
  48. package/lib/module/types/NativeAd.js.map +1 -1
  49. package/lib/module/types/index.js.map +1 -1
  50. package/lib/module/version.js +1 -1
  51. package/lib/typescript/src/CloudXNativeAd.d.ts +58 -0
  52. package/lib/typescript/src/CloudXNativeAd.d.ts.map +1 -0
  53. package/lib/typescript/src/CloudXNativeAdView.d.ts +6 -13
  54. package/lib/typescript/src/CloudXNativeAdView.d.ts.map +1 -1
  55. package/lib/typescript/src/hooks.d.ts +30 -0
  56. package/lib/typescript/src/hooks.d.ts.map +1 -1
  57. package/lib/typescript/src/index.d.ts +4 -3
  58. package/lib/typescript/src/index.d.ts.map +1 -1
  59. package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts +23 -2
  60. package/lib/typescript/src/specs/CloudXNativeAdViewNativeComponent.d.ts.map +1 -1
  61. package/lib/typescript/src/specs/NativeCloudX.d.ts +13 -0
  62. package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -1
  63. package/lib/typescript/src/types/NativeAd.d.ts +76 -13
  64. package/lib/typescript/src/types/NativeAd.d.ts.map +1 -1
  65. package/lib/typescript/src/types/index.d.ts +1 -1
  66. package/lib/typescript/src/types/index.d.ts.map +1 -1
  67. package/lib/typescript/src/version.d.ts +1 -1
  68. package/package.json +1 -1
  69. package/src/CloudXNativeAd.ts +177 -0
  70. package/src/CloudXNativeAdView.tsx +82 -15
  71. package/src/hooks.ts +236 -0
  72. package/src/index.ts +14 -1
  73. package/src/specs/CloudXNativeAdViewNativeComponent.ts +27 -2
  74. package/src/specs/NativeCloudX.ts +20 -0
  75. package/src/types/NativeAd.ts +85 -18
  76. package/src/types/index.ts +4 -0
  77. package/src/version.ts +1 -1
@@ -0,0 +1,247 @@
1
+ //
2
+ // CloudXNativeAdHolder.mm
3
+ // cloudx-react-native
4
+ //
5
+
6
+ #import "CloudXNativeAdHolder.h"
7
+ #import "CloudX.h"
8
+ #import "CloudXNativeAdView.h"
9
+
10
+ @interface CloudXNativeAdHolder ()
11
+ @property (nonatomic, assign, readwrite, getter=isImpressed) BOOL impressed;
12
+ @end
13
+
14
+ @implementation CloudXNativeAdHolder
15
+
16
+ // The registry lives on the CloudX module instance, not in a static: after a
17
+ // JS reload the old module's teardown must only release the old context's
18
+ // ads, never ones the new context has already preloaded.
19
+ + (nullable NSMutableDictionary<NSString *, CloudXNativeAdHolder *> *)registry
20
+ {
21
+ NSAssert([NSThread isMainThread], @"CloudXNativeAdHolder registry must be accessed on the main thread");
22
+ return [CloudX shared].nativeAdHolders;
23
+ }
24
+
25
+ + (void)registerHolder:(CloudXNativeAdHolder *)holder
26
+ {
27
+ if ( holder.nativeAdId.length == 0 ) return;
28
+ [self registry][holder.nativeAdId] = holder;
29
+ }
30
+
31
+ + (nullable CloudXNativeAdHolder *)holderForId:(NSString *)nativeAdId
32
+ {
33
+ if ( nativeAdId.length == 0 ) return nil;
34
+ return [self registry][nativeAdId];
35
+ }
36
+
37
+ + (void)removeHolderForId:(NSString *)nativeAdId
38
+ {
39
+ if ( nativeAdId.length == 0 ) return;
40
+ [[self registry] removeObjectForKey: nativeAdId];
41
+ }
42
+
43
+ + (void)destroyAllHoldersInRegistry:(NSMutableDictionary<NSString *, CloudXNativeAdHolder *> *)registry
44
+ {
45
+ NSAssert([NSThread isMainThread], @"CloudXNativeAdHolder registry must be accessed on the main thread");
46
+ NSArray<CloudXNativeAdHolder *> *holders = [registry.allValues copy];
47
+ [registry removeAllObjects];
48
+ for ( CloudXNativeAdHolder *holder in holders )
49
+ {
50
+ [holder destroy];
51
+ }
52
+ }
53
+
54
+ + (void)configureLoader:(CLXNativeAdLoader *)loader
55
+ placement:(nullable NSString *)placement
56
+ customData:(nullable NSString *)customData
57
+ disableVideoFullScreen:(BOOL)disableVideoFullScreen
58
+ startVideoUnmuted:(BOOL)startVideoUnmuted
59
+ hideVideoMediaControls:(BOOL)hideVideoMediaControls
60
+ extraParameterEntries:(nullable NSArray<NSDictionary *> *)extraParameterEntries
61
+ localExtraParameterEntries:(nullable NSArray<NSDictionary *> *)localExtraParameterEntries
62
+ {
63
+ loader.placement = placement;
64
+ loader.customData = customData;
65
+ loader.disableVideoFullScreen = disableVideoFullScreen;
66
+ loader.startVideoUnmuted = startVideoUnmuted;
67
+ loader.hideVideoMediaControls = hideVideoMediaControls;
68
+
69
+ // JS null crosses the bridge as NSNull; normalize to nil so the loader
70
+ // never receives NSNull.
71
+ //
72
+ // extraParameters are bid-level auction signals (setExtraParameter:value:);
73
+ // localExtraParameters are adapter-only and never sent in the bid request
74
+ // (setLocalExtraParameterForKey:value:) — see CLXNativeAdLoader.h.
75
+ for ( NSDictionary *entry in extraParameterEntries )
76
+ {
77
+ if ( ![entry isKindOfClass: [NSDictionary class]] ) continue;
78
+ NSString *key = [entry[@"key"] isKindOfClass: [NSString class]] ? entry[@"key"] : nil;
79
+ if ( key.length == 0 ) continue;
80
+ id value = entry[@"value"];
81
+ if ( value == [NSNull null] ) value = nil;
82
+ [loader setExtraParameter: key value: value];
83
+ }
84
+
85
+ for ( NSDictionary *entry in localExtraParameterEntries )
86
+ {
87
+ if ( ![entry isKindOfClass: [NSDictionary class]] ) continue;
88
+ NSString *key = [entry[@"key"] isKindOfClass: [NSString class]] ? entry[@"key"] : nil;
89
+ if ( key.length == 0 ) continue;
90
+ id value = entry[@"value"];
91
+ if ( value == [NSNull null] ) value = nil;
92
+ [loader setLocalExtraParameterForKey: key value: value];
93
+ }
94
+ }
95
+
96
+ - (instancetype)initWithNativeAdId:(NSString *)nativeAdId
97
+ adUnitId:(NSString *)adUnitId
98
+ loader:(CLXNativeAdLoader *)loader
99
+ {
100
+ self = [super init];
101
+ if ( self )
102
+ {
103
+ _nativeAdId = [nativeAdId copy];
104
+ _adUnitId = [adUnitId copy];
105
+ _loader = loader;
106
+ }
107
+ return self;
108
+ }
109
+
110
+ - (void)destroy
111
+ {
112
+ NSAssert([NSThread isMainThread], @"CloudXNativeAdHolder destroy must be called on the main thread");
113
+
114
+ self.loader.nativeAdDelegate = nil;
115
+ self.loader.revenueDelegate = nil;
116
+
117
+ CloudXNativeAdView *bound = self.boundView;
118
+ if ( bound )
119
+ {
120
+ self.boundView = nil;
121
+ [bound handleBoundAdDestroyed];
122
+ }
123
+
124
+ if ( self.ad )
125
+ {
126
+ [self.loader destroyAd: self.ad];
127
+ self.ad = nil;
128
+ }
129
+ [self.loader destroy];
130
+
131
+ if ( self.rejectBlock )
132
+ {
133
+ self.rejectBlock(@"400", @"native ad destroyed", nil);
134
+ self.resolveBlock = nil;
135
+ self.rejectBlock = nil;
136
+ }
137
+ }
138
+
139
+ - (void)dealloc
140
+ {
141
+ CLXNativeAdLoader *loader = _loader;
142
+ CLXAd *ad = _ad;
143
+ if ( !loader ) return;
144
+
145
+ loader.nativeAdDelegate = nil;
146
+ loader.revenueDelegate = nil;
147
+
148
+ dispatch_async(dispatch_get_main_queue(), ^{
149
+ if ( ad ) [loader destroyAd: ad];
150
+ [loader destroy];
151
+ });
152
+ }
153
+
154
+ #pragma mark - CLXNativeAdDelegate
155
+
156
+ - (void)didLoadNativeAd:(nullable CLXNativeAdView *)nativeAdView forAd:(CLXAd *)ad
157
+ {
158
+ NSAssert([NSThread isMainThread], @"didLoadNativeAd must be called on the main thread");
159
+ self.ad = ad;
160
+
161
+ if ( self.resolveBlock )
162
+ {
163
+ NSDictionary *adInfo = [[CloudX shared] adInfoForAd: ad];
164
+ self.resolveBlock(@{@"nativeAdId": self.nativeAdId, @"adInfo": adInfo});
165
+ self.resolveBlock = nil;
166
+ self.rejectBlock = nil;
167
+ }
168
+ }
169
+
170
+ - (void)didFailToLoadNativeAdForAdUnitIdentifier:(NSString *)adUnitId error:(CLXError *)error
171
+ {
172
+ NSAssert([NSThread isMainThread], @"didFailToLoadNativeAd must be called on the main thread");
173
+ [[CloudX shared] log: @"Preloaded native ad load failed. nativeAdId=%@ adUnitId=%@ code=%ld message=%@",
174
+ self.nativeAdId, adUnitId ?: @"", (long)(error ? error.code : CLXErrorCodeInternalError),
175
+ error.localizedDescription ?: @""];
176
+
177
+ if ( self.rejectBlock )
178
+ {
179
+ NSString *codeStr = [NSString stringWithFormat: @"%ld", (long)(error ? error.code : CLXErrorCodeInternalError)];
180
+ NSString *message = error.localizedDescription ?: @"Ad failed to load";
181
+ self.rejectBlock(codeStr, message, nil);
182
+ self.resolveBlock = nil;
183
+ self.rejectBlock = nil;
184
+ }
185
+
186
+ [self.loader destroy];
187
+ [CloudXNativeAdHolder removeHolderForId: self.nativeAdId];
188
+ }
189
+
190
+ - (void)didClickNativeAd:(CLXAd *)ad
191
+ {
192
+ NSAssert([NSThread isMainThread], @"didClickNativeAd must be called on the main thread");
193
+ NSMutableDictionary *payload = [[[CloudX shared] adInfoForAd: ad] mutableCopy];
194
+ payload[@"nativeAdId"] = self.nativeAdId;
195
+ [[CloudX shared] sendReactNativeEventWithName: ON_NATIVE_AD_CLICKED_EVENT body: payload];
196
+ }
197
+
198
+ - (void)didExpireNativeAd:(CLXAd *)ad
199
+ {
200
+ NSAssert([NSThread isMainThread], @"didExpireNativeAd must be called on the main thread");
201
+ self.expired = YES;
202
+
203
+ if ( self.isImpressed )
204
+ {
205
+ [[CloudX shared] log: @"Preloaded native ad expired after its impression; ignoring. nativeAdId=%@", self.nativeAdId];
206
+ return;
207
+ }
208
+
209
+ NSMutableDictionary *payload = [[[CloudX shared] adInfoForAd: ad] mutableCopy];
210
+ payload[@"nativeAdId"] = self.nativeAdId;
211
+ [[CloudX shared] sendReactNativeEventWithName: ON_NATIVE_AD_EXPIRED_EVENT body: payload];
212
+
213
+ CloudXNativeAdView *bound = self.boundView;
214
+ if ( bound )
215
+ {
216
+ self.boundView = nil;
217
+ [bound handleBoundAdExpired];
218
+ }
219
+
220
+ if ( self.ad )
221
+ {
222
+ [self.loader destroyAd: self.ad];
223
+ self.ad = nil;
224
+ }
225
+ [self.loader destroy];
226
+ }
227
+
228
+ - (void)didCloseNativeAd:(CLXAd *)ad
229
+ {
230
+ NSAssert([NSThread isMainThread], @"didCloseNativeAd must be called on the main thread");
231
+ NSMutableDictionary *payload = [[[CloudX shared] adInfoForAd: ad] mutableCopy];
232
+ payload[@"nativeAdId"] = self.nativeAdId;
233
+ [[CloudX shared] sendReactNativeEventWithName: ON_NATIVE_AD_CLOSED_EVENT body: payload];
234
+ }
235
+
236
+ #pragma mark - CLXAdRevenueDelegate
237
+
238
+ - (void)didPayRevenueForAd:(CLXAd *)ad
239
+ {
240
+ NSAssert([NSThread isMainThread], @"didPayRevenueForAd must be called on the main thread");
241
+ self.impressed = YES;
242
+ NSMutableDictionary *payload = [[[CloudX shared] adInfoForAd: ad] mutableCopy];
243
+ payload[@"nativeAdId"] = self.nativeAdId;
244
+ [[CloudX shared] sendReactNativeEventWithName: ON_NATIVE_AD_REVENUE_PAID body: payload];
245
+ }
246
+
247
+ @end
@@ -22,6 +22,7 @@
22
22
  NS_ASSUME_NONNULL_BEGIN
23
23
 
24
24
  @property (nonatomic, copy, nullable) NSString *adUnitId;
25
+ @property (nonatomic, copy, nullable) NSString *nativeAdId;
25
26
  @property (nonatomic, copy, nullable) NSString *templateName;
26
27
  @property (nonatomic, copy, nullable) NSString *placement;
27
28
  @property (nonatomic, copy, nullable) NSString *customData;
@@ -38,13 +39,21 @@ NS_ASSUME_NONNULL_BEGIN
38
39
  // Nil by default on the Old Architecture (only set when the publisher passes
39
40
  // the corresponding callback); delegate call sites guard with `if (self.onX)`.
40
41
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadedEvent;
42
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdDisplayedEvent;
41
43
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdLoadFailedEvent;
42
44
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdDisplayFailedEvent;
45
+ // Internal: the preloaded ad left this view (destroy, expiry, or a newer view
46
+ // took it), so the JS view clears its asset components. Not a publisher callback.
47
+ @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdBindingClearedEvent;
43
48
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClickedEvent;
44
49
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdExpiredEvent;
45
50
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdClosedEvent;
46
51
  @property (nonatomic, copy, nullable) RCTDirectEventBlock onAdRevenuePaidEvent;
47
52
 
53
+ - (void)handleBoundAdDestroyed;
54
+ - (void)handleBoundAdExpired;
55
+ - (void)clearRenderedAdSilently;
56
+
48
57
  - (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters;
49
58
  - (void)setLocalExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)localExtraParameters;
50
59