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.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +16 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +14 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdView.kt +238 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +28 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewManagerImpl.kt +54 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXExtraParameters.kt +101 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +171 -57
- package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +1 -1
- package/android/src/newarch/com/cloudxreactnative/CloudXAdViewManager.kt +52 -0
- package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +7 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXAdViewManager.kt +46 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +7 -0
- package/cloudx-react-native.podspec +3 -3
- package/ios/CloudX.h +2 -2
- package/ios/CloudX.mm +268 -62
- package/ios/CloudXAdView.h +33 -0
- package/ios/CloudXAdView.mm +500 -0
- package/ios/CloudXAdViewManager.h +12 -0
- package/ios/CloudXAdViewManager.mm +38 -0
- package/ios/CloudXExtraParameters.h +27 -0
- package/ios/CloudXExtraParameters.mm +117 -0
- package/lib/commonjs/CloudX.js +5 -1
- package/lib/commonjs/CloudX.js.map +1 -1
- package/lib/commonjs/CloudXAdViewBase.js +250 -0
- package/lib/commonjs/CloudXAdViewBase.js.map +1 -0
- package/lib/commonjs/CloudXAppOpenAd.js +98 -0
- package/lib/commonjs/CloudXAppOpenAd.js.map +1 -0
- package/lib/commonjs/CloudXBannerView.js +27 -0
- package/lib/commonjs/CloudXBannerView.js.map +1 -0
- package/lib/commonjs/CloudXMRECView.js +27 -0
- package/lib/commonjs/CloudXMRECView.js.map +1 -0
- package/lib/commonjs/hooks.js +81 -0
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +53 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +30 -0
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/NativeCloudX.js.map +1 -1
- package/lib/commonjs/types/AppOpenAd.js +6 -0
- package/lib/commonjs/types/AppOpenAd.js.map +1 -0
- package/lib/commonjs/types/RevenueData.js +21 -0
- package/lib/commonjs/types/RevenueData.js.map +1 -0
- package/lib/commonjs/types/index.js +17 -0
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/CloudX.js +5 -1
- package/lib/module/CloudX.js.map +1 -1
- package/lib/module/CloudXAdViewBase.js +242 -0
- package/lib/module/CloudXAdViewBase.js.map +1 -0
- package/lib/module/CloudXAppOpenAd.js +91 -0
- package/lib/module/CloudXAppOpenAd.js.map +1 -0
- package/lib/module/CloudXBannerView.js +19 -0
- package/lib/module/CloudXBannerView.js.map +1 -0
- package/lib/module/CloudXMRECView.js +19 -0
- package/lib/module/CloudXMRECView.js.map +1 -0
- package/lib/module/hooks.js +80 -0
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +10 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/CloudXAdViewNativeComponent.js +27 -0
- package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/module/specs/NativeCloudX.js.map +1 -1
- package/lib/module/types/AppOpenAd.js +2 -0
- package/lib/module/types/AppOpenAd.js.map +1 -0
- package/lib/module/types/RevenueData.js +15 -0
- package/lib/module/types/RevenueData.js.map +1 -0
- package/lib/module/types/index.js +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/CloudXAdViewBase.d.ts +28 -0
- package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -0
- package/lib/typescript/src/CloudXAppOpenAd.d.ts +4 -0
- package/lib/typescript/src/CloudXAppOpenAd.d.ts.map +1 -0
- package/lib/typescript/src/CloudXBannerView.d.ts +16 -0
- package/lib/typescript/src/CloudXBannerView.d.ts.map +1 -0
- package/lib/typescript/src/CloudXMRECView.d.ts +16 -0
- package/lib/typescript/src/CloudXMRECView.d.ts.map +1 -0
- package/lib/typescript/src/hooks.d.ts +14 -0
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +9 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +62 -0
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeCloudX.d.ts +13 -0
- package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -1
- package/lib/typescript/src/types/AdProps.d.ts +3 -0
- package/lib/typescript/src/types/AdProps.d.ts.map +1 -1
- package/lib/typescript/src/types/AppOpenAd.d.ts +8 -0
- package/lib/typescript/src/types/AppOpenAd.d.ts.map +1 -0
- package/lib/typescript/src/types/CloudX.d.ts +6 -0
- package/lib/typescript/src/types/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/types/RevenueData.d.ts +32 -0
- package/lib/typescript/src/types/RevenueData.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +3 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +6 -2
- package/src/CloudX.ts +6 -0
- package/src/CloudXAdViewBase.tsx +294 -0
- package/src/CloudXAppOpenAd.ts +109 -0
- package/src/CloudXBannerView.tsx +20 -0
- package/src/CloudXMRECView.tsx +20 -0
- package/src/hooks.ts +103 -0
- package/src/index.ts +22 -2
- package/src/specs/CloudXAdViewNativeComponent.ts +84 -0
- package/src/specs/NativeCloudX.ts +22 -0
- package/src/types/AdProps.ts +4 -0
- package/src/types/AppOpenAd.ts +8 -0
- package/src/types/CloudX.ts +7 -0
- package/src/types/RevenueData.ts +39 -0
- package/src/types/index.ts +3 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CloudXAdView.mm
|
|
3
|
+
// cloudx-react-native
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
#import "CloudXAdView.h"
|
|
7
|
+
#import "CloudXExtraParameters.h"
|
|
8
|
+
#import <React/RCTLog.h>
|
|
9
|
+
|
|
10
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
11
|
+
#import <react/renderer/components/CloudXSpec/ComponentDescriptors.h>
|
|
12
|
+
#import <react/renderer/components/CloudXSpec/EventEmitters.h>
|
|
13
|
+
#import <react/renderer/components/CloudXSpec/Props.h>
|
|
14
|
+
#import <react/renderer/components/CloudXSpec/RCTComponentViewHelpers.h>
|
|
15
|
+
#import <React/RCTConversions.h>
|
|
16
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
17
|
+
|
|
18
|
+
using namespace facebook::react;
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Fills a generated AdInfo-style event struct from the NSDictionary the ad
|
|
22
|
+
* delegate builds. All three ad-info events share the same field set, so this
|
|
23
|
+
* macro keeps the three emitter blocks in sync.
|
|
24
|
+
*/
|
|
25
|
+
#define CLX_FILL_ADINFO(result, event) \
|
|
26
|
+
result.adUnitId = std::string([(event[@"adUnitId"] ?: @"") UTF8String]); \
|
|
27
|
+
result.adFormat = std::string([(event[@"adFormat"] ?: @"") UTF8String]); \
|
|
28
|
+
result.networkName = std::string([(event[@"networkName"] ?: @"") UTF8String]); \
|
|
29
|
+
result.networkPlacement = std::string([(event[@"networkPlacement"] ?: @"") UTF8String]); \
|
|
30
|
+
result.placement = std::string([(event[@"placement"] ?: @"") UTF8String]); \
|
|
31
|
+
result.revenue = [event[@"revenue"] doubleValue]; \
|
|
32
|
+
result.adValuesJson = std::string([(event[@"adValuesJson"] ?: @"") UTF8String]);
|
|
33
|
+
|
|
34
|
+
static id CLXIdFromFollyDynamic(const folly::dynamic &dynamicValue)
|
|
35
|
+
{
|
|
36
|
+
switch ( dynamicValue.type() )
|
|
37
|
+
{
|
|
38
|
+
case folly::dynamic::NULLT:
|
|
39
|
+
return [NSNull null];
|
|
40
|
+
case folly::dynamic::BOOL:
|
|
41
|
+
return @(dynamicValue.getBool());
|
|
42
|
+
case folly::dynamic::INT64:
|
|
43
|
+
return @(dynamicValue.getInt());
|
|
44
|
+
case folly::dynamic::DOUBLE:
|
|
45
|
+
return @(dynamicValue.getDouble());
|
|
46
|
+
case folly::dynamic::STRING:
|
|
47
|
+
return [[NSString alloc] initWithBytes: dynamicValue.c_str() length: dynamicValue.size() encoding: NSUTF8StringEncoding] ?: @"";
|
|
48
|
+
case folly::dynamic::ARRAY: {
|
|
49
|
+
NSMutableArray *array = [NSMutableArray arrayWithCapacity: dynamicValue.size()];
|
|
50
|
+
for ( const auto &item : dynamicValue )
|
|
51
|
+
{
|
|
52
|
+
[array addObject: CLXIdFromFollyDynamic(item) ?: [NSNull null]];
|
|
53
|
+
}
|
|
54
|
+
return [array copy];
|
|
55
|
+
}
|
|
56
|
+
case folly::dynamic::OBJECT: {
|
|
57
|
+
NSMutableDictionary<NSString *, id> *dictionary = [NSMutableDictionary dictionaryWithCapacity: dynamicValue.size()];
|
|
58
|
+
for ( const auto &item : dynamicValue.items() )
|
|
59
|
+
{
|
|
60
|
+
id key = CLXIdFromFollyDynamic(item.first);
|
|
61
|
+
if ( ![key isKindOfClass: [NSString class]] ) continue;
|
|
62
|
+
dictionary[key] = CLXIdFromFollyDynamic(item.second) ?: [NSNull null];
|
|
63
|
+
}
|
|
64
|
+
return [dictionary copy];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return [NSNull null];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@interface CloudXAdView () <RCTCloudXAdViewViewProtocol>
|
|
72
|
+
#else
|
|
73
|
+
@interface CloudXAdView ()
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
@property (nonatomic, strong, nullable) CLXBannerAdView *adView;
|
|
77
|
+
@property (nonatomic, copy, nullable) NSString *adUnitId;
|
|
78
|
+
@property (nonatomic, copy, nullable) NSString *adFormat;
|
|
79
|
+
@property (nonatomic, copy, nullable) NSString *placement;
|
|
80
|
+
@property (nonatomic, copy, nullable) NSString *customData;
|
|
81
|
+
@property (nonatomic, copy) NSDictionary<NSString *, id> *extraParameters;
|
|
82
|
+
@property (nonatomic, copy) NSSet<NSString *> *appliedExtraParameterKeys;
|
|
83
|
+
|
|
84
|
+
@end
|
|
85
|
+
|
|
86
|
+
@implementation CloudXAdView
|
|
87
|
+
|
|
88
|
+
- (void)commonInit
|
|
89
|
+
{
|
|
90
|
+
_extraParameters = @{};
|
|
91
|
+
_appliedExtraParameterKeys = [NSSet set];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
95
|
+
|
|
96
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
97
|
+
{
|
|
98
|
+
return concreteComponentDescriptorProvider<CloudXAdViewComponentDescriptor>();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
102
|
+
{
|
|
103
|
+
self = [super initWithFrame: frame];
|
|
104
|
+
if ( self )
|
|
105
|
+
{
|
|
106
|
+
[self commonInit];
|
|
107
|
+
static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
|
|
108
|
+
_props = defaultProps;
|
|
109
|
+
[self setupEventHandlers];
|
|
110
|
+
}
|
|
111
|
+
return self;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* On Fabric the RCTDirectEventBlock properties are not wired by a view manager,
|
|
116
|
+
* so point each block at the generated C++ EventEmitter. The delegate callbacks
|
|
117
|
+
* below always call self.onXxxEvent(dict) regardless of architecture.
|
|
118
|
+
*/
|
|
119
|
+
- (void)setupEventHandlers
|
|
120
|
+
{
|
|
121
|
+
__weak CloudXAdView *weakSelf = self;
|
|
122
|
+
|
|
123
|
+
self.onAdLoadedEvent = ^(NSDictionary *event) {
|
|
124
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
125
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
126
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
127
|
+
CloudXAdViewEventEmitter::OnAdLoadedEvent result;
|
|
128
|
+
CLX_FILL_ADINFO(result, event);
|
|
129
|
+
emitter->onAdLoadedEvent(result);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
self.onAdClickedEvent = ^(NSDictionary *event) {
|
|
133
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
134
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
135
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
136
|
+
CloudXAdViewEventEmitter::OnAdClickedEvent result;
|
|
137
|
+
CLX_FILL_ADINFO(result, event);
|
|
138
|
+
emitter->onAdClickedEvent(result);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
self.onAdRevenuePaidEvent = ^(NSDictionary *event) {
|
|
142
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
143
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
144
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
145
|
+
CloudXAdViewEventEmitter::OnAdRevenuePaidEvent result;
|
|
146
|
+
CLX_FILL_ADINFO(result, event);
|
|
147
|
+
emitter->onAdRevenuePaidEvent(result);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
self.onAdLoadFailedEvent = ^(NSDictionary *event) {
|
|
151
|
+
CloudXAdView *strongSelf = weakSelf;
|
|
152
|
+
if ( !strongSelf || !strongSelf->_eventEmitter ) return;
|
|
153
|
+
auto emitter = std::static_pointer_cast<CloudXAdViewEventEmitter const>(strongSelf->_eventEmitter);
|
|
154
|
+
CloudXAdViewEventEmitter::OnAdLoadFailedEvent result;
|
|
155
|
+
result.adUnitId = std::string([(event[@"adUnitId"] ?: @"") UTF8String]);
|
|
156
|
+
result.code = [event[@"code"] doubleValue];
|
|
157
|
+
result.message = std::string([(event[@"message"] ?: @"") UTF8String]);
|
|
158
|
+
emitter->onAdLoadFailedEvent(result);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
163
|
+
{
|
|
164
|
+
const auto &oldViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(_props);
|
|
165
|
+
const auto &newViewProps = *std::static_pointer_cast<CloudXAdViewProps const>(props);
|
|
166
|
+
|
|
167
|
+
BOOL shouldAttach = NO;
|
|
168
|
+
|
|
169
|
+
if ( oldViewProps.adUnitId != newViewProps.adUnitId )
|
|
170
|
+
{
|
|
171
|
+
[self setAdUnitId: RCTNSStringFromString(newViewProps.adUnitId)];
|
|
172
|
+
shouldAttach = YES;
|
|
173
|
+
}
|
|
174
|
+
if ( oldViewProps.adFormat != newViewProps.adFormat )
|
|
175
|
+
{
|
|
176
|
+
[self setAdFormat: RCTNSStringFromString(newViewProps.adFormat)];
|
|
177
|
+
}
|
|
178
|
+
if ( oldViewProps.placement != newViewProps.placement )
|
|
179
|
+
{
|
|
180
|
+
[self setPlacement: RCTNSStringFromStringNilIfEmpty(newViewProps.placement)];
|
|
181
|
+
}
|
|
182
|
+
if ( oldViewProps.customData != newViewProps.customData )
|
|
183
|
+
{
|
|
184
|
+
[self setCustomData: RCTNSStringFromStringNilIfEmpty(newViewProps.customData)];
|
|
185
|
+
}
|
|
186
|
+
/*
|
|
187
|
+
* CloudXAdViewExtraParametersStruct contains folly::dynamic, so the
|
|
188
|
+
* generated props do not support a simple old/new equality guard like the
|
|
189
|
+
* scalar props above. Applying is idempotent, with removed keys cleared by
|
|
190
|
+
* applyExtraParametersIfReady.
|
|
191
|
+
*/
|
|
192
|
+
[self setExtraParametersFromEntryArray: [self entryArrayFromFabricExtraParameters: newViewProps.extraParameters]];
|
|
193
|
+
|
|
194
|
+
if ( shouldAttach )
|
|
195
|
+
{
|
|
196
|
+
[self attachAdViewIfNeeded];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
[super updateProps: props oldProps: oldProps];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
- (void)prepareForRecycle
|
|
203
|
+
{
|
|
204
|
+
[super prepareForRecycle];
|
|
205
|
+
|
|
206
|
+
static const auto defaultProps = std::make_shared<const CloudXAdViewProps>();
|
|
207
|
+
_props = defaultProps;
|
|
208
|
+
|
|
209
|
+
[self destroyAdIfNeeded];
|
|
210
|
+
self.adUnitId = nil;
|
|
211
|
+
self.adFormat = nil;
|
|
212
|
+
self.placement = nil;
|
|
213
|
+
self.customData = nil;
|
|
214
|
+
self.extraParameters = @{};
|
|
215
|
+
self.appliedExtraParameterKeys = [NSSet set];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
- (NSArray<NSDictionary<NSString *, id> *> *)entryArrayFromFabricExtraParameters:(const std::vector<CloudXAdViewExtraParametersStruct> &)entries
|
|
219
|
+
{
|
|
220
|
+
NSMutableArray<NSDictionary<NSString *, id> *> *result = [NSMutableArray arrayWithCapacity: entries.size()];
|
|
221
|
+
for ( const auto &entry : entries )
|
|
222
|
+
{
|
|
223
|
+
NSString *key = [NSString stringWithUTF8String: entry.key.c_str()] ?: @"";
|
|
224
|
+
id value = CLXIdFromFollyDynamic(entry.value) ?: [NSNull null];
|
|
225
|
+
[result addObject: @{@"key": key, @"value": value}];
|
|
226
|
+
}
|
|
227
|
+
return [result copy];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#else
|
|
231
|
+
|
|
232
|
+
- (instancetype)init
|
|
233
|
+
{
|
|
234
|
+
self = [super init];
|
|
235
|
+
if ( self )
|
|
236
|
+
{
|
|
237
|
+
[self commonInit];
|
|
238
|
+
}
|
|
239
|
+
return self;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
243
|
+
|
|
244
|
+
#pragma mark - Property setters (shared; Paper view manager sets these via KVC)
|
|
245
|
+
|
|
246
|
+
- (void)setAdUnitId:(NSString *)adUnitId
|
|
247
|
+
{
|
|
248
|
+
if ( self.adView )
|
|
249
|
+
{
|
|
250
|
+
// Ad unit ID is immutable once the ad view is created. Warn only on an
|
|
251
|
+
// actual change; unchanged re-sets on re-render stay quiet.
|
|
252
|
+
if ( ![adUnitId isEqualToString: _adUnitId] )
|
|
253
|
+
{
|
|
254
|
+
RCTLogWarn(@"CloudXAdView: adUnitId cannot change after the ad view is created; remount the component (e.g. via a React key).");
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
_adUnitId = adUnitId;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
- (void)setAdFormat:(NSString *)adFormat
|
|
262
|
+
{
|
|
263
|
+
if ( self.adView )
|
|
264
|
+
{
|
|
265
|
+
if ( ![adFormat isEqualToString: _adFormat] )
|
|
266
|
+
{
|
|
267
|
+
RCTLogWarn(@"CloudXAdView: adFormat cannot change after the ad view is created; remount the component (e.g. via a React key).");
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
_adFormat = adFormat;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
- (void)setPlacement:(NSString *)placement
|
|
275
|
+
{
|
|
276
|
+
_placement = placement;
|
|
277
|
+
self.adView.placement = placement;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
- (void)setCustomData:(NSString *)customData
|
|
281
|
+
{
|
|
282
|
+
_customData = customData;
|
|
283
|
+
self.adView.customData = customData;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
- (void)setExtraParametersFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)extraParameters
|
|
287
|
+
{
|
|
288
|
+
self.extraParameters = [CloudXExtraParameters dictionaryFromEntryArray: extraParameters];
|
|
289
|
+
[self applyExtraParametersIfReady];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#pragma mark - Paper attach hook
|
|
293
|
+
|
|
294
|
+
// Invoked after all JS props are set when mounting on the Old Architecture.
|
|
295
|
+
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
|
296
|
+
{
|
|
297
|
+
[self attachAdViewIfNeeded];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#pragma mark - Ad view lifecycle
|
|
301
|
+
|
|
302
|
+
- (void)attachAdViewIfNeeded
|
|
303
|
+
{
|
|
304
|
+
NSString *adUnitId = self.adUnitId;
|
|
305
|
+
NSString *adFormat = self.adFormat;
|
|
306
|
+
|
|
307
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
308
|
+
if ( self.adView ) return;
|
|
309
|
+
if ( adUnitId.length == 0 || adFormat.length == 0 ) return;
|
|
310
|
+
|
|
311
|
+
CLXBannerAdView *adView;
|
|
312
|
+
if ( [adFormat caseInsensitiveCompare: @"MREC"] == NSOrderedSame )
|
|
313
|
+
{
|
|
314
|
+
adView = [[CloudXCore shared] createMRECWithAdUnitId: adUnitId];
|
|
315
|
+
}
|
|
316
|
+
else
|
|
317
|
+
{
|
|
318
|
+
adView = [[CloudXCore shared] createBannerWithAdUnitId: adUnitId];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if ( !adView )
|
|
322
|
+
{
|
|
323
|
+
/*
|
|
324
|
+
* createBanner/createMRECWithAdUnitId: returned nil. The JS layer
|
|
325
|
+
* gates mounting on SDK initialization, so a nil here post-init is
|
|
326
|
+
* an invalid/expired ad unit — surface it as a load failure instead
|
|
327
|
+
* of leaving a permanently-dead, silent view (self.adView stays nil
|
|
328
|
+
* and props don't re-land, so there is no retry).
|
|
329
|
+
*/
|
|
330
|
+
if ( self.onAdLoadFailedEvent )
|
|
331
|
+
{
|
|
332
|
+
self.onAdLoadFailedEvent(@{@"adUnitId": adUnitId ?: @"",
|
|
333
|
+
@"code": @(CLXErrorCodeInvalidAdUnit),
|
|
334
|
+
@"message": @"Ad view creation returned nil (invalid ad unit or SDK not initialized)"});
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
adView.delegate = self;
|
|
340
|
+
adView.revenueDelegate = self;
|
|
341
|
+
adView.placement = self.placement;
|
|
342
|
+
adView.customData = self.customData;
|
|
343
|
+
adView.userInteractionEnabled = YES;
|
|
344
|
+
adView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
345
|
+
|
|
346
|
+
self.adView = adView;
|
|
347
|
+
[self applyExtraParametersIfReady];
|
|
348
|
+
[self addSubview: adView];
|
|
349
|
+
[NSLayoutConstraint activateConstraints: @[
|
|
350
|
+
[adView.topAnchor constraintEqualToAnchor: self.topAnchor],
|
|
351
|
+
[adView.bottomAnchor constraintEqualToAnchor: self.bottomAnchor],
|
|
352
|
+
[adView.leadingAnchor constraintEqualToAnchor: self.leadingAnchor],
|
|
353
|
+
[adView.trailingAnchor constraintEqualToAnchor: self.trailingAnchor],
|
|
354
|
+
]];
|
|
355
|
+
|
|
356
|
+
[adView load];
|
|
357
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
- (void)updateAutoRefreshForWindowVisibility
|
|
362
|
+
{
|
|
363
|
+
if ( !self.adView ) return;
|
|
364
|
+
if ( self.window )
|
|
365
|
+
{
|
|
366
|
+
[self.adView startAutoRefresh];
|
|
367
|
+
}
|
|
368
|
+
else
|
|
369
|
+
{
|
|
370
|
+
[self.adView stopAutoRefresh];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
- (void)didMoveToWindow
|
|
375
|
+
{
|
|
376
|
+
[super didMoveToWindow];
|
|
377
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
- (void)didMoveToSuperview
|
|
381
|
+
{
|
|
382
|
+
[super didMoveToSuperview];
|
|
383
|
+
|
|
384
|
+
if ( self.superview != nil )
|
|
385
|
+
{
|
|
386
|
+
[self updateAutoRefreshForWindowVisibility];
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Superview nil could be a real unmount or brief reparenting (react-native-screens).
|
|
391
|
+
// Defer one main-queue turn; destroy only if it is still detached. Strong ref so the
|
|
392
|
+
// ad is always torn down on a genuine unmount.
|
|
393
|
+
CloudXAdView *viewRef = self;
|
|
394
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
395
|
+
if ( viewRef.superview != nil )
|
|
396
|
+
{
|
|
397
|
+
[viewRef updateAutoRefreshForWindowVisibility];
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
[viewRef destroyAdIfNeeded];
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
- (void)dealloc
|
|
405
|
+
{
|
|
406
|
+
[self destroyAdIfNeeded];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
- (void)destroyAdIfNeeded
|
|
410
|
+
{
|
|
411
|
+
if ( !self.adView ) return;
|
|
412
|
+
|
|
413
|
+
[self.adView stopAutoRefresh];
|
|
414
|
+
self.adView.delegate = nil;
|
|
415
|
+
self.adView.revenueDelegate = nil;
|
|
416
|
+
[self.adView destroy];
|
|
417
|
+
[self.adView removeFromSuperview];
|
|
418
|
+
self.adView = nil;
|
|
419
|
+
self.appliedExtraParameterKeys = [NSSet set];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
- (void)applyExtraParametersIfReady
|
|
423
|
+
{
|
|
424
|
+
if ( !self.adView ) return;
|
|
425
|
+
|
|
426
|
+
NSDictionary<NSString *, id> *extraParameters = self.extraParameters ?: @{};
|
|
427
|
+
[CloudXExtraParameters applyExtraParameters: extraParameters toAdView: self.adView logBlock: nil];
|
|
428
|
+
|
|
429
|
+
NSMutableDictionary<NSString *, id> *removed = [NSMutableDictionary dictionary];
|
|
430
|
+
for ( NSString *key in self.appliedExtraParameterKeys )
|
|
431
|
+
{
|
|
432
|
+
if ( !extraParameters[key] )
|
|
433
|
+
{
|
|
434
|
+
removed[key] = [NSNull null];
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
[CloudXExtraParameters applyExtraParameters: removed toAdView: self.adView logBlock: nil];
|
|
438
|
+
self.appliedExtraParameterKeys = [NSSet setWithArray: extraParameters.allKeys];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#pragma mark - Event payloads
|
|
442
|
+
|
|
443
|
+
- (NSDictionary<NSString *, id> *)adInfoDictForAd:(CLXAd *)ad
|
|
444
|
+
{
|
|
445
|
+
NSString *adValuesJson = @"";
|
|
446
|
+
if ( ad.adValues )
|
|
447
|
+
{
|
|
448
|
+
NSData *data = [NSJSONSerialization dataWithJSONObject: ad.adValues options: 0 error: nil];
|
|
449
|
+
if ( data )
|
|
450
|
+
{
|
|
451
|
+
adValuesJson = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] ?: @"";
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return @{@"adUnitId": ad.adUnitId ?: @"",
|
|
456
|
+
@"adFormat": self.adFormat ?: @"",
|
|
457
|
+
@"networkName": ad.networkName ?: @"",
|
|
458
|
+
@"networkPlacement": ad.networkPlacement ?: @"",
|
|
459
|
+
@"placement": ad.placement ?: @"",
|
|
460
|
+
@"revenue": ad.revenue ?: @(0),
|
|
461
|
+
@"adValuesJson": adValuesJson};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
- (NSDictionary<NSString *, id> *)loadFailedDictForAdUnit:(NSString *)adUnitId error:(CLXError *)error
|
|
465
|
+
{
|
|
466
|
+
return @{@"adUnitId": adUnitId ?: (self.adUnitId ?: @""),
|
|
467
|
+
@"code": error ? @(error.code) : @(CLXErrorCodeInternalError),
|
|
468
|
+
@"message": error.localizedDescription ?: @""};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
#pragma mark - CLXBannerDelegate / CLXAdRevenueDelegate
|
|
472
|
+
|
|
473
|
+
- (void)didLoadAd:(CLXAd *)ad
|
|
474
|
+
{
|
|
475
|
+
if ( self.onAdLoadedEvent ) self.onAdLoadedEvent([self adInfoDictForAd: ad]);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
- (void)didFailToLoadAd:(NSString *)adUnitId error:(CLXError *)error
|
|
479
|
+
{
|
|
480
|
+
if ( self.onAdLoadFailedEvent ) self.onAdLoadFailedEvent([self loadFailedDictForAdUnit: adUnitId error: error]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
- (void)didClickAd:(CLXAd *)ad
|
|
484
|
+
{
|
|
485
|
+
if ( self.onAdClickedEvent ) self.onAdClickedEvent([self adInfoDictForAd: ad]);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
- (void)didPayRevenueForAd:(CLXAd *)ad
|
|
489
|
+
{
|
|
490
|
+
if ( self.onAdRevenuePaidEvent ) self.onAdRevenuePaidEvent([self adInfoDictForAd: ad]);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
@end
|
|
494
|
+
|
|
495
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
496
|
+
Class<RCTComponentViewProtocol> CloudXAdViewCls(void)
|
|
497
|
+
{
|
|
498
|
+
return [CloudXAdView class];
|
|
499
|
+
}
|
|
500
|
+
#endif
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CloudXAdViewManager.mm
|
|
3
|
+
// cloudx-react-native
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
#import "CloudXAdViewManager.h"
|
|
7
|
+
#import "CloudXAdView.h"
|
|
8
|
+
|
|
9
|
+
@implementation CloudXAdViewManager
|
|
10
|
+
|
|
11
|
+
RCT_EXPORT_MODULE(CloudXAdView)
|
|
12
|
+
|
|
13
|
+
RCT_EXPORT_VIEW_PROPERTY(adUnitId, NSString)
|
|
14
|
+
RCT_EXPORT_VIEW_PROPERTY(adFormat, NSString)
|
|
15
|
+
RCT_EXPORT_VIEW_PROPERTY(placement, NSString)
|
|
16
|
+
RCT_EXPORT_VIEW_PROPERTY(customData, NSString)
|
|
17
|
+
RCT_CUSTOM_VIEW_PROPERTY(extraParameters, NSArray, CloudXAdView)
|
|
18
|
+
{
|
|
19
|
+
NSArray<NSDictionary<NSString *, id> *> *entries = [json isKindOfClass: [NSArray class]] ? json : nil;
|
|
20
|
+
[view setExtraParametersFromEntryArray: entries];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdLoadedEvent, RCTDirectEventBlock)
|
|
24
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdLoadFailedEvent, RCTDirectEventBlock)
|
|
25
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdClickedEvent, RCTDirectEventBlock)
|
|
26
|
+
RCT_EXPORT_VIEW_PROPERTY(onAdRevenuePaidEvent, RCTDirectEventBlock)
|
|
27
|
+
|
|
28
|
+
+ (BOOL)requiresMainQueueSetup
|
|
29
|
+
{
|
|
30
|
+
return YES;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (UIView *)view
|
|
34
|
+
{
|
|
35
|
+
return [[CloudXAdView alloc] init];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CloudXExtraParameters.h
|
|
3
|
+
* cloudx-react-native
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#import <Foundation/Foundation.h>
|
|
7
|
+
#import <CloudXCore/CloudXCore.h>
|
|
8
|
+
|
|
9
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
10
|
+
|
|
11
|
+
typedef void (^CloudXExtraParametersLogBlock)(NSString *message);
|
|
12
|
+
|
|
13
|
+
@interface CloudXExtraParameters : NSObject
|
|
14
|
+
|
|
15
|
+
+ (NSDictionary<NSString *, id> *)dictionaryFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)entries;
|
|
16
|
+
+ (void)mergeExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
17
|
+
intoPendingDictionary:(NSMutableDictionary<NSString *, id> *)pending;
|
|
18
|
+
+ (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
19
|
+
toAdView:(CLXBannerAdView *)adView
|
|
20
|
+
logBlock:(nullable CloudXExtraParametersLogBlock)logBlock;
|
|
21
|
+
+ (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
22
|
+
toFullscreenAd:(id<CLXFullscreenAd>)ad
|
|
23
|
+
logBlock:(nullable CloudXExtraParametersLogBlock)logBlock;
|
|
24
|
+
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CloudXExtraParameters.mm
|
|
3
|
+
* cloudx-react-native
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#import "CloudXExtraParameters.h"
|
|
7
|
+
|
|
8
|
+
@implementation CloudXExtraParameters
|
|
9
|
+
|
|
10
|
+
+ (NSDictionary<NSString *, id> *)dictionaryFromEntryArray:(nullable NSArray<NSDictionary<NSString *, id> *> *)entries
|
|
11
|
+
{
|
|
12
|
+
if ( !entries || ![(id)entries isKindOfClass: [NSArray class]] )
|
|
13
|
+
{
|
|
14
|
+
return @{};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
NSMutableDictionary<NSString *, id> *extraParameters = [NSMutableDictionary dictionary];
|
|
18
|
+
for ( id entry in entries )
|
|
19
|
+
{
|
|
20
|
+
if ( ![entry isKindOfClass: [NSDictionary class]] ) continue;
|
|
21
|
+
|
|
22
|
+
NSDictionary<NSString *, id> *entryDictionary = (NSDictionary<NSString *, id> *)entry;
|
|
23
|
+
id keyValue = entryDictionary[@"key"];
|
|
24
|
+
if ( ![keyValue isKindOfClass: [NSString class]] ) continue;
|
|
25
|
+
|
|
26
|
+
NSString *key = (NSString *)keyValue;
|
|
27
|
+
if ( key.length == 0 ) continue;
|
|
28
|
+
|
|
29
|
+
extraParameters[key] = entryDictionary[@"value"] ?: [NSNull null];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return [extraParameters copy];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
+ (void)mergeExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
36
|
+
intoPendingDictionary:(NSMutableDictionary<NSString *, id> *)pending
|
|
37
|
+
{
|
|
38
|
+
[extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
|
|
39
|
+
if ( !key || key.length == 0 ) return;
|
|
40
|
+
if ( !value || [value isKindOfClass: [NSNull class]] )
|
|
41
|
+
{
|
|
42
|
+
[pending removeObjectForKey: key];
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
{
|
|
46
|
+
pending[key] = value;
|
|
47
|
+
}
|
|
48
|
+
}];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
+ (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
52
|
+
toAdView:(CLXBannerAdView *)adView
|
|
53
|
+
logBlock:(nullable CloudXExtraParametersLogBlock)logBlock
|
|
54
|
+
{
|
|
55
|
+
SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
|
|
56
|
+
id target = [adView respondsToSelector: selector] ? adView : adView.ad;
|
|
57
|
+
|
|
58
|
+
[extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
|
|
59
|
+
if ( !key || key.length == 0 ) return;
|
|
60
|
+
id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
|
|
61
|
+
[self applyExtraParameterValue: normalizedValue forKey: key toTarget: target logBlock: logBlock];
|
|
62
|
+
}];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
+ (void)applyExtraParameters:(NSDictionary<NSString *, id> *)extraParameters
|
|
66
|
+
toFullscreenAd:(id<CLXFullscreenAd>)ad
|
|
67
|
+
logBlock:(nullable CloudXExtraParametersLogBlock)logBlock
|
|
68
|
+
{
|
|
69
|
+
[extraParameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) {
|
|
70
|
+
if ( !key || key.length == 0 ) return;
|
|
71
|
+
id normalizedValue = [value isKindOfClass: [NSNull class]] ? nil : value;
|
|
72
|
+
[self applyExtraParameterValue: normalizedValue forKey: key toTarget: ad logBlock: logBlock];
|
|
73
|
+
}];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
+ (void)applyExtraParameterValue:(id)value
|
|
77
|
+
forKey:(NSString *)key
|
|
78
|
+
toTarget:(id)target
|
|
79
|
+
logBlock:(nullable CloudXExtraParametersLogBlock)logBlock
|
|
80
|
+
{
|
|
81
|
+
if ( !target || !key || key.length == 0 ) return;
|
|
82
|
+
|
|
83
|
+
SEL selector = NSSelectorFromString(@"setExtraParameter:value:");
|
|
84
|
+
if ( ![target respondsToSelector: selector] )
|
|
85
|
+
{
|
|
86
|
+
selector = NSSelectorFromString(@"setExtraParameterForKey:value:");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if ( ![target respondsToSelector: selector] )
|
|
90
|
+
{
|
|
91
|
+
if ( logBlock )
|
|
92
|
+
{
|
|
93
|
+
logBlock(
|
|
94
|
+
[NSString stringWithFormat: @"Skipping extra parameter \"%@\" because %@ does not respond to setExtraParameter:value: or setExtraParameterForKey:value:",
|
|
95
|
+
key,
|
|
96
|
+
NSStringFromClass([target class])]
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
using SetExtraParameterMethod = void (*)(id, SEL, NSString *, id);
|
|
103
|
+
SetExtraParameterMethod method = (SetExtraParameterMethod)[target methodForSelector: selector];
|
|
104
|
+
method(target, selector, key, value);
|
|
105
|
+
|
|
106
|
+
if ( logBlock )
|
|
107
|
+
{
|
|
108
|
+
logBlock(
|
|
109
|
+
[NSString stringWithFormat: @"Applied extra parameter \"%@\" with value \"%@\" to %@",
|
|
110
|
+
key,
|
|
111
|
+
value ?: @"(cleared)",
|
|
112
|
+
NSStringFromClass([target class])]
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@end
|