cloudx-react-native 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/LICENSE +57 -0
  2. package/README.md +1258 -0
  3. package/android/build.gradle +78 -0
  4. package/android/gradle.properties +7 -0
  5. package/android/src/main/AndroidManifest.xml +7 -0
  6. package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +15 -0
  7. package/android/src/main/java/com/cloudxreactnative/CloudXBannerViewManagerImpl.kt +472 -0
  8. package/android/src/main/java/com/cloudxreactnative/CloudXReactNativeModuleImpl.kt +861 -0
  9. package/android/src/newarch/com/cloudxreactnative/CloudXBannerViewManager.kt +90 -0
  10. package/android/src/newarch/com/cloudxreactnative/CloudXReactNativeModule.kt +73 -0
  11. package/android/src/newarch/com/cloudxreactnative/CloudXReactNativePackage.kt +37 -0
  12. package/android/src/oldarch/com/cloudxreactnative/CloudXBannerViewManager.kt +76 -0
  13. package/android/src/oldarch/com/cloudxreactnative/CloudXReactNativeModule.kt +73 -0
  14. package/android/src/oldarch/com/cloudxreactnative/CloudXReactNativePackage.kt +16 -0
  15. package/cloudx-react-native.podspec +46 -0
  16. package/ios/AppTrackingTransparency.h +13 -0
  17. package/ios/AppTrackingTransparency.mm +59 -0
  18. package/ios/RNCloudXBannerView.h +51 -0
  19. package/ios/RNCloudXBannerView.mm +633 -0
  20. package/ios/RNCloudXBannerViewManager.h +11 -0
  21. package/ios/RNCloudXBannerViewManager.mm +60 -0
  22. package/ios/RNCloudXModule.h +30 -0
  23. package/ios/RNCloudXModule.mm +1088 -0
  24. package/lib/commonjs/AdView.js +151 -0
  25. package/lib/commonjs/AdView.js.map +1 -0
  26. package/lib/commonjs/AppTrackingTransparency.js +62 -0
  27. package/lib/commonjs/AppTrackingTransparency.js.map +1 -0
  28. package/lib/commonjs/BannerAd.js +117 -0
  29. package/lib/commonjs/BannerAd.js.map +1 -0
  30. package/lib/commonjs/CloudX.js +49 -0
  31. package/lib/commonjs/CloudX.js.map +1 -0
  32. package/lib/commonjs/ErrorCode.js +116 -0
  33. package/lib/commonjs/ErrorCode.js.map +1 -0
  34. package/lib/commonjs/EventEmitter.js +44 -0
  35. package/lib/commonjs/EventEmitter.js.map +1 -0
  36. package/lib/commonjs/InterstitialAd.js +94 -0
  37. package/lib/commonjs/InterstitialAd.js.map +1 -0
  38. package/lib/commonjs/MRecAd.js +117 -0
  39. package/lib/commonjs/MRecAd.js.map +1 -0
  40. package/lib/commonjs/RewardedAd.js +103 -0
  41. package/lib/commonjs/RewardedAd.js.map +1 -0
  42. package/lib/commonjs/hooks.js +239 -0
  43. package/lib/commonjs/hooks.js.map +1 -0
  44. package/lib/commonjs/index.js +144 -0
  45. package/lib/commonjs/index.js.map +1 -0
  46. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +26 -0
  47. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -0
  48. package/lib/commonjs/specs/NativeCloudXModule.js +18 -0
  49. package/lib/commonjs/specs/NativeCloudXModule.js.map +1 -0
  50. package/lib/commonjs/types/AdEvent.js +6 -0
  51. package/lib/commonjs/types/AdEvent.js.map +1 -0
  52. package/lib/commonjs/types/AdInfo.js +6 -0
  53. package/lib/commonjs/types/AdInfo.js.map +1 -0
  54. package/lib/commonjs/types/BannerAd.js +6 -0
  55. package/lib/commonjs/types/BannerAd.js.map +1 -0
  56. package/lib/commonjs/types/CloudX.js +6 -0
  57. package/lib/commonjs/types/CloudX.js.map +1 -0
  58. package/lib/commonjs/types/Configuration.js +2 -0
  59. package/lib/commonjs/types/Configuration.js.map +1 -0
  60. package/lib/commonjs/types/FullscreenAd.js +6 -0
  61. package/lib/commonjs/types/FullscreenAd.js.map +1 -0
  62. package/lib/commonjs/types/RewardedAd.js +6 -0
  63. package/lib/commonjs/types/RewardedAd.js.map +1 -0
  64. package/lib/commonjs/types/index.js +2 -0
  65. package/lib/commonjs/types/index.js.map +1 -0
  66. package/lib/module/AdView.js +144 -0
  67. package/lib/module/AdView.js.map +1 -0
  68. package/lib/module/AppTrackingTransparency.js +55 -0
  69. package/lib/module/AppTrackingTransparency.js.map +1 -0
  70. package/lib/module/BannerAd.js +110 -0
  71. package/lib/module/BannerAd.js.map +1 -0
  72. package/lib/module/CloudX.js +42 -0
  73. package/lib/module/CloudX.js.map +1 -0
  74. package/lib/module/ErrorCode.js +110 -0
  75. package/lib/module/ErrorCode.js.map +1 -0
  76. package/lib/module/EventEmitter.js +35 -0
  77. package/lib/module/EventEmitter.js.map +1 -0
  78. package/lib/module/InterstitialAd.js +87 -0
  79. package/lib/module/InterstitialAd.js.map +1 -0
  80. package/lib/module/MRecAd.js +110 -0
  81. package/lib/module/MRecAd.js.map +1 -0
  82. package/lib/module/RewardedAd.js +96 -0
  83. package/lib/module/RewardedAd.js.map +1 -0
  84. package/lib/module/hooks.js +230 -0
  85. package/lib/module/hooks.js.map +1 -0
  86. package/lib/module/index.js +33 -0
  87. package/lib/module/index.js.map +1 -0
  88. package/lib/module/specs/CloudXAdViewNativeComponent.js +20 -0
  89. package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -0
  90. package/lib/module/specs/NativeCloudXModule.js +14 -0
  91. package/lib/module/specs/NativeCloudXModule.js.map +1 -0
  92. package/lib/module/types/AdEvent.js +2 -0
  93. package/lib/module/types/AdEvent.js.map +1 -0
  94. package/lib/module/types/AdInfo.js +2 -0
  95. package/lib/module/types/AdInfo.js.map +1 -0
  96. package/lib/module/types/BannerAd.js +2 -0
  97. package/lib/module/types/BannerAd.js.map +1 -0
  98. package/lib/module/types/CloudX.js +2 -0
  99. package/lib/module/types/CloudX.js.map +1 -0
  100. package/lib/module/types/Configuration.js +2 -0
  101. package/lib/module/types/Configuration.js.map +1 -0
  102. package/lib/module/types/FullscreenAd.js +2 -0
  103. package/lib/module/types/FullscreenAd.js.map +1 -0
  104. package/lib/module/types/RewardedAd.js +2 -0
  105. package/lib/module/types/RewardedAd.js.map +1 -0
  106. package/lib/module/types/index.js +2 -0
  107. package/lib/module/types/index.js.map +1 -0
  108. package/lib/typescript/src/AdView.d.ts +69 -0
  109. package/lib/typescript/src/AdView.d.ts.map +1 -0
  110. package/lib/typescript/src/AppTrackingTransparency.d.ts +28 -0
  111. package/lib/typescript/src/AppTrackingTransparency.d.ts.map +1 -0
  112. package/lib/typescript/src/BannerAd.d.ts +4 -0
  113. package/lib/typescript/src/BannerAd.d.ts.map +1 -0
  114. package/lib/typescript/src/CloudX.d.ts +4 -0
  115. package/lib/typescript/src/CloudX.d.ts.map +1 -0
  116. package/lib/typescript/src/ErrorCode.d.ts +102 -0
  117. package/lib/typescript/src/ErrorCode.d.ts.map +1 -0
  118. package/lib/typescript/src/EventEmitter.d.ts +16 -0
  119. package/lib/typescript/src/EventEmitter.d.ts.map +1 -0
  120. package/lib/typescript/src/InterstitialAd.d.ts +4 -0
  121. package/lib/typescript/src/InterstitialAd.d.ts.map +1 -0
  122. package/lib/typescript/src/MRecAd.d.ts +4 -0
  123. package/lib/typescript/src/MRecAd.d.ts.map +1 -0
  124. package/lib/typescript/src/RewardedAd.d.ts +4 -0
  125. package/lib/typescript/src/RewardedAd.d.ts.map +1 -0
  126. package/lib/typescript/src/hooks.d.ts +50 -0
  127. package/lib/typescript/src/hooks.d.ts.map +1 -0
  128. package/lib/typescript/src/index.d.ts +23 -0
  129. package/lib/typescript/src/index.d.ts.map +1 -0
  130. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +61 -0
  131. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -0
  132. package/lib/typescript/src/specs/NativeCloudXModule.d.ts +106 -0
  133. package/lib/typescript/src/specs/NativeCloudXModule.d.ts.map +1 -0
  134. package/lib/typescript/src/types/AdEvent.d.ts +10 -0
  135. package/lib/typescript/src/types/AdEvent.d.ts.map +1 -0
  136. package/lib/typescript/src/types/AdInfo.d.ts +48 -0
  137. package/lib/typescript/src/types/AdInfo.d.ts.map +1 -0
  138. package/lib/typescript/src/types/BannerAd.d.ts +39 -0
  139. package/lib/typescript/src/types/BannerAd.d.ts.map +1 -0
  140. package/lib/typescript/src/types/CloudX.d.ts +25 -0
  141. package/lib/typescript/src/types/CloudX.d.ts.map +1 -0
  142. package/lib/typescript/src/types/Configuration.d.ts +10 -0
  143. package/lib/typescript/src/types/Configuration.d.ts.map +1 -0
  144. package/lib/typescript/src/types/FullscreenAd.d.ts +29 -0
  145. package/lib/typescript/src/types/FullscreenAd.d.ts.map +1 -0
  146. package/lib/typescript/src/types/RewardedAd.d.ts +10 -0
  147. package/lib/typescript/src/types/RewardedAd.d.ts.map +1 -0
  148. package/lib/typescript/src/types/index.d.ts +8 -0
  149. package/lib/typescript/src/types/index.d.ts.map +1 -0
  150. package/package.json +78 -0
  151. package/src/AdView.tsx +213 -0
  152. package/src/AppTrackingTransparency.ts +56 -0
  153. package/src/BannerAd.ts +133 -0
  154. package/src/CloudX.ts +55 -0
  155. package/src/ErrorCode.ts +157 -0
  156. package/src/EventEmitter.ts +38 -0
  157. package/src/InterstitialAd.ts +103 -0
  158. package/src/MRecAd.ts +133 -0
  159. package/src/RewardedAd.ts +113 -0
  160. package/src/hooks.ts +292 -0
  161. package/src/index.ts +50 -0
  162. package/src/specs/CloudXAdViewNativeComponent.ts +82 -0
  163. package/src/specs/NativeCloudXModule.ts +162 -0
  164. package/src/types/AdEvent.ts +11 -0
  165. package/src/types/AdInfo.ts +60 -0
  166. package/src/types/BannerAd.ts +59 -0
  167. package/src/types/CloudX.ts +33 -0
  168. package/src/types/Configuration.ts +10 -0
  169. package/src/types/FullscreenAd.ts +39 -0
  170. package/src/types/RewardedAd.ts +10 -0
  171. package/src/types/index.ts +7 -0
@@ -0,0 +1,633 @@
1
+ //
2
+ // RNCloudXBannerView.mm
3
+ // cloudx-react-native
4
+ //
5
+
6
+ #import "RNCloudXBannerView.h"
7
+ #import <React/RCTLog.h>
8
+ #import <CloudXCore/CLXError.h>
9
+
10
+ #ifdef RCT_NEW_ARCH_ENABLED
11
+ #import <react/renderer/components/RNCloudXSpec/ComponentDescriptors.h>
12
+ #import <react/renderer/components/RNCloudXSpec/EventEmitters.h>
13
+ #import <react/renderer/components/RNCloudXSpec/Props.h>
14
+ #import <react/renderer/components/RNCloudXSpec/RCTComponentViewHelpers.h>
15
+ #import <React/RCTConversions.h>
16
+ #import "RCTFabricComponentsPlugins.h"
17
+ using namespace facebook::react;
18
+ #endif
19
+
20
+ #ifdef RCT_NEW_ARCH_ENABLED
21
+ @interface RNCloudXBannerView () <RCTCloudXAdViewViewProtocol>
22
+ #else
23
+ @interface RNCloudXBannerView ()
24
+ #endif
25
+ @property (nonatomic, strong) CLXBannerAdView *bannerAdView;
26
+ @property (nonatomic, assign) BOOL hasCreatedAd;
27
+ @property (nonatomic, assign) BOOL isUsingWindowPositioning;
28
+ @end
29
+
30
+ @implementation RNCloudXBannerView
31
+
32
+ #ifdef RCT_NEW_ARCH_ENABLED
33
+
34
+ + (ComponentDescriptorProvider)componentDescriptorProvider
35
+ {
36
+ return concreteComponentDescriptorProvider<CloudXAdViewComponentDescriptor>();
37
+ }
38
+
39
+ - (instancetype)initWithFrame:(CGRect)frame
40
+ {
41
+ self = [super initWithFrame:frame];
42
+ if (self) {
43
+ static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
44
+ _props = defaultProps;
45
+
46
+ const auto &initProps = *std::static_pointer_cast<CloudXAdViewProps const>(_props);
47
+ _hasCreatedAd = NO;
48
+ _isUsingWindowPositioning = NO;
49
+ _autoRefresh = initProps.autoRefresh;
50
+ _shouldLoad = initProps.loadOnMount;
51
+ self.backgroundColor = [UIColor clearColor];
52
+
53
+ [self setupEventHandlers];
54
+ }
55
+ return self;
56
+ }
57
+
58
+ - (void)setupEventHandlers
59
+ {
60
+ self.onAdLoaded = [self](NSDictionary *event) {
61
+ if (_eventEmitter) {
62
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
63
+ CloudXAdViewEventEmitter::OnAdLoaded result = {
64
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
65
+ .adFormat = std::string([event[@"adFormat"] ?: @"" UTF8String]),
66
+ .networkName = std::string([event[@"networkName"] ?: @"" UTF8String]),
67
+ .networkPlacement = std::string([event[@"networkPlacement"] ?: @"" UTF8String]),
68
+ .placement = std::string([event[@"placement"] ?: @"" UTF8String]),
69
+ .revenue = [event[@"revenue"] doubleValue],
70
+ };
71
+ emitter->onAdLoaded(result);
72
+ }
73
+ };
74
+
75
+ self.onAdLoadFailed = [self](NSDictionary *event) {
76
+ if (_eventEmitter) {
77
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
78
+ CloudXAdViewEventEmitter::OnAdLoadFailed result = {
79
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
80
+ .code = [event[@"code"] intValue],
81
+ .message = std::string([event[@"message"] ?: @"" UTF8String]),
82
+ };
83
+ emitter->onAdLoadFailed(result);
84
+ }
85
+ };
86
+
87
+ self.onAdClicked = [self](NSDictionary *event) {
88
+ if (_eventEmitter) {
89
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
90
+ CloudXAdViewEventEmitter::OnAdClicked result = {
91
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
92
+ .adFormat = std::string([event[@"adFormat"] ?: @"" UTF8String]),
93
+ .networkName = std::string([event[@"networkName"] ?: @"" UTF8String]),
94
+ .networkPlacement = std::string([event[@"networkPlacement"] ?: @"" UTF8String]),
95
+ .placement = std::string([event[@"placement"] ?: @"" UTF8String]),
96
+ .revenue = [event[@"revenue"] doubleValue],
97
+ };
98
+ emitter->onAdClicked(result);
99
+ }
100
+ };
101
+
102
+ self.onAdExpanded = [self](NSDictionary *event) {
103
+ if (_eventEmitter) {
104
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
105
+ CloudXAdViewEventEmitter::OnAdExpanded result = {
106
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
107
+ .adFormat = std::string([event[@"adFormat"] ?: @"" UTF8String]),
108
+ .networkName = std::string([event[@"networkName"] ?: @"" UTF8String]),
109
+ .networkPlacement = std::string([event[@"networkPlacement"] ?: @"" UTF8String]),
110
+ .placement = std::string([event[@"placement"] ?: @"" UTF8String]),
111
+ .revenue = [event[@"revenue"] doubleValue],
112
+ };
113
+ emitter->onAdExpanded(result);
114
+ }
115
+ };
116
+
117
+ self.onAdCollapsed = [self](NSDictionary *event) {
118
+ if (_eventEmitter) {
119
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
120
+ CloudXAdViewEventEmitter::OnAdCollapsed result = {
121
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
122
+ .adFormat = std::string([event[@"adFormat"] ?: @"" UTF8String]),
123
+ .networkName = std::string([event[@"networkName"] ?: @"" UTF8String]),
124
+ .networkPlacement = std::string([event[@"networkPlacement"] ?: @"" UTF8String]),
125
+ .placement = std::string([event[@"placement"] ?: @"" UTF8String]),
126
+ .revenue = [event[@"revenue"] doubleValue],
127
+ };
128
+ emitter->onAdCollapsed(result);
129
+ }
130
+ };
131
+
132
+ self.onAdRevenuePaid = [self](NSDictionary *event) {
133
+ if (_eventEmitter) {
134
+ auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(_eventEmitter);
135
+ CloudXAdViewEventEmitter::OnAdRevenuePaid result = {
136
+ .adUnitId = std::string([event[@"adUnitId"] ?: @"" UTF8String]),
137
+ .adFormat = std::string([event[@"adFormat"] ?: @"" UTF8String]),
138
+ .networkName = std::string([event[@"networkName"] ?: @"" UTF8String]),
139
+ .networkPlacement = std::string([event[@"networkPlacement"] ?: @"" UTF8String]),
140
+ .placement = std::string([event[@"placement"] ?: @"" UTF8String]),
141
+ .revenue = [event[@"revenue"] doubleValue],
142
+ };
143
+ emitter->onAdRevenuePaid(result);
144
+ }
145
+ };
146
+ }
147
+
148
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
149
+ {
150
+ const auto &oldViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(_props);
151
+ const auto &newViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(props);
152
+
153
+ BOOL adUnitIdChanged = NO;
154
+
155
+ if (oldViewProps.adUnitId != newViewProps.adUnitId) {
156
+ [self setAdId:RCTNSStringFromString(newViewProps.adUnitId)];
157
+ adUnitIdChanged = YES;
158
+ }
159
+
160
+ if (oldViewProps.adFormat != newViewProps.adFormat) {
161
+ [self setBannerSize:RCTNSStringFromString(newViewProps.adFormat)];
162
+ }
163
+
164
+ if (oldViewProps.placement != newViewProps.placement) {
165
+ [self setPlacement:RCTNSStringFromString(newViewProps.placement)];
166
+ }
167
+
168
+ if (oldViewProps.customData != newViewProps.customData) {
169
+ [self setCustomData:RCTNSStringFromString(newViewProps.customData)];
170
+ }
171
+
172
+ if (oldViewProps.autoRefresh != newViewProps.autoRefresh) {
173
+ [self setAutoRefresh:newViewProps.autoRefresh];
174
+ }
175
+
176
+ if (oldViewProps.loadOnMount != newViewProps.loadOnMount) {
177
+ [self setShouldLoad:newViewProps.loadOnMount];
178
+ }
179
+
180
+ if (oldViewProps.adPosition != newViewProps.adPosition) {
181
+ [self setAdPosition:RCTNSStringFromString(newViewProps.adPosition)];
182
+ }
183
+
184
+ if (adUnitIdChanged) {
185
+ [self attemptLoadIfReady];
186
+ }
187
+
188
+ [super updateProps:props oldProps:oldProps];
189
+ }
190
+
191
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
192
+ {
193
+ if ([commandName isEqualToString:@"loadAd"]) {
194
+ [self loadAd];
195
+ } else if ([commandName isEqualToString:@"destroy"]) {
196
+ [self destroyAd];
197
+ }
198
+ }
199
+
200
+ - (void)prepareForRecycle
201
+ {
202
+ [super prepareForRecycle];
203
+
204
+ static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
205
+ _props = defaultProps;
206
+
207
+ [self destroyAd];
208
+
209
+ _adId = nil;
210
+ _bannerSize = nil;
211
+ _adPosition = nil;
212
+ _placement = nil;
213
+ _customData = nil;
214
+ _hasCreatedAd = NO;
215
+ _isUsingWindowPositioning = NO;
216
+ _autoRefresh = NO;
217
+ _shouldLoad = NO;
218
+ }
219
+
220
+ #else
221
+
222
+ - (instancetype)init {
223
+ if (self = [super init]) {
224
+ _hasCreatedAd = NO;
225
+ _isUsingWindowPositioning = NO;
226
+ _autoRefresh = YES;
227
+ self.backgroundColor = [UIColor clearColor];
228
+ }
229
+ return self;
230
+ }
231
+
232
+ #endif
233
+
234
+ // Dispatch to main queue -- dealloc may run on arbitrary threads
235
+ - (void)dealloc {
236
+ CLXBannerAdView *adView = _bannerAdView;
237
+ BOOL needsWindowRemoval = _isUsingWindowPositioning;
238
+ if (adView) {
239
+ dispatch_async(dispatch_get_main_queue(), ^{
240
+ adView.delegate = nil;
241
+ adView.revenueDelegate = nil;
242
+ [adView stopAutoRefresh];
243
+ if (needsWindowRemoval) [adView removeFromSuperview];
244
+ [adView destroy];
245
+ });
246
+ }
247
+ }
248
+
249
+ #pragma mark - Position Helpers
250
+
251
+ - (RNCloudXAdViewPosition)positionFromString:(NSString *)positionString {
252
+ if (!positionString || positionString.length == 0) {
253
+ return RNCloudXAdViewPositionNone;
254
+ }
255
+
256
+ NSDictionary *positionMap = @{
257
+ @"TOP_LEFT": @(RNCloudXAdViewPositionTopLeft),
258
+ @"TOP_CENTER": @(RNCloudXAdViewPositionTopCenter),
259
+ @"TOP_RIGHT": @(RNCloudXAdViewPositionTopRight),
260
+ @"CENTER_LEFT": @(RNCloudXAdViewPositionCenterLeft),
261
+ @"CENTERED": @(RNCloudXAdViewPositionCentered),
262
+ @"CENTER_RIGHT": @(RNCloudXAdViewPositionCenterRight),
263
+ @"BOTTOM_LEFT": @(RNCloudXAdViewPositionBottomLeft),
264
+ @"BOTTOM_CENTER": @(RNCloudXAdViewPositionBottomCenter),
265
+ @"BOTTOM_RIGHT": @(RNCloudXAdViewPositionBottomRight),
266
+ };
267
+
268
+ NSNumber *position = positionMap[positionString.uppercaseString];
269
+ return position ? (RNCloudXAdViewPosition)position.integerValue : RNCloudXAdViewPositionNone;
270
+ }
271
+
272
+ - (void)setShouldLoad:(BOOL)shouldLoad {
273
+ _shouldLoad = shouldLoad;
274
+ [self attemptLoadIfReady];
275
+ }
276
+
277
+ - (void)setAdId:(NSString *)adId {
278
+ _adId = adId;
279
+ [self attemptLoadIfReady];
280
+ }
281
+
282
+ - (void)setPlacement:(NSString *)placement {
283
+ _placement = placement;
284
+ if (self.bannerAdView) {
285
+ self.bannerAdView.placement = placement;
286
+ }
287
+ [self attemptLoadIfReady];
288
+ }
289
+
290
+ - (void)setCustomData:(NSString *)customData {
291
+ _customData = customData;
292
+ if (self.bannerAdView) {
293
+ self.bannerAdView.customData = customData;
294
+ }
295
+ }
296
+
297
+ // Destroy and recreate if format changed on an already-mounted ad,
298
+ // since banner and MREC use different native SDK creation methods.
299
+ - (void)setBannerSize:(NSString *)bannerSize {
300
+ NSString *oldSize = _bannerSize;
301
+ _bannerSize = [bannerSize copy];
302
+ if (self.hasCreatedAd && oldSize != nil && ![oldSize isEqualToString:bannerSize]) {
303
+ [self destroyAd];
304
+ [self attemptLoadIfReady];
305
+ }
306
+ }
307
+
308
+ - (void)setAutoRefresh:(BOOL)autoRefresh {
309
+ _autoRefresh = autoRefresh;
310
+ if (self.bannerAdView) {
311
+ if (autoRefresh) {
312
+ [self.bannerAdView startAutoRefresh];
313
+ } else {
314
+ [self.bannerAdView stopAutoRefresh];
315
+ }
316
+ }
317
+ }
318
+
319
+ - (void)didSetProps:(NSArray<NSString *> *)changedProps {
320
+ [self attemptLoadIfReady];
321
+ }
322
+
323
+ - (void)attemptLoadIfReady {
324
+ if (self.shouldLoad && !self.hasCreatedAd && self.adId) {
325
+ dispatch_async(dispatch_get_main_queue(), ^{
326
+ if (!self.hasCreatedAd) {
327
+ [self createAndLoadBanner];
328
+ }
329
+ });
330
+ }
331
+ }
332
+
333
+ - (void)loadAd {
334
+ if (self.bannerAdView) {
335
+ [self.bannerAdView load];
336
+ }
337
+ }
338
+
339
+ - (void)destroyAd {
340
+ if (self.bannerAdView) {
341
+ self.bannerAdView.delegate = nil;
342
+ self.bannerAdView.revenueDelegate = nil;
343
+ [self.bannerAdView stopAutoRefresh];
344
+ if (self.isUsingWindowPositioning) {
345
+ [self.bannerAdView removeFromSuperview];
346
+ }
347
+ [self.bannerAdView destroy];
348
+ self.bannerAdView = nil;
349
+ self.hasCreatedAd = NO;
350
+ }
351
+ }
352
+
353
+ - (void)createAndLoadBanner {
354
+ if (self.hasCreatedAd) {
355
+ return;
356
+ }
357
+
358
+ UIViewController *viewController = [self reactViewController];
359
+ if (!viewController) {
360
+ RCTLogError(@"[CloudXBannerView] No view controller found");
361
+ if (self.onAdLoadFailed) {
362
+ self.onAdLoadFailed(@{
363
+ @"adUnitId": self.adId ?: @"",
364
+ @"code": @(-1),
365
+ @"message": @"No view controller"
366
+ });
367
+ }
368
+ return;
369
+ }
370
+
371
+ // Determine if this is a banner or MREC
372
+ BOOL isMREC = [self.bannerSize isEqualToString:@"MREC"];
373
+
374
+ NSString *adUnitId = self.adId;
375
+ if (isMREC) {
376
+ self.bannerAdView = [[CloudXCore shared] createMRECWithAdUnitId:adUnitId
377
+ viewController:viewController];
378
+ } else {
379
+ self.bannerAdView = [[CloudXCore shared] createBannerWithAdUnitId:adUnitId
380
+ viewController:viewController];
381
+ }
382
+ if (self.bannerAdView) {
383
+ self.bannerAdView.delegate = self;
384
+ self.bannerAdView.revenueDelegate = self;
385
+ if (self.placement) {
386
+ self.bannerAdView.placement = self.placement;
387
+ }
388
+ if (self.customData) {
389
+ self.bannerAdView.customData = self.customData;
390
+ }
391
+ if (!self.autoRefresh) {
392
+ [self.bannerAdView stopAutoRefresh];
393
+ }
394
+
395
+ self.hasCreatedAd = YES;
396
+
397
+ // Check if we should use programmatic window positioning
398
+ RNCloudXAdViewPosition adViewPosition = [self positionFromString:self.adPosition];
399
+
400
+ if (adViewPosition != RNCloudXAdViewPositionNone) {
401
+ [self addBannerToWindowWithPosition:adViewPosition isMREC:isMREC];
402
+ } else {
403
+ [self addBannerAsSubview];
404
+ }
405
+
406
+ [self.bannerAdView load];
407
+ } else {
408
+ RCTLogError(@"[CloudXBannerView] Failed to create banner");
409
+ if (self.onAdLoadFailed) {
410
+ self.onAdLoadFailed(@{
411
+ @"adUnitId": self.adId ?: @"",
412
+ @"code": @(-1),
413
+ @"message": @"Failed to create banner"
414
+ });
415
+ }
416
+ }
417
+ }
418
+
419
+ - (void)addBannerAsSubview {
420
+ self.isUsingWindowPositioning = NO;
421
+ self.bannerAdView.translatesAutoresizingMaskIntoConstraints = NO;
422
+ [self addSubview:self.bannerAdView];
423
+
424
+ // Setup constraints to fill container
425
+ [NSLayoutConstraint activateConstraints:@[
426
+ [self.bannerAdView.topAnchor constraintEqualToAnchor:self.topAnchor],
427
+ [self.bannerAdView.leftAnchor constraintEqualToAnchor:self.leftAnchor],
428
+ [self.bannerAdView.rightAnchor constraintEqualToAnchor:self.rightAnchor],
429
+ [self.bannerAdView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor]
430
+ ]];
431
+ }
432
+
433
+ - (void)addBannerToWindowWithPosition:(RNCloudXAdViewPosition)position isMREC:(BOOL)isMREC {
434
+ self.isUsingWindowPositioning = YES;
435
+
436
+ UIWindow *keyWindow = [self keyWindow];
437
+ if (!keyWindow) {
438
+ RCTLogError(@"[CloudXBannerView] No key window found for positioning");
439
+ [self addBannerAsSubview]; // Fallback to React Native layout
440
+ return;
441
+ }
442
+
443
+ self.bannerAdView.translatesAutoresizingMaskIntoConstraints = NO;
444
+ [keyWindow addSubview:self.bannerAdView];
445
+
446
+ // Banner dimensions
447
+ BOOL isTablet = (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad);
448
+ CGFloat bannerWidth = isMREC ? 300 : (isTablet ? 728 : 320);
449
+ CGFloat bannerHeight = isMREC ? 250 : (isTablet ? 90 : 50);
450
+
451
+ // Get safe area insets
452
+ UIEdgeInsets safeArea = UIEdgeInsetsZero;
453
+ if (@available(iOS 11.0, *)) {
454
+ safeArea = keyWindow.safeAreaInsets;
455
+ }
456
+
457
+ // Size constraints
458
+ [NSLayoutConstraint activateConstraints:@[
459
+ [self.bannerAdView.widthAnchor constraintEqualToConstant:bannerWidth],
460
+ [self.bannerAdView.heightAnchor constraintEqualToConstant:bannerHeight]
461
+ ]];
462
+
463
+ // Position constraints based on specified position
464
+ switch (position) {
465
+ case RNCloudXAdViewPositionTopLeft:
466
+ [NSLayoutConstraint activateConstraints:@[
467
+ [self.bannerAdView.topAnchor constraintEqualToAnchor:keyWindow.topAnchor constant:safeArea.top],
468
+ [self.bannerAdView.leftAnchor constraintEqualToAnchor:keyWindow.leftAnchor constant:safeArea.left]
469
+ ]];
470
+ break;
471
+
472
+ case RNCloudXAdViewPositionTopCenter:
473
+ [NSLayoutConstraint activateConstraints:@[
474
+ [self.bannerAdView.topAnchor constraintEqualToAnchor:keyWindow.topAnchor constant:safeArea.top],
475
+ [self.bannerAdView.centerXAnchor constraintEqualToAnchor:keyWindow.centerXAnchor]
476
+ ]];
477
+ break;
478
+
479
+ case RNCloudXAdViewPositionTopRight:
480
+ [NSLayoutConstraint activateConstraints:@[
481
+ [self.bannerAdView.topAnchor constraintEqualToAnchor:keyWindow.topAnchor constant:safeArea.top],
482
+ [self.bannerAdView.rightAnchor constraintEqualToAnchor:keyWindow.rightAnchor constant:-safeArea.right]
483
+ ]];
484
+ break;
485
+
486
+ case RNCloudXAdViewPositionCenterLeft:
487
+ [NSLayoutConstraint activateConstraints:@[
488
+ [self.bannerAdView.centerYAnchor constraintEqualToAnchor:keyWindow.centerYAnchor],
489
+ [self.bannerAdView.leftAnchor constraintEqualToAnchor:keyWindow.leftAnchor constant:safeArea.left]
490
+ ]];
491
+ break;
492
+
493
+ case RNCloudXAdViewPositionCentered:
494
+ [NSLayoutConstraint activateConstraints:@[
495
+ [self.bannerAdView.centerXAnchor constraintEqualToAnchor:keyWindow.centerXAnchor],
496
+ [self.bannerAdView.centerYAnchor constraintEqualToAnchor:keyWindow.centerYAnchor]
497
+ ]];
498
+ break;
499
+
500
+ case RNCloudXAdViewPositionCenterRight:
501
+ [NSLayoutConstraint activateConstraints:@[
502
+ [self.bannerAdView.centerYAnchor constraintEqualToAnchor:keyWindow.centerYAnchor],
503
+ [self.bannerAdView.rightAnchor constraintEqualToAnchor:keyWindow.rightAnchor constant:-safeArea.right]
504
+ ]];
505
+ break;
506
+
507
+ case RNCloudXAdViewPositionBottomLeft:
508
+ [NSLayoutConstraint activateConstraints:@[
509
+ [self.bannerAdView.bottomAnchor constraintEqualToAnchor:keyWindow.bottomAnchor constant:-safeArea.bottom],
510
+ [self.bannerAdView.leftAnchor constraintEqualToAnchor:keyWindow.leftAnchor constant:safeArea.left]
511
+ ]];
512
+ break;
513
+
514
+ case RNCloudXAdViewPositionBottomCenter:
515
+ [NSLayoutConstraint activateConstraints:@[
516
+ [self.bannerAdView.bottomAnchor constraintEqualToAnchor:keyWindow.bottomAnchor constant:-safeArea.bottom],
517
+ [self.bannerAdView.centerXAnchor constraintEqualToAnchor:keyWindow.centerXAnchor]
518
+ ]];
519
+ break;
520
+
521
+ case RNCloudXAdViewPositionBottomRight:
522
+ [NSLayoutConstraint activateConstraints:@[
523
+ [self.bannerAdView.bottomAnchor constraintEqualToAnchor:keyWindow.bottomAnchor constant:-safeArea.bottom],
524
+ [self.bannerAdView.rightAnchor constraintEqualToAnchor:keyWindow.rightAnchor constant:-safeArea.right]
525
+ ]];
526
+ break;
527
+
528
+ default:
529
+ // Should not reach here, but fallback to bottom center
530
+ [NSLayoutConstraint activateConstraints:@[
531
+ [self.bannerAdView.bottomAnchor constraintEqualToAnchor:keyWindow.bottomAnchor constant:-safeArea.bottom],
532
+ [self.bannerAdView.centerXAnchor constraintEqualToAnchor:keyWindow.centerXAnchor]
533
+ ]];
534
+ break;
535
+ }
536
+ }
537
+
538
+ - (UIWindow *)keyWindow {
539
+ if (@available(iOS 13.0, *)) {
540
+ for (UIWindowScene *scene in UIApplication.sharedApplication.connectedScenes) {
541
+ if (scene.activationState == UISceneActivationStateForegroundActive) {
542
+ for (UIWindow *window in scene.windows) {
543
+ if (window.isKeyWindow) {
544
+ return window;
545
+ }
546
+ }
547
+ }
548
+ }
549
+ }
550
+
551
+ // Fallback for iOS 12 and earlier
552
+ #pragma clang diagnostic push
553
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
554
+ return UIApplication.sharedApplication.keyWindow;
555
+ #pragma clang diagnostic pop
556
+ }
557
+
558
+ #pragma mark - Helper
559
+
560
+ - (UIViewController *)reactViewController {
561
+ UIResponder *responder = self;
562
+ while (responder) {
563
+ if ([responder isKindOfClass:[UIViewController class]]) {
564
+ return (UIViewController *)responder;
565
+ }
566
+ responder = [responder nextResponder];
567
+ }
568
+ return nil;
569
+ }
570
+
571
+ #pragma mark - CLXBannerDelegate
572
+
573
+ - (void)didLoadAd:(CLXAd *)ad {
574
+ NSDictionary *event = [self serializeAdEvent:ad];
575
+ if (self.onAdLoaded) {
576
+ self.onAdLoaded(event);
577
+ }
578
+ }
579
+
580
+ - (void)didFailToLoadAd:(NSString *)adUnitId error:(CLXError *)error {
581
+ RCTLogError(@"[CloudXBannerView] Banner failed to load: %@", error.localizedDescription);
582
+ NSDictionary *event = @{
583
+ @"adUnitId": adUnitId ?: self.adId ?: @"",
584
+ @"code": @(error.code),
585
+ @"message": error.localizedDescription ?: @"Unknown error"
586
+ };
587
+ if (self.onAdLoadFailed) {
588
+ self.onAdLoadFailed(event);
589
+ }
590
+ }
591
+
592
+ - (void)didClickAd:(CLXAd *)ad {
593
+ NSDictionary *event = [self serializeAdEvent:ad];
594
+ if (self.onAdClicked) {
595
+ self.onAdClicked(event);
596
+ }
597
+ }
598
+
599
+ - (void)didPayRevenueForAd:(CLXAd *)ad {
600
+ NSDictionary *event = [self serializeAdEvent:ad];
601
+ if (self.onAdRevenuePaid) {
602
+ self.onAdRevenuePaid(event);
603
+ }
604
+ }
605
+
606
+ - (void)didExpandAd:(CLXAd *)ad {
607
+ NSDictionary *event = [self serializeAdEvent:ad];
608
+ if (self.onAdExpanded) {
609
+ self.onAdExpanded(event);
610
+ }
611
+ }
612
+
613
+ - (void)didCollapseAd:(CLXAd *)ad {
614
+ NSDictionary *event = [self serializeAdEvent:ad];
615
+ if (self.onAdCollapsed) {
616
+ self.onAdCollapsed(event);
617
+ }
618
+ }
619
+
620
+ #pragma mark - Serialization Helper
621
+
622
+ - (NSDictionary *)serializeAdEvent:(CLXAd *)ad {
623
+ NSMutableDictionary *eventData = [NSMutableDictionary dictionary];
624
+ eventData[@"adUnitId"] = ad.adUnitId ?: self.adId ?: @"";
625
+ eventData[@"adFormat"] = [self.bannerSize isEqualToString:@"MREC"] ? @"MREC" : @"BANNER";
626
+ eventData[@"networkName"] = ad.networkName ?: @"";
627
+ eventData[@"networkPlacement"] = ad.networkPlacement ?: @"";
628
+ eventData[@"placement"] = ad.placement ?: self.placement ?: @"";
629
+ eventData[@"revenue"] = ad.revenue ? @([ad.revenue doubleValue]) : @(0);
630
+ return eventData;
631
+ }
632
+
633
+ @end
@@ -0,0 +1,11 @@
1
+ //
2
+ // RNCloudXBannerViewManager.h
3
+ // cloudx-react-native
4
+ //
5
+
6
+ #import <React/RCTViewManager.h>
7
+
8
+ @interface RNCloudXBannerViewManager : RCTViewManager
9
+
10
+ @end
11
+
@@ -0,0 +1,60 @@
1
+ //
2
+ // RNCloudXBannerViewManager.m
3
+ // cloudx-react-native
4
+ //
5
+
6
+ #import "RNCloudXBannerViewManager.h"
7
+ #import "RNCloudXBannerView.h"
8
+ #import <React/RCTUIManager.h>
9
+
10
+ @implementation RNCloudXBannerViewManager
11
+
12
+ RCT_EXPORT_MODULE(CloudXAdView)
13
+
14
+ - (UIView *)view {
15
+ return [[RNCloudXBannerView alloc] init];
16
+ }
17
+
18
+ // Props matching the codegen spec (CloudXAdViewNativeComponent.ts)
19
+ // Remap JS prop names to native ObjC property names where they differ
20
+ RCT_REMAP_VIEW_PROPERTY(adUnitId, adId, NSString)
21
+ RCT_REMAP_VIEW_PROPERTY(adFormat, bannerSize, NSString)
22
+ RCT_REMAP_VIEW_PROPERTY(loadOnMount, shouldLoad, BOOL)
23
+ RCT_EXPORT_VIEW_PROPERTY(placement, NSString)
24
+ RCT_EXPORT_VIEW_PROPERTY(customData, NSString)
25
+ RCT_EXPORT_VIEW_PROPERTY(autoRefresh, BOOL)
26
+ RCT_EXPORT_VIEW_PROPERTY(adPosition, NSString)
27
+ RCT_EXPORT_VIEW_PROPERTY(onAdLoaded, RCTDirectEventBlock)
28
+ RCT_EXPORT_VIEW_PROPERTY(onAdLoadFailed, RCTDirectEventBlock)
29
+ RCT_EXPORT_VIEW_PROPERTY(onAdClicked, RCTDirectEventBlock)
30
+ RCT_EXPORT_VIEW_PROPERTY(onAdExpanded, RCTDirectEventBlock)
31
+ RCT_EXPORT_VIEW_PROPERTY(onAdCollapsed, RCTDirectEventBlock)
32
+ RCT_EXPORT_VIEW_PROPERTY(onAdRevenuePaid, RCTDirectEventBlock)
33
+
34
+ + (BOOL)requiresMainQueueSetup {
35
+ return YES;
36
+ }
37
+
38
+ #pragma mark - Native Commands
39
+
40
+ - (void)receiveCommand:(UIView *)view commandName:(NSString *)commandName args:(NSArray *)args {
41
+ RNCloudXBannerView *bannerView = (RNCloudXBannerView *)view;
42
+ if ([commandName isEqualToString:@"loadAd"]) {
43
+ [bannerView loadAd];
44
+ } else if ([commandName isEqualToString:@"destroy"]) {
45
+ [bannerView destroyAd];
46
+ }
47
+ }
48
+
49
+ @end
50
+
51
+ #ifdef RCT_NEW_ARCH_ENABLED
52
+ #import <React/RCTComponentViewProtocol.h>
53
+ #import "RNCloudXBannerView.h"
54
+
55
+ extern "C" Class<RCTComponentViewProtocol> CloudXAdViewCls(void)
56
+ {
57
+ return [RNCloudXBannerView class];
58
+ }
59
+ #endif
60
+